package mongo import ( "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo/options" ) // Index represents a MongoDB index type Index struct { Name string `json:"name"` Keys bson.D `json:"keys"` Options *options.IndexOptionsBuilder `json:"options"` } // NewIndex creates a new index with default options func NewIndex(name string, keys bson.D) *Index { return &Index{ Name: name, Keys: keys, Options: options.Index().SetName(name), } } // WithUnique sets the unique option for the index func (i *Index) WithUnique(unique bool) *Index { i.Options.SetUnique(unique) return i } // WithSparse sets the sparse option for the index func (i *Index) WithSparse(sparse bool) *Index { i.Options.SetSparse(sparse) return i } // WithExpireAfterSeconds sets the TTL for the index func (i *Index) WithExpireAfterSeconds(seconds int32) *Index { i.Options.SetExpireAfterSeconds(seconds) return i } // NonEmptyStringPartialFilter returns a partial-index filter for non-empty string field values. // MongoDB partial indexes do not support $ne; use $gt "" instead. func NonEmptyStringPartialFilter(field string) bson.M { return bson.M{ field: bson.M{ "$type": "string", "$gt": "", }, } } // WithPartialFilterExpression sets the partial filter expression for the index func (i *Index) WithPartialFilterExpression(filter bson.M) *Index { i.Options.SetPartialFilterExpression(filter) return i } // WithCollation sets the collation for the index func (i *Index) WithCollation(collation *options.Collation) *Index { i.Options.SetCollation(collation) return i } // Common index builders // CreateUniqueIndex creates a unique index func CreateUniqueIndex(name string, keys bson.D) *Index { return NewIndex(name, keys).WithUnique(true) } // CreateTTLIndex creates a TTL index func CreateTTLIndex(name string, field string, expireAfterSeconds int32) *Index { return NewIndex(name, bson.D{{Key: field, Value: 1}}).WithExpireAfterSeconds(expireAfterSeconds) } // CreateTextIndex creates a text index func CreateTextIndex(name string, fields ...string) *Index { keys := bson.D{} for _, field := range fields { keys = append(keys, bson.E{Key: field, Value: "text"}) } return NewIndex(name, keys) } // CreateCompoundIndex creates a compound index func CreateCompoundIndex(name string, fields map[string]int) *Index { keys := bson.D{} for field, direction := range fields { keys = append(keys, bson.E{Key: field, Value: direction}) } return NewIndex(name, keys) } // CreateGeospatialIndex creates a 2dsphere geospatial index func CreateGeospatialIndex(name string, field string) *Index { return NewIndex(name, bson.D{{Key: field, Value: "2dsphere"}}) } // CreateHashedIndex creates a hashed index func CreateHashedIndex(name string, field string) *Index { return NewIndex(name, bson.D{{Key: field, Value: "hashed"}}) } // Common index patterns // DefaultIndexes returns common default indexes for most collections func DefaultIndexes() []Index { return []Index{ *CreateUniqueIndex("_id_", bson.D{{Key: "_id", Value: 1}}), *NewIndex("created_at_idx", bson.D{{Key: "created_at", Value: -1}}), *NewIndex("updated_at_idx", bson.D{{Key: "updated_at", Value: -1}}), } } // UserIndexes returns common indexes for user collections func UserIndexes() []Index { return []Index{ *CreateUniqueIndex("_id_", bson.D{{Key: "_id", Value: 1}}), *CreateUniqueIndex("email_idx", bson.D{{Key: "email", Value: 1}}), *NewIndex("created_at_idx", bson.D{{Key: "created_at", Value: -1}}), *NewIndex("updated_at_idx", bson.D{{Key: "updated_at", Value: -1}}), *NewIndex("is_active_idx", bson.D{{Key: "is_active", Value: 1}}), } } // TenderIndexes returns common indexes for tender collections func TenderIndexes() []Index { return []Index{ *CreateUniqueIndex("_id_", bson.D{{Key: "_id", Value: 1}}), *NewIndex("created_at_idx", bson.D{{Key: "created_at", Value: -1}}), *NewIndex("updated_at_idx", bson.D{{Key: "updated_at", Value: -1}}), *NewIndex("status_idx", bson.D{{Key: "status", Value: 1}}), *NewIndex("deadline_idx", bson.D{{Key: "deadline", Value: 1}}), *NewIndex("category_idx", bson.D{{Key: "category", Value: 1}}), *NewIndex("location_idx", bson.D{{Key: "location", Value: 1}}), } } // CompanyIndexes returns common indexes for company collections func CompanyIndexes() []Index { return []Index{ *CreateUniqueIndex("_id_", bson.D{{Key: "_id", Value: 1}}), *CreateUniqueIndex("name_idx", bson.D{{Key: "name", Value: 1}}), *NewIndex("created_at_idx", bson.D{{Key: "created_at", Value: -1}}), *NewIndex("updated_at_idx", bson.D{{Key: "updated_at", Value: -1}}), *NewIndex("is_active_idx", bson.D{{Key: "is_active", Value: 1}}), } } // QueryBuilder provides a fluent interface for building MongoDB queries type QueryBuilder struct { filter bson.M } // NewQueryBuilder creates a new query builder func NewQueryBuilder() *QueryBuilder { return &QueryBuilder{ filter: bson.M{}, } } // Where adds a simple equality condition func (qb *QueryBuilder) Where(field string, value interface{}) *QueryBuilder { qb.filter[field] = value return qb } // WhereIn adds an $in condition func (qb *QueryBuilder) WhereIn(field string, values []interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$in": values} return qb } // WhereNotIn adds a $nin condition func (qb *QueryBuilder) WhereNotIn(field string, values []interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$nin": values} return qb } // WhereGreaterThan adds a $gt condition func (qb *QueryBuilder) WhereGreaterThan(field string, value interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$gt": value} return qb } // WhereGreaterThanOrEqual adds a $gte condition func (qb *QueryBuilder) WhereGreaterThanOrEqual(field string, value interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$gte": value} return qb } // WhereLessThan adds a $lt condition func (qb *QueryBuilder) WhereLessThan(field string, value interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$lt": value} return qb } // WhereLessThanOrEqual adds a $lte condition func (qb *QueryBuilder) WhereLessThanOrEqual(field string, value interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$lte": value} return qb } // WhereNotEqual adds a $ne condition func (qb *QueryBuilder) WhereNotEqual(field string, value interface{}) *QueryBuilder { qb.filter[field] = bson.M{"$ne": value} return qb } // WhereExists adds an $exists condition func (qb *QueryBuilder) WhereExists(field string, exists bool) *QueryBuilder { qb.filter[field] = bson.M{"$exists": exists} return qb } // WhereRegex adds a $regex condition func (qb *QueryBuilder) WhereRegex(field string, pattern string, options string) *QueryBuilder { qb.filter[field] = bson.M{"$regex": pattern, "$options": options} return qb } // WhereText adds a $text condition func (qb *QueryBuilder) WhereText(search string) *QueryBuilder { qb.filter["$text"] = bson.M{"$search": search} return qb } // WhereAnd adds an $and condition func (qb *QueryBuilder) WhereAnd(conditions ...bson.M) *QueryBuilder { qb.filter["$and"] = conditions return qb } // WhereOr adds an $or condition func (qb *QueryBuilder) WhereOr(conditions ...bson.M) *QueryBuilder { qb.filter["$or"] = conditions return qb } // WhereNor adds a $nor condition func (qb *QueryBuilder) WhereNor(conditions ...bson.M) *QueryBuilder { qb.filter["$nor"] = conditions return qb } // Build returns the final filter func (qb *QueryBuilder) Build() bson.M { return qb.filter } // PaginationBuilder provides a fluent interface for building pagination options type PaginationBuilder struct { pagination Pagination } // NewPaginationBuilder creates a new pagination builder func NewPaginationBuilder() *PaginationBuilder { return &PaginationBuilder{ pagination: Pagination{ Limit: 10, SortField: "_id", SortOrder: -1, }, } } // Limit sets the limit func (pb *PaginationBuilder) Limit(limit int) *PaginationBuilder { pb.pagination.Limit = limit return pb } // Skip sets the skip value for offset-based pagination func (pb *PaginationBuilder) Skip(skip int) *PaginationBuilder { pb.pagination.Skip = skip return pb } // Cursor sets the cursor for cursor-based pagination func (pb *PaginationBuilder) Cursor(cursor string) *PaginationBuilder { pb.pagination.Cursor = cursor return pb } // SortBy sets the sort field and order func (pb *PaginationBuilder) SortBy(field string, order string) *PaginationBuilder { pb.pagination.SortField = field if order == "asc" { pb.pagination.SortOrder = 1 } else { pb.pagination.SortOrder = -1 } return pb } // SortAsc sorts in ascending order func (pb *PaginationBuilder) SortAsc(field string) *PaginationBuilder { return pb.SortBy(field, "asc") } // SortDesc sorts in descending order func (pb *PaginationBuilder) SortDesc(field string) *PaginationBuilder { return pb.SortBy(field, "desc") } // Projection sets optional MongoDB field projection for Find (e.g. exclude large fields). func (pb *PaginationBuilder) Projection(projection bson.M) *PaginationBuilder { pb.pagination.Projection = projection return pb } // SkipCount disables CountDocuments for this query. func (pb *PaginationBuilder) SkipCount(skip bool) *PaginationBuilder { pb.pagination.SkipCount = skip return pb } // Build returns the final pagination options func (pb *PaginationBuilder) Build() Pagination { return pb.pagination }