package wmo import ( "context" "go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/mongo" ct "gogs.mikescher.com/BlackForestBytes/goext/cursortoken" "gogs.mikescher.com/BlackForestBytes/goext/exerr" "gogs.mikescher.com/BlackForestBytes/goext/langext" "reflect" ) type EntityID interface { MarshalBSONValue() (bsontype.Type, []byte, error) String() string } type Decodable interface { Decode(v any) error } type Cursorable interface { Decode(v any) error Err() error Close(ctx context.Context) error All(ctx context.Context, results any) error RemainingBatchLength() int Next(ctx context.Context) bool } type fullTypeRef struct { IsPointer bool Kind reflect.Kind RealType reflect.Type Type reflect.Type UnderlyingType reflect.Type Name string Index []int } type Coll[TData any] struct { coll *mongo.Collection // internal mongo collection, access via Collection() dataTypeMap map[string]fullTypeRef // list of TData fields (only if TData is not an interface) implDataTypeMap map[reflect.Type]map[string]fullTypeRef // dynamic list of fields of TData implementations (only if TData is an interface) customDecoder *func(ctx context.Context, dec Decodable) (TData, error) // custom decoding function (useful if TData is an interface) isInterfaceDataType bool // true if TData is an interface (not a struct) } func (c *Coll[TData]) Collection() *mongo.Collection { return c.coll } func (c *Coll[TData]) Name() string { return c.coll.Name() } func (c *Coll[TData]) WithDecodeFunc(cdf func(ctx context.Context, dec Decodable) (TData, error), example TData) *Coll[TData] { c.EnsureInitializedReflection(example) c.customDecoder = langext.Ptr(cdf) return c } func (c *Coll[TData]) Indexes() mongo.IndexView { return c.coll.Indexes() } func (c *Coll[TData]) Drop(ctx context.Context) error { err := c.coll.Drop(ctx) if err != nil { return exerr.Wrap(err, "failed to drop collection").Str("collection", c.Name()).Build() } return nil } func (c *Coll[TData]) createToken(fieldPrimary string, dirPrimary ct.SortDirection, fieldSecondary *string, dirSecondary *ct.SortDirection, lastEntity TData, pageSize *int) (ct.CursorToken, error) { valuePrimary, err := c.getFieldValueAsTokenString(lastEntity, fieldPrimary) if err != nil { return ct.CursorToken{}, exerr.Wrap(err, "failed to get (primary) field-value as token-string").Type("lastEntity", lastEntity).Str("fieldPrimary", fieldPrimary).Build() } valueSeconary := "" if fieldSecondary != nil && dirSecondary != nil { valueSeconary, err = c.getFieldValueAsTokenString(lastEntity, *fieldSecondary) if err != nil { return ct.CursorToken{}, exerr.Wrap(err, "failed to get (secondary) field-value as token-string").Type("lastEntity", lastEntity).StrPtr("fieldSecondary", fieldSecondary).Build() } } return ct.CursorToken{ Mode: ct.CTMNormal, ValuePrimary: valuePrimary, ValueSecondary: valueSeconary, Direction: dirPrimary, PageSize: langext.Coalesce(pageSize, 0), Extra: ct.Extra{}, }, nil }