Mike Schwörer
3a8baaa6d9
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 1m45s
108 lines
3.5 KiB
Go
108 lines
3.5 KiB
Go
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)
|
|
unmarshalHooks []func(d TData) TData // called for every object after unmarshalling
|
|
}
|
|
|
|
func (c *Coll[TData]) Collection() *mongo.Collection {
|
|
return c.coll
|
|
}
|
|
|
|
func (c *Coll[TData]) Name() string {
|
|
return c.coll.Name()
|
|
}
|
|
|
|
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]) 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]) WithUnmarshalHook(fn func(d TData) TData) *Coll[TData] {
|
|
c.unmarshalHooks = append(c.unmarshalHooks, fn)
|
|
|
|
return c
|
|
}
|
|
|
|
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
|
|
}
|