Files
tm_back/pkg/mongo/utils.go
T
2026-05-14 14:18:34 +03:30

306 lines
8.8 KiB
Go

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(),
}
}
// 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
}
// 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
}
// Build returns the final pagination options
func (pb *PaginationBuilder) Build() Pagination {
return pb.pagination
}