Skip to content

Commit

Permalink
Merge branch 'master' of github.com:didi/Gendry
Browse files Browse the repository at this point in the history
  • Loading branch information
caibirdme committed Apr 18, 2019
2 parents d498822 + ea1a1e6 commit 0a22272
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ result, err = AggregateQuery(ctx, db, "tableName", where, AggregateAvg("score"))
averageScore := result.Float64()
```

If you want to clear the zero value in the where map, you can use builder.OmitEmpty
``` go
where := map[string]interface{}{
"score": 0,
"age >": 35,
}
finalWhere := builder.OmitEmpty(where, []string{"score", "age"})
// finalWhere = map[string]interface{}{"age >": 35}

// support: Bool, Array, String, Float32, Float64, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Map, Slice, Interface, Struct
```

For complex queries, `NamedQuery` may be helpful:
```go
cond, vals, err := builder.NamedQuery("select * from tb where name={{name}} and id in (select uid from anothertable where score in {{m_score}})", map[string]interface{}{
Expand Down
55 changes: 55 additions & 0 deletions builder/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package builder
import (
"context"
"database/sql"
"reflect"
"strconv"
)

Expand Down Expand Up @@ -110,3 +111,57 @@ func AggregateMax(col string) AggregateSymbleBuilder {
func AggregateMin(col string) AggregateSymbleBuilder {
return agBuilder("min(" + col + ")")
}

// OmitEmpty is a helper function to clear where map zero value
func OmitEmpty(where map[string]interface{}, omitKey []string) map[string]interface{} {
for _, key := range omitKey {
v, ok := where[key]
if !ok {
continue
}

if isZero(reflect.ValueOf(v)) {
delete(where, key)
}
}
return where
}

// isZero reports whether a value is a zero value
// Including support: Bool, Array, String, Float32, Float64, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr
// Map, Slice, Interface, Struct
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return !v.Bool()
case reflect.Array, reflect.String:
return v.Len() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Map, reflect.Slice:
return v.IsNil() || v.Len() == 0
case reflect.Interface:
return v.IsNil()
case reflect.Invalid:
return true
}

if v.Kind() != reflect.Struct {
return false
}

// Traverse the Struct and only return true
// if all of its fields return IsZero == true
n := v.NumField()
for i := 0; i < n; i++ {
vf := v.Field(i)
if !isZero(vf) {
return false
}
}
return true
}
123 changes: 123 additions & 0 deletions builder/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package builder
import (
"context"
"math"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -137,3 +138,125 @@ func TestAggregateQuery(t *testing.T) {
ass.True(math.Abs(result.Float64()-tc.floatout) < 1e6)
}
}

func TestOmitEmpty(t *testing.T) {
var (
m map[string]string
sl []string
i interface{}
)

type stru struct {
x string
y int
}

var testData = []struct {
where map[string]interface{}
omitKey []string
finalWhere map[string]interface{}
}{
// Bool
{
map[string]interface{}{"b1": true, "b2": false},
[]string{"b1", "b2", "b2"},
map[string]interface{}{"b1": true},
},
// Array, String
{
map[string]interface{}{"a1": [0]string{}, "a2": [...]string{"2"}},
[]string{"a1", "a2"},
map[string]interface{}{"a2": [...]string{"2"}},
},
// Float32, Float64
{
map[string]interface{}{"f1": float32(0), "f2": float32(1.1)},
[]string{"f1", "f2"},
map[string]interface{}{"f2": float32(1.1)},
},
{
map[string]interface{}{"f1": float64(0), "f2": float64(1.1)},
[]string{"f1", "f2"},
map[string]interface{}{"f2": float64(1.1)},
},
// Int, Int8, Int16, Int32, Int64
{
map[string]interface{}{"i8": int8(0), "i8_1": int8(8)},
[]string{"i8", "i8_1"},
map[string]interface{}{"i8_1": int8(8)},
},
{
map[string]interface{}{"i16": int16(0), "i16_1": int16(16)},
[]string{"i16", "i16_1"},
map[string]interface{}{"i16_1": int16(16)},
},
{
map[string]interface{}{"i32": int32(0), "i32_1": int32(32)},
[]string{"i32", "i32_1"},
map[string]interface{}{"i32_1": int32(32)},
},
{
map[string]interface{}{"i64": int64(0), "i64_1": int64(64)},
[]string{"i64", "i64_1"},
map[string]interface{}{"i64_1": int64(64)},
},
// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr
{
map[string]interface{}{"ui": uint(0), "ui_1": uint(1)},
[]string{"ui", "ui_1"},
map[string]interface{}{"ui_1": uint(1)},
},
{
map[string]interface{}{"ui8": uint8(0), "ui8_1": uint8(8)},
[]string{"ui8", "ui8_1"},
map[string]interface{}{"ui8_1": uint8(8)},
},
{
map[string]interface{}{"ui16": uint16(0), "ui16_1": uint16(16)},
[]string{"ui16", "ui16_1"},
map[string]interface{}{"ui16_1": uint16(16)},
},
{
map[string]interface{}{"ui32": uint32(0), "ui32_1": uint32(32)},
[]string{"ui32", "ui32_1"},
map[string]interface{}{"ui32_1": uint32(32)},
},
{
map[string]interface{}{"ui64": uint64(0), "ui64_1": uint64(64)},
[]string{"ui64", "ui64_1"},
map[string]interface{}{"ui64_1": uint64(64)},
},
{
map[string]interface{}{"uip": uintptr(0), "uip_1": uintptr(1)},
[]string{"uip", "uip_1"},
map[string]interface{}{"uip_1": uintptr(1)},
},
// Map, Slice, Interface
{
map[string]interface{}{"m1": m, "m2": map[string]string{"foo": "hi"}, "m3": map[string]string{}},
[]string{"m1", "m2", "m3"},
map[string]interface{}{"m2": map[string]string{"foo": "hi"}},
},
{
map[string]interface{}{"sl1": sl, "sl2": []string{"sl"}, "sl3": []int{}},
[]string{"sl1", "sl2", "sl3"},
map[string]interface{}{"sl2": []string{"sl"}},
},
{
map[string]interface{}{"i": i},
[]string{"i"},
map[string]interface{}{},
},
// struct
{
map[string]interface{}{"stru1": stru{x: "s", y: 0}, "stru2": stru{x: "", y: 0}},
[]string{"stru1", "stru2"},
map[string]interface{}{"stru1": stru{x: "s", y: 0}},
},
}
ass := assert.New(t)
for _, tc := range testData {
r := OmitEmpty(tc.where, tc.omitKey)
ass.True(reflect.DeepEqual(tc.finalWhere, r))
}
}
12 changes: 12 additions & 0 deletions translation/zhcn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ cond, values, err := builder.BuildSelect(table, where, selectFields)
rows,err := db.Query(cond, values...)
```

如果你想清除where map中的零值可以使用 builder.OmitEmpty
``` go
where := map[string]interface{}{
"score": 0,
"age": 35,
}
finalWhere := builder.OmitEmpty(where, []string{"score", "age"})
// finalWhere = map[string]interface{}{"age": 35}

// support: Bool, Array, String, Float32, Float64, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Map, Slice, Interface, Struct
```

同时,builder还提供一个便捷方法来进行聚合查询,比如:count,sum,max,min,avg

```go
Expand Down

0 comments on commit 0a22272

Please sign in to comment.