Files
satusehat-service/pkg/utils/query/mongo_execution.go
T
2026-04-14 01:23:34 +00:00

212 lines
7.0 KiB
Go

package query
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// ExecuteFind executes a MongoDB find query
func (mqb *MongoQueryBuilderImpl) ExecuteFind(ctx context.Context, collection *mongo.Collection, query DynamicQuery, dest interface{}) error {
// Security check for collection name
if mqb.enableSecurityChecks && len(mqb.allowedCollections) > 0 && !mqb.allowedCollections[collection.Name()] {
return fmt.Errorf("disallowed collection: %s", collection.Name())
}
filter, findOptions, err := mqb.BuildFindQuery(query)
if err != nil {
return err
}
// Set timeout if not already in context
if _, hasDeadline := ctx.Deadline(); !hasDeadline && mqb.queryTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(mqb.queryTimeout)*time.Second)
defer cancel()
}
start := time.Now()
cursor, err := collection.Find(ctx, filter.(bson.M), findOptions.(*options.FindOptions))
if err != nil {
return err
}
defer cursor.Close(ctx)
err = cursor.All(ctx, dest)
if mqb.enableQueryLogging {
fmt.Printf("[DEBUG] MongoDB Find executed in %v\n", time.Since(start))
}
return err
}
// ExecuteAggregate executes a MongoDB aggregation pipeline
func (mqb *MongoQueryBuilderImpl) ExecuteAggregate(ctx context.Context, collection *mongo.Collection, query DynamicQuery, dest interface{}) error {
// Security check for collection name
if mqb.enableSecurityChecks && len(mqb.allowedCollections) > 0 && !mqb.allowedCollections[collection.Name()] {
return fmt.Errorf("disallowed collection: %s", collection.Name())
}
pipeline, err := mqb.BuildAggregateQuery(query)
if err != nil {
return err
}
// Set timeout if not already in context
if _, hasDeadline := ctx.Deadline(); !hasDeadline && mqb.queryTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(mqb.queryTimeout)*time.Second)
defer cancel()
}
start := time.Now()
cursor, err := collection.Aggregate(ctx, pipeline.([]bson.D))
if err != nil {
return err
}
defer cursor.Close(ctx)
err = cursor.All(ctx, dest)
if mqb.enableQueryLogging {
fmt.Printf("[DEBUG] MongoDB Aggregate executed in %v\n", time.Since(start))
}
return err
}
// ExecuteCount executes a MongoDB count query
func (mqb *MongoQueryBuilderImpl) ExecuteCount(ctx context.Context, collection *mongo.Collection, query DynamicQuery) (int64, error) {
// Security check for collection name
if mqb.enableSecurityChecks && len(mqb.allowedCollections) > 0 && !mqb.allowedCollections[collection.Name()] {
return 0, fmt.Errorf("disallowed collection: %s", collection.Name())
}
filter, _, err := mqb.BuildFindQuery(query)
if err != nil {
return 0, err
}
// Set timeout if not already in context
if _, hasDeadline := ctx.Deadline(); !hasDeadline && mqb.queryTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(mqb.queryTimeout)*time.Second)
defer cancel()
}
start := time.Now()
count, err := collection.CountDocuments(ctx, filter.(bson.M))
if mqb.enableQueryLogging {
fmt.Printf("[DEBUG] MongoDB Count executed in %v\n", time.Since(start))
}
return count, err
}
// ExecuteInsert executes a MongoDB insert operation
func (mqb *MongoQueryBuilderImpl) ExecuteInsert(ctx context.Context, collection *mongo.Collection, data InsertData) (*mongo.InsertOneResult, error) {
// Security check for collection name
if mqb.enableSecurityChecks && len(mqb.allowedCollections) > 0 && !mqb.allowedCollections[collection.Name()] {
return nil, fmt.Errorf("disallowed collection: %s", collection.Name())
}
document := bson.M{}
for i, col := range data.Columns {
if mqb.allowedFields != nil && !mqb.allowedFields[col] {
return nil, fmt.Errorf("disallowed field: %s", col)
}
document[col] = data.Values[i]
}
// Handle JSON values
for col, val := range data.JsonValues {
if mqb.allowedFields != nil && !mqb.allowedFields[col] {
return nil, fmt.Errorf("disallowed field: %s", col)
}
document[col] = val
}
// Set timeout if not already in context
if _, hasDeadline := ctx.Deadline(); !hasDeadline && mqb.queryTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(mqb.queryTimeout)*time.Second)
defer cancel()
}
start := time.Now()
result, err := collection.InsertOne(ctx, document)
if mqb.enableQueryLogging {
fmt.Printf("[DEBUG] MongoDB Insert executed in %v\n", time.Since(start))
}
return result, err
}
// ExecuteUpdate executes a MongoDB update operation
func (mqb *MongoQueryBuilderImpl) ExecuteUpdate(ctx context.Context, collection *mongo.Collection, updateData UpdateData, filters []FilterGroup) (*mongo.UpdateResult, error) {
// Security check for collection name
if mqb.enableSecurityChecks && len(mqb.allowedCollections) > 0 && !mqb.allowedCollections[collection.Name()] {
return nil, fmt.Errorf("disallowed collection: %s", collection.Name())
}
filter, err := mqb.buildFilter(filters)
if err != nil {
return nil, err
}
update := bson.M{"$set": bson.M{}}
for i, col := range updateData.Columns {
if mqb.allowedFields != nil && !mqb.allowedFields[col] {
return nil, fmt.Errorf("disallowed field: %s", col)
}
update["$set"].(bson.M)[col] = updateData.Values[i]
}
// Handle JSON updates
for col, jsonUpdate := range updateData.JsonUpdates {
if mqb.allowedFields != nil && !mqb.allowedFields[col] {
return nil, fmt.Errorf("disallowed field: %s", col)
}
// Use dot notation for nested JSON updates
update["$set"].(bson.M)[col+"."+jsonUpdate.Path] = jsonUpdate.Value
}
// Set timeout if not already in context
if _, hasDeadline := ctx.Deadline(); !hasDeadline && mqb.queryTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(mqb.queryTimeout)*time.Second)
defer cancel()
}
start := time.Now()
result, err := collection.UpdateMany(ctx, filter, update)
if mqb.enableQueryLogging {
fmt.Printf("[DEBUG] MongoDB Update executed in %v\n", time.Since(start))
}
return result, err
}
// ExecuteDelete executes a MongoDB delete operation
func (mqb *MongoQueryBuilderImpl) ExecuteDelete(ctx context.Context, collection *mongo.Collection, filters []FilterGroup) (*mongo.DeleteResult, error) {
// Security check for collection name
if mqb.enableSecurityChecks && len(mqb.allowedCollections) > 0 && !mqb.allowedCollections[collection.Name()] {
return nil, fmt.Errorf("disallowed collection: %s", collection.Name())
}
filter, err := mqb.buildFilter(filters)
if err != nil {
return nil, err
}
// Set timeout if not already in context
if _, hasDeadline := ctx.Deadline(); !hasDeadline && mqb.queryTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(mqb.queryTimeout)*time.Second)
defer cancel()
}
start := time.Now()
result, err := collection.DeleteMany(ctx, filter)
if mqb.enableQueryLogging {
fmt.Printf("[DEBUG] MongoDB Delete executed in %v\n", time.Since(start))
}
return result, err
}