package dbs import ( "fmt" "strings" "go.mongodb.org/mongo-driver/bson" ) type Operator int const ( LIKE Operator = iota EXISTS IN GTE LTE LT GT EQUAL NOT ) var str = [...]string{ "like", "exists", "in", "gte", "lte", "lt", "gt", "equal", "not", } func (m Operator) String() string { return str[m] } func (m Operator) ToMongoEOperator(k string, value interface{}) bson.E { defer func() { if r := recover(); r != nil { fmt.Println("Recovered. Error:\n", r) } }() defaultValue := bson.E{Key: k, Value: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} switch m { case LIKE: return bson.E{Key: k, Value: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} case EXISTS: return bson.E{Key: k, Value: bson.M{"$exists": ToValueOperator(StringToOperator(m.String()), value)}} case IN: return bson.E{Key: k, Value: bson.M{"$in": ToValueOperator(StringToOperator(m.String()), value)}} case GTE: return bson.E{Key: k, Value: bson.M{"$gte": ToValueOperator(StringToOperator(m.String()), value)}} case GT: return bson.E{Key: k, Value: bson.M{"$gt": ToValueOperator(StringToOperator(m.String()), value)}} case LTE: return bson.E{Key: k, Value: bson.M{"$lte": ToValueOperator(StringToOperator(m.String()), value)}} case LT: return bson.E{Key: k, Value: bson.M{"$lt": ToValueOperator(StringToOperator(m.String()), value)}} case EQUAL: return bson.E{Key: k, Value: value} case NOT: v := value.(Filters) orList := bson.A{} andList := bson.A{} f := bson.D{} for k, filter := range v.Or { for _, ff := range filter { orList = append(orList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) } } for k, filter := range v.And { for _, ff := range filter { andList = append(andList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) } } if len(orList) > 0 && len(andList) == 0 { f = bson.D{{"$or", orList}} } else { if len(orList) > 0 { andList = append(andList, bson.M{"$or": orList}) } f = bson.D{{"$and", andList}} } return bson.E{Key: "$not", Value: f} default: return defaultValue } } func (m Operator) ToMongoOperator(k string, value interface{}) bson.M { defer func() { if r := recover(); r != nil { fmt.Println("Recovered. Error:\n", r) } }() defaultValue := bson.M{k: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} switch m { case LIKE: return bson.M{k: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} case EXISTS: return bson.M{k: bson.M{"$exists": ToValueOperator(StringToOperator(m.String()), value)}} case IN: return bson.M{k: bson.M{"$in": ToValueOperator(StringToOperator(m.String()), value)}} case GTE: return bson.M{k: bson.M{"$gte": ToValueOperator(StringToOperator(m.String()), value)}} case GT: return bson.M{k: bson.M{"$gt": ToValueOperator(StringToOperator(m.String()), value)}} case LTE: return bson.M{k: bson.M{"$lte": ToValueOperator(StringToOperator(m.String()), value)}} case LT: return bson.M{k: bson.M{"$lt": ToValueOperator(StringToOperator(m.String()), value)}} case EQUAL: return bson.M{k: value} case NOT: v := value.(Filters) orList := bson.A{} andList := bson.A{} f := bson.D{} for k, filter := range v.Or { for _, ff := range filter { orList = append(orList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) } } for k, filter := range v.And { for _, ff := range filter { andList = append(andList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) } } if len(orList) > 0 && len(andList) == 0 { f = bson.D{{"$or", orList}} } else { if len(orList) > 0 { andList = append(andList, bson.M{"$or": orList}) } f = bson.D{{"$and", andList}} } return bson.M{"$not": f} default: return defaultValue } } func StringToOperator(s string) Operator { for i, v := range str { if v == s { return Operator(i) } } return LIKE } func ToValueOperator(operator Operator, value interface{}) interface{} { if strings.TrimSpace(fmt.Sprintf("%v", value)) == "*" { value = "" } if operator == LIKE { return "(?i).*" + strings.TrimSpace(fmt.Sprintf("%v", value)) + ".*" } return value } type Filters struct { And map[string][]Filter `json:"and"` Or map[string][]Filter `json:"or"` } type Filter struct { Operator string `json:"operator,omitempty"` Value interface{} `json:"value,omitempty"` } type Input = map[string]interface{} func InputToBson(i Input, isUpdate bool) bson.D { input := bson.D{} for k, v := range i { if k == "id" { input = append(input, bson.E{Key: "_id", Value: v}) } else { input = append(input, bson.E{Key: k, Value: v}) } } if isUpdate { return bson.D{{Key: "$set", Value: input}} } return input }