Skip to content

Commit

Permalink
支持where 条件中的key 根据value判断是否op为in (#109)
Browse files Browse the repository at this point in the history
* 支持where 条件中的key 根据value判断是否op为in

* add readme ex

Co-authored-by: Hao Wu <hao.wu@yunzhanghu.com>
  • Loading branch information
voctior and Hao Wu authored Feb 24, 2021
1 parent faf1a3a commit 1d0b691
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 14 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"))
Expand Down
9 changes: 6 additions & 3 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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:], " ")
Expand Down
17 changes: 10 additions & 7 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}{
{
Expand Down Expand Up @@ -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,
},
},
Expand Down Expand Up @@ -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<?)",
vals: []interface{}{23, 1000, 50000},
cond: "SELECT name, count(price) as total FROM tb WHERE (age>?) GROUP BY name HAVING (vx IN (?,?,?) AND total>=? AND total<?)",
vals: []interface{}{23, 1, 3, 5, 1000, 50000},
err: nil,
},
},
Expand Down Expand Up @@ -519,6 +521,7 @@ func Test_BuildSelect(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{}{
{
Expand Down Expand Up @@ -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,
},
},
Expand Down Expand Up @@ -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)
}
}
13 changes: 11 additions & 2 deletions translation/zhcn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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{}{
Expand All @@ -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"))
Expand Down

0 comments on commit 1d0b691

Please sign in to comment.