212 lines
7.0 KiB
Go
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
|
|
}
|