groupware: refactoring for pagination and support for multiple query suppliers

* refactor APIs in JMAP and Groupware in order to implement pagination
   across multiple accountIds and multiple suppliers (currently
   implemented using a mock supplier for contacts)

 * requires go 1.26 due to use of self-reflecting generics type
   constraints

 * still missing: query criteria and sorting parameters

 * still missing: multi-accountId support for emails

 * errors are now all just 'error' in the APIs, instead of the
   specialized implementations, and are interpreted dynamically where
   necessary in order to transform them into HTTP responses

 * remove position, anchor, anchorOffset as individual query parameters
   as we now only support a 'next=...' token for subsequent pages
   (except in emails for now), and use jmap.QueryParams instead; those
   tokens have a header character for the format, followed by a JSON
   encoded QueryParams map, all wrapped into base62 to make it clearer
   that it is meant to be an opaque token, and not a parameter clients
   should tinker with or construct themselves

 * introduce QueryParamsSupplier as an interface to provide QueryParams
   for various scenarios (single supplier, multiple supplier, ...) per
   accountId

 * implement multi-supplier template methods slist and squery
This commit is contained in:
Pascal Bleser
2026-06-03 10:42:47 +02:00
parent 6660bd7749
commit b26c6cadce
51 changed files with 2812 additions and 681 deletions

View File

@@ -2,6 +2,7 @@
package structs
import (
"fmt"
"iter"
"maps"
"slices"
@@ -309,3 +310,52 @@ func FilterSeq[T any](it iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
}
}
}
func FilterKeys[K comparable, V any](m map[K]V, predicate func(K, V) bool) []K {
if m == nil {
return []K{}
}
r := []K{}
for k, v := range m {
if predicate(k, v) {
r = append(r, k)
}
}
return r
}
func FilterValues[K comparable, V any](m map[K]V, predicate func(K, V) bool) []V {
if m == nil {
return []V{}
}
r := []V{}
for k, v := range m {
if predicate(k, v) {
r = append(r, v)
}
}
return r
}
func MeshMap[A any, B any, K comparable, V any](keys []A, values []B, mapper func(A, B) (K, V, bool)) (map[K]V, error) {
m := map[K]V{}
if len(keys) != len(values) {
return nil, fmt.Errorf("different length for slices")
}
for i := range keys {
if k, v, b := mapper(keys[i], values[i]); b {
m[k] = v
}
}
return m, nil
}
func First[T any](values []T, predicate func(T) bool) (T, bool) {
for _, value := range values {
if predicate(value) {
return value, true
}
}
var zero T
return zero, false
}