diff --git a/db.go b/db.go index 80e6288ddc2f6edf2549a489dd3d1e43475c0fbb..fcea7e56486a08e981b7f6ecf579c95b6c0b0047 100644 --- a/db.go +++ b/db.go @@ -62,7 +62,21 @@ import ( // // Where age is lower than 18 (On MongoDB context). // db.Cond { "age $lt": 18 } -type Cond map[string]interface{} +type Cond builder.M + +func (m Cond) Constraints() []builder.Constraint { + return builder.M(m).Constraints() +} + +func (m Cond) Operator() builder.CompoundOperator { + return builder.M(m).Operator() +} + +func (m Cond) Sentences() []builder.Compound { + return builder.M(m).Sentences() +} + +/*map[string]interface{} func (m Cond) Constraints() []builder.Constraint { c := make([]builder.Constraint, 0, len(m)) @@ -71,6 +85,7 @@ func (m Cond) Constraints() []builder.Constraint { } return c } +*/ // Func is a struct that represents database functions. // @@ -124,20 +139,7 @@ func Func(name string, args ...interface{}) builder.Function { // }, // db.Cond{ "last_name": "Mouse" }, // } -type And []builder.Constraints - -// And adds a new expression to an And conditions array. -func (a And) And(t ...builder.Constraints) And { - return append(a, t...) -} - -func (a And) Constraints() []builder.Constraints { - return a -} - -func (a And) Operator() builder.ConstraintOperator { - return builder.OperatorAnd -} +var And = builder.And // Or is an array of interfaced that is used to join two or more expressions // under logical disjunction, it accepts `db.Cond{}`, `db.And{}`, `db.Raw{}` @@ -150,20 +152,7 @@ func (a And) Operator() builder.ConstraintOperator { // db.Cond{"year": 2012}, // db.Cond{"year": 1987}, // } -type Or []builder.Constraints - -// Or adds a new expression to an Or conditions array. -func (o Or) Or(t ...builder.Constraints) Or { - return append(o, t...) -} - -func (o Or) Constraints() []builder.Constraints { - return o -} - -func (o Or) Operator() builder.ConstraintOperator { - return builder.OperatorOr -} +var Or = builder.Or // Raw holds chunks of data to be passed to the database without any filtering. // Use with care. @@ -410,7 +399,6 @@ type Constrainer interface { var ( _ = builder.Constraints(Cond{}) - _ = builder.Criteria(And{}) - _ = builder.Criteria(Or{}) + _ = builder.Compound(Cond{}) _ = builder.Function(&dbFunc{}) ) diff --git a/db_test.go b/db_test.go index f389fc15496d0771dc9ec1e8761e4f72a0c82c4f..62646f59f908412cf0975342df40f661ee6b779f 100644 --- a/db_test.go +++ b/db_test.go @@ -718,13 +718,13 @@ func TestFibonacci(t *testing.T) { // Testing sorting by function. res = col.Find( // 5, 6, 7, 3 - db.Or{ - db.And{ + db.Or( + db.And( db.Cond{"input >=": 5}, db.Cond{"input <=": 7}, - }, + ), db.Cond{"input": 3}, - }, + ), ) // Testing sort by function. @@ -748,16 +748,7 @@ func TestFibonacci(t *testing.T) { } // Find() with IN/$in - var whereIn db.Cond - - switch wrapper { - case `mongo`: - whereIn = db.Cond{"input": db.Func("$in", 3, 5, 6, 7)} - default: - whereIn = db.Cond{"input": db.Func("IN", 3, 5, 6, 7)} - } - - res = col.Find(whereIn).Sort("input") + res = col.Find(db.Cond{"input IN": []int{3, 5, 6, 7}}).Sort("input") total, err = res.Count() @@ -794,13 +785,13 @@ func TestFibonacci(t *testing.T) { // Find() with range res = col.Find( // 5, 6, 7, 3 - db.Or{ - db.And{ + db.Or( + db.And( db.Cond{"input >=": 5}, db.Cond{"input <=": 7}, - }, + ), db.Cond{"input": 3}, - }, + ), ).Sort("-input") if total, err = res.Count(); err != nil { @@ -866,7 +857,7 @@ func TestFibonacci(t *testing.T) { } // Find() with empty expression - res1b := col.Find(db.Or{db.And{db.Cond{}, db.Cond{}}, db.Or{db.Cond{}}}) + res1b := col.Find(db.Or(db.And(db.Cond{}, db.Cond{}), db.Or(db.Cond{}))) total, err = res1b.Count() if total != 6 { diff --git a/mongo/benchmark_test.go b/mongo/benchmark_test.go index 3b23101f5d30402c0e3e743c4fef215462012e17..d915985bb9d0f7c6c01912c3e0ce3eaa40c7d5d4 100644 --- a/mongo/benchmark_test.go +++ b/mongo/benchmark_test.go @@ -262,11 +262,11 @@ func BenchmarkUpperFindAll(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - res := artist.Find(db.Or{ + res := artist.Find(db.Or( db.Cond{"name": artistN(i)}, db.Cond{"name": artistN(i + 1)}, db.Cond{"name": artistN(i + 2)}, - }) + )) if err = res.All(&items); err != nil { b.Fatal(err) } diff --git a/mongo/collection.go b/mongo/collection.go index c5fa1d69a82828a8f45c342e788e8a66af2c5a75..b5a366ea36303c4efe362f267156b4efb87a159a 100644 --- a/mongo/collection.go +++ b/mongo/collection.go @@ -23,6 +23,7 @@ package mongo import ( "fmt" + "log" "strings" "sync" @@ -88,11 +89,16 @@ func compileStatement(cond db.Cond) bson.M { field = strings.TrimSpace(field) chunks := strings.SplitN(field, ` `, 2) + log.Printf("chunks: %#v", chunks) var op string if len(chunks) > 1 { switch chunks[1] { + case `IN`: + op = `$in` + case `NOT IN`: + op = `$nin` case `>`: op = `$gt` case `<`: @@ -106,15 +112,10 @@ func compileStatement(cond db.Cond) bson.M { } } - switch value := value.(type) { - case builder.Function: - conds[chunks[0]] = bson.M{value.Name(): value.Arguments()} - default: - if op == "" { - conds[chunks[0]] = value - } else { - conds[chunks[0]] = bson.M{op: value} - } + if op == "" { + conds[chunks[0]] = value + } else { + conds[chunks[0]] = bson.M{op: value} } } @@ -138,24 +139,26 @@ func (col *Collection) compileConditions(term interface{}) interface{} { if len(values) > 0 { return values } - case db.Or: - values := []interface{}{} - for i := range t { - values = append(values, col.compileConditions(t[i])) - } - condition := bson.M{`$or`: values} - return condition - case db.And: - values := []interface{}{} - for i := range t { - values = append(values, col.compileConditions(t[i])) - } - condition := bson.M{`$and`: values} - return condition case db.Cond: return compileStatement(t) case db.Constrainer: return compileStatement(t.Constraints()) + case builder.Compound: + values := []interface{}{} + + for _, s := range t.Sentences() { + values = append(values, col.compileConditions(s)) + } + + var op string + switch t.Operator() { + case builder.OperatorOr: + op = `$or` + default: + op = `$and` + } + + return bson.M{op: values} } return nil } diff --git a/mongo/database_test.go b/mongo/database_test.go index 6380d8cdc31b6215358359ef69238cce404bd0fc..e22b3434b8591a6782bd88480b204da1404c57a0 100644 --- a/mongo/database_test.go +++ b/mongo/database_test.go @@ -816,8 +816,7 @@ func TestUpdate(t *testing.T) { } -// Test database functions -func TestFunction(t *testing.T) { +func TestOperators(t *testing.T) { var err error var res db.Result @@ -843,13 +842,7 @@ func TestFunction(t *testing.T) { Name string }{} - res = artist.Find(db.Cond{"_id $nin": []int{0, -1}}) - - if err = res.One(&rowS); err != nil { - t.Fatalf("One: %q", err) - } - - res = artist.Find(db.Cond{"_id": db.Func("$nin", 0, -1)}) + res = artist.Find(db.Cond{"_id NOT IN": []int{0, -1}}) if err = res.One(&rowS); err != nil { t.Fatalf("One: %q", err) diff --git a/mysql/benchmark_test.go b/mysql/benchmark_test.go index 57ad6cc995fa81a4d3f81fbc35d7e99c5eb44a08..8aa1803cdc6832dc71452bbcf119e3d69d31832b 100644 --- a/mysql/benchmark_test.go +++ b/mysql/benchmark_test.go @@ -528,11 +528,11 @@ func BenchmarkUpperFindAll(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - res := artist.Find(db.Or{ + res := artist.Find(db.Or( db.Cond{"name": artistN(i)}, db.Cond{"name": artistN(i + 1)}, db.Cond{"name": artistN(i + 2)}, - }) + )) if err = res.All(&items); err != nil { b.Fatal(err) } diff --git a/postgresql/benchmark_test.go b/postgresql/benchmark_test.go index 1402f590443aff1f93108eed5a0cd4b8e7bfade2..dff2de1e14d8a1cbb21d31b31bcc5f61249d7d08 100644 --- a/postgresql/benchmark_test.go +++ b/postgresql/benchmark_test.go @@ -540,11 +540,11 @@ func BenchmarkUpperFindAll(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - res := artist.Find(db.Or{ + res := artist.Find(db.Or( db.Cond{"name": artistN(i)}, db.Cond{"name": artistN(i + 1)}, db.Cond{"name": artistN(i + 2)}, - }) + )) if err = res.All(&items); err != nil { b.Fatal(err) } diff --git a/ql/benchmark_test.go b/ql/benchmark_test.go index f763f7b298a9cb63ff0aa3341a57b433a91154af..9e35c90e88b840d1d3ff12d8f84c19b7f8759175 100644 --- a/ql/benchmark_test.go +++ b/ql/benchmark_test.go @@ -607,11 +607,11 @@ func BenchmarkUpperFindAll(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - res := artist.Find(db.Or{ + res := artist.Find(db.Or( db.Cond{"name": artistN(i)}, db.Cond{"name": artistN(i + 1)}, db.Cond{"name": artistN(i + 2)}, - }) + )) if err = res.All(&items); err != nil { b.Fatal(err) } diff --git a/sqlite/benchmark_test.go b/sqlite/benchmark_test.go index b52339a42238fc294989097834131ea398ab5a91..e312e972a4aa50deada7d10190a2ab48df28caff 100644 --- a/sqlite/benchmark_test.go +++ b/sqlite/benchmark_test.go @@ -528,11 +528,11 @@ func BenchmarkUpperFindAll(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - res := artist.Find(db.Or{ + res := artist.Find(db.Or( db.Cond{"name": artistN(i)}, db.Cond{"name": artistN(i + 1)}, db.Cond{"name": artistN(i + 2)}, - }) + )) if err = res.All(&items); err != nil { b.Fatal(err) }