package repositoryimp import ( "context" "fmt" ri "git.sendico.io/tech/sxchnge/shared/database/repository/index" "git.sendico.io/tech/sxchnge/shared/errors" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) func (r *MongoRepository) CreateIndex(def *ri.Definition) error { ctx := context.Background() collection, ctx, release, err := r.acquire(ctx) if err != nil { return err } defer release() if collection == nil { return merrors.NoData("data collection is not set") } if len(def.Keys) == 0 { return merrors.InvalidArgument("Index definition has no keys", "index.keys") } // ----- build BSON keys -------------------------------------------------- keys := bson.D{} for _, k := range def.Keys { var value any switch { case k.Type != "": value = k.Type // text, 2dsphere, … case k.Sort == ri.Desc: value = int8(-1) default: value = int8(1) // default to Asc } keys = append(keys, bson.E{Key: k.Field, Value: value}) } opts := options.Index(). SetUnique(def.Unique) if def.TTL != nil { opts.SetExpireAfterSeconds(*def.TTL) } if def.Name != "" { opts.SetName(def.Name) } if def.PartialFilter != nil { opts.SetPartialFilterExpression(def.PartialFilter.BuildQuery()) } if def.Sparse { opts.SetSparse(def.Sparse) } _, err = collection.Indexes().CreateOne( ctx, mongo.IndexModel{Keys: keys, Options: opts}, ) return err } func (r *MongoRepository) DropIndex(ctx context.Context, name string) error { collection, ctx, release, err := r.acquire(ctx) if err != nil { return err } defer release() if collection == nil { return merrors.NoData("data collection is not set") } if name == "" { return merrors.InvalidArgument("index name is required", "index.name") } return collection.Indexes().DropOne(ctx, name) } func (r *MongoRepository) ListIndexDefinitions(ctx context.Context) ([]*ri.Definition, error) { collection, ctx, release, err := r.acquire(ctx) if err != nil { return nil, err } defer release() if collection == nil { return nil, merrors.NoData("data collection is not set") } cursor, err := collection.Indexes().List(ctx) if err != nil { return nil, err } defer func() { _ = cursor.Close(ctx) }() defs := make([]*ri.Definition, 0) for cursor.Next(ctx) { var doc mongoIndexDocument if err := cursor.Decode(&doc); err != nil { return nil, err } defs = append(defs, indexDefinitionFromDocument(doc)) } if err := cursor.Err(); err != nil { return nil, err } return defs, nil } type mongoIndexDocument struct { Name string `bson:"name"` Key bson.D `bson:"key"` Unique bool `bson:"unique"` Sparse bool `bson:"sparse"` ExpireAfterSeconds *int32 `bson:"expireAfterSeconds,omitempty"` } func indexDefinitionFromDocument(doc mongoIndexDocument) *ri.Definition { keys := make([]ri.Key, 0, len(doc.Key)) for _, key := range doc.Key { keys = append(keys, indexKeyFromBSON(key)) } return &ri.Definition{ Keys: keys, Unique: doc.Unique, Sparse: doc.Sparse, TTL: doc.ExpireAfterSeconds, Name: doc.Name, } } func indexKeyFromBSON(key bson.E) ri.Key { out := ri.Key{Field: key.Key} switch typed := key.Value.(type) { case string: out.Type = ri.IndexType(typed) case int: out.Sort = indexSort(typed) case int8: out.Sort = indexSort(typed) case int16: out.Sort = indexSort(typed) case int32: out.Sort = indexSort(typed) case int64: out.Sort = indexSort(typed) case float64: out.Sort = indexSort(typed) default: out.Type = ri.IndexType(fmt.Sprint(typed)) } return out } func indexSort[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~float64](value T) ri.Sort { if value < 0 { return ri.Desc } return ri.Asc }