diff --git a/README.md b/README.md index 6abee76..796b717 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,10 @@ builder isn't an ORM, in fact one of the most important reasons we create Gendry ```go where := map[string]interface{}{ - "city in": []string{"beijing", "shanghai"}, + "city": []string{"beijing", "shanghai"}, + // The in operator can be omitted by default, + // which is equivalent to: + // "city in": []string{"beijing", "shanghai"}, "score": 5, "age >": 35, "address": builder.IsNotNull, @@ -81,12 +84,27 @@ cond, values, err := builder.BuildSelect(table, where, selectFields) rows, err := db.Query(cond, values...) ``` + +In the `where` param, automatically add 'in' operator by value type(reflect.Slice). + +```go +where := map[string]interface{}{ + "city": []string{"beijing", "shanghai"}, +} +``` +the same as +```go +where := map[string]interface{}{ + "city in": []string{"beijing", "shanghai"}, +} +``` + And, the library provide a useful API for executing aggregate queries like count, sum, max, min, avg ```go where := map[string]interface{}{ "score > ": 100, - "city in": []interface{}{"Beijing", "Shijiazhuang", } + "city": []interface{}{"Beijing", "Shijiazhuang", } } // AggregateSum, AggregateMax, AggregateMin, AggregateCount, AggregateAvg are supported result, err := AggregateQuery(ctx, db, "tableName", where, AggregateSum("age")) diff --git a/builder/builder.go b/builder/builder.go index 2ad99ff..0dc447b 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -156,7 +156,7 @@ func resolveHaving(having interface{}) (map[string]interface{}, error) { } copiedMap := make(map[string]interface{}) for key, val := range havingMap { - _, operator, err := splitKey(key) + _, operator, err := splitKey(key, val) if nil != err { return nil, err } @@ -264,7 +264,7 @@ func getWhereConditions(where map[string]interface{}, ignoreKeys map[string]stru comparables = append(comparables, OrWhere(orWhereComparable)) continue } - field, operator, err = splitKey(key) + field, operator, err = splitKey(key, val) if nil != err { return nil, err } @@ -415,7 +415,7 @@ func convertInterfaceToMap(val interface{}) ([]interface{}, bool) { return interfaceSlice, true } -func splitKey(key string) (field string, operator string, err error) { +func splitKey(key string, val interface{}) (field string, operator string, err error) { key = strings.Trim(key, " ") if "" == key { err = errSplitEmptyKey @@ -425,6 +425,9 @@ func splitKey(key string) (field string, operator string, err error) { if idx == -1 { field = key operator = "=" + if reflect.ValueOf(val).Kind() == reflect.Slice { + operator = "in" + } } else { field = key[:idx] operator = strings.Trim(key[idx+1:], " ") diff --git a/builder/builder_test.go b/builder/builder_test.go index 55dc579..54ae426 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -29,6 +29,7 @@ func TestBuildLockMode(t *testing.T) { "foo": "bar", "qq": "tt", "age in": []interface{}{1, 3, 5, 7, 9}, + "vx": []interface{}{1, 3, 5}, "faith <>": "Muslim", "_or": []map[string]interface{}{ { @@ -58,8 +59,8 @@ func TestBuildLockMode(t *testing.T) { fields: []string{"id", "name", "age"}, }, out: outStruct{ - cond: "SELECT id,name,age FROM tb WHERE (((aa=? AND bb=?) OR (((neeest_ff IN (?,?) AND neeest_ee!=?) OR (neeest_gg=? AND neeest_hh NOT IN (?,?))) AND cc=? AND dd IN (?,?))) AND foo=? AND qq=? AND age IN (?,?,?,?,?) AND faith!=?) GROUP BY department ORDER BY age DESC,score ASC LIMIT ?,? LOCK IN SHARE MODE", - vals: []interface{}{11, "xswl", 34, 59, "dw42", 1259, 358, 1245, "234", 7, 8, "bar", "tt", 1, 3, 5, 7, 9, "Muslim", 0, 100}, + cond: "SELECT id,name,age FROM tb WHERE (((aa=? AND bb=?) OR (((neeest_ff IN (?,?) AND neeest_ee!=?) OR (neeest_gg=? AND neeest_hh NOT IN (?,?))) AND cc=? AND dd IN (?,?))) AND foo=? AND qq=? AND age IN (?,?,?,?,?) AND vx IN (?,?,?) AND faith!=?) GROUP BY department ORDER BY age DESC,score ASC LIMIT ?,? LOCK IN SHARE MODE", + vals: []interface{}{11, "xswl", 34, 59, "dw42", 1259, 358, 1245, "234", 7, 8, "bar", "tt", 1, 3, 5, 7, 9, 1, 3, 5, "Muslim", 0, 100}, err: nil, }, }, @@ -157,13 +158,14 @@ func TestBuildHaving(t *testing.T) { "_having": map[string]interface{}{ "total >=": 1000, "total <": 50000, + "vx": []interface{}{1, 3, 5}, }, }, selectField: []string{"name, count(price) as total"}, }, out: outStruct{ - cond: "SELECT name, count(price) as total FROM tb WHERE (age>?) GROUP BY name HAVING (total>=? AND total?) GROUP BY name HAVING (vx IN (?,?,?) AND total>=? AND total": "Muslim", "_or": []map[string]interface{}{ { @@ -547,8 +550,8 @@ func Test_BuildSelect(t *testing.T) { fields: []string{"id", "name", "age"}, }, out: outStruct{ - cond: "SELECT id,name,age FROM tb WHERE (((aa=? AND bb=?) OR (((neeest_ff IN (?,?) AND neeest_ee!=?) OR (neeest_gg=? AND neeest_hh NOT IN (?,?))) AND cc=? AND dd IN (?,?))) AND foo=? AND qq=? AND age IN (?,?,?,?,?) AND faith!=?) GROUP BY department ORDER BY age DESC,score ASC LIMIT ?,?", - vals: []interface{}{11, "xswl", 34, 59, "dw42", 1259, 358, 1245, "234", 7, 8, "bar", "tt", 1, 3, 5, 7, 9, "Muslim", 0, 100}, + cond: "SELECT id,name,age FROM tb WHERE (((aa=? AND bb=?) OR (((neeest_ff IN (?,?) AND neeest_ee!=?) OR (neeest_gg=? AND neeest_hh NOT IN (?,?))) AND cc=? AND dd IN (?,?))) AND foo=? AND qq=? AND age IN (?,?,?,?,?) AND vx IN (?,?,?) AND faith!=?) GROUP BY department ORDER BY age DESC,score ASC LIMIT ?,?", + vals: []interface{}{11, "xswl", 34, 59, "dw42", 1259, 358, 1245, "234", 7, 8, "bar", "tt", 1, 3, 5, 7, 9, 1, 3, 5, "Muslim", 0, 100}, err: nil, }, }, @@ -1314,4 +1317,4 @@ func TestInsertOnDuplicate(t *testing.T) { ass.NoError(err) ass.Equal("INSERT INTO tb (a,b,c) VALUES (?,?,?) ON DUPLICATE KEY UPDATE c=?", cond) ass.Equal([]interface{}{1, 2, 3, 4}, vals) -} \ No newline at end of file +} diff --git a/translation/zhcn/README.md b/translation/zhcn/README.md index a175be4..93da080 100644 --- a/translation/zhcn/README.md +++ b/translation/zhcn/README.md @@ -44,7 +44,9 @@ builder不是一个ORM(我们开发Gendry的重要原因之一就是不喜欢O ```go where := map[string]interface{}{ - "city in": []string{"beijing", "shanghai"}, + "city": []string{"beijing", "shanghai"}, + // 默认可以省略 in 操作符,等同于: + // "city in": []string{"beijing", "shanghai"}, "score": 5, "age >": 35, "address": builder.IsNotNull, @@ -61,6 +63,13 @@ cond, values, err := builder.BuildSelect(table, where, selectFields) rows,err := db.Query(cond, values...) ``` +默认 `where` 参数中可以根据value(reflect.Slice)类型来自动的添加 `in` 参数 +```go +where := map[string]interface{}{ + "city": []string{"beijing", "shanghai"}, +} +``` + 如果你想清除where map中的零值可以使用 builder.OmitEmpty ``` go where := map[string]interface{}{ @@ -78,7 +87,7 @@ finalWhere := builder.OmitEmpty(where, []string{"score", "age"}) ```go where := map[string]interface{}{ "score > ": 100, - "city in": []interface{}{"Beijing", "Shijiazhuang",} + "city": []interface{}{"Beijing", "Shijiazhuang",} } // AggregateSum,AggregateMax,AggregateMin,AggregateCount,AggregateAvg is supported result, err := AggregateQuery(ctx, db, "tableName", where, AggregateSum("age"))