Skip to content

Commit 0a22272

Browse files
committed
Merge branch 'master' of github.com:didi/Gendry
2 parents d498822 + ea1a1e6 commit 0a22272

File tree

4 files changed

+202
-0
lines changed

4 files changed

+202
-0
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ result, err = AggregateQuery(ctx, db, "tableName", where, AggregateAvg("score"))
8787
averageScore := result.Float64()
8888
```
8989

90+
If you want to clear the zero value in the where map, you can use builder.OmitEmpty
91+
``` go
92+
where := map[string]interface{}{
93+
"score": 0,
94+
"age >": 35,
95+
}
96+
finalWhere := builder.OmitEmpty(where, []string{"score", "age"})
97+
// finalWhere = map[string]interface{}{"age >": 35}
98+
99+
// support: Bool, Array, String, Float32, Float64, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Map, Slice, Interface, Struct
100+
```
101+
90102
For complex queries, `NamedQuery` may be helpful:
91103
```go
92104
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{}{

builder/utils.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package builder
33
import (
44
"context"
55
"database/sql"
6+
"reflect"
67
"strconv"
78
)
89

@@ -110,3 +111,57 @@ func AggregateMax(col string) AggregateSymbleBuilder {
110111
func AggregateMin(col string) AggregateSymbleBuilder {
111112
return agBuilder("min(" + col + ")")
112113
}
114+
115+
// OmitEmpty is a helper function to clear where map zero value
116+
func OmitEmpty(where map[string]interface{}, omitKey []string) map[string]interface{} {
117+
for _, key := range omitKey {
118+
v, ok := where[key]
119+
if !ok {
120+
continue
121+
}
122+
123+
if isZero(reflect.ValueOf(v)) {
124+
delete(where, key)
125+
}
126+
}
127+
return where
128+
}
129+
130+
// isZero reports whether a value is a zero value
131+
// Including support: Bool, Array, String, Float32, Float64, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr
132+
// Map, Slice, Interface, Struct
133+
func isZero(v reflect.Value) bool {
134+
switch v.Kind() {
135+
case reflect.Bool:
136+
return !v.Bool()
137+
case reflect.Array, reflect.String:
138+
return v.Len() == 0
139+
case reflect.Float32, reflect.Float64:
140+
return v.Float() == 0
141+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
142+
return v.Int() == 0
143+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
144+
return v.Uint() == 0
145+
case reflect.Map, reflect.Slice:
146+
return v.IsNil() || v.Len() == 0
147+
case reflect.Interface:
148+
return v.IsNil()
149+
case reflect.Invalid:
150+
return true
151+
}
152+
153+
if v.Kind() != reflect.Struct {
154+
return false
155+
}
156+
157+
// Traverse the Struct and only return true
158+
// if all of its fields return IsZero == true
159+
n := v.NumField()
160+
for i := 0; i < n; i++ {
161+
vf := v.Field(i)
162+
if !isZero(vf) {
163+
return false
164+
}
165+
}
166+
return true
167+
}

builder/utils_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package builder
33
import (
44
"context"
55
"math"
6+
"reflect"
67
"testing"
78

89
"github.com/stretchr/testify/assert"
@@ -137,3 +138,125 @@ func TestAggregateQuery(t *testing.T) {
137138
ass.True(math.Abs(result.Float64()-tc.floatout) < 1e6)
138139
}
139140
}
141+
142+
func TestOmitEmpty(t *testing.T) {
143+
var (
144+
m map[string]string
145+
sl []string
146+
i interface{}
147+
)
148+
149+
type stru struct {
150+
x string
151+
y int
152+
}
153+
154+
var testData = []struct {
155+
where map[string]interface{}
156+
omitKey []string
157+
finalWhere map[string]interface{}
158+
}{
159+
// Bool
160+
{
161+
map[string]interface{}{"b1": true, "b2": false},
162+
[]string{"b1", "b2", "b2"},
163+
map[string]interface{}{"b1": true},
164+
},
165+
// Array, String
166+
{
167+
map[string]interface{}{"a1": [0]string{}, "a2": [...]string{"2"}},
168+
[]string{"a1", "a2"},
169+
map[string]interface{}{"a2": [...]string{"2"}},
170+
},
171+
// Float32, Float64
172+
{
173+
map[string]interface{}{"f1": float32(0), "f2": float32(1.1)},
174+
[]string{"f1", "f2"},
175+
map[string]interface{}{"f2": float32(1.1)},
176+
},
177+
{
178+
map[string]interface{}{"f1": float64(0), "f2": float64(1.1)},
179+
[]string{"f1", "f2"},
180+
map[string]interface{}{"f2": float64(1.1)},
181+
},
182+
// Int, Int8, Int16, Int32, Int64
183+
{
184+
map[string]interface{}{"i8": int8(0), "i8_1": int8(8)},
185+
[]string{"i8", "i8_1"},
186+
map[string]interface{}{"i8_1": int8(8)},
187+
},
188+
{
189+
map[string]interface{}{"i16": int16(0), "i16_1": int16(16)},
190+
[]string{"i16", "i16_1"},
191+
map[string]interface{}{"i16_1": int16(16)},
192+
},
193+
{
194+
map[string]interface{}{"i32": int32(0), "i32_1": int32(32)},
195+
[]string{"i32", "i32_1"},
196+
map[string]interface{}{"i32_1": int32(32)},
197+
},
198+
{
199+
map[string]interface{}{"i64": int64(0), "i64_1": int64(64)},
200+
[]string{"i64", "i64_1"},
201+
map[string]interface{}{"i64_1": int64(64)},
202+
},
203+
// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr
204+
{
205+
map[string]interface{}{"ui": uint(0), "ui_1": uint(1)},
206+
[]string{"ui", "ui_1"},
207+
map[string]interface{}{"ui_1": uint(1)},
208+
},
209+
{
210+
map[string]interface{}{"ui8": uint8(0), "ui8_1": uint8(8)},
211+
[]string{"ui8", "ui8_1"},
212+
map[string]interface{}{"ui8_1": uint8(8)},
213+
},
214+
{
215+
map[string]interface{}{"ui16": uint16(0), "ui16_1": uint16(16)},
216+
[]string{"ui16", "ui16_1"},
217+
map[string]interface{}{"ui16_1": uint16(16)},
218+
},
219+
{
220+
map[string]interface{}{"ui32": uint32(0), "ui32_1": uint32(32)},
221+
[]string{"ui32", "ui32_1"},
222+
map[string]interface{}{"ui32_1": uint32(32)},
223+
},
224+
{
225+
map[string]interface{}{"ui64": uint64(0), "ui64_1": uint64(64)},
226+
[]string{"ui64", "ui64_1"},
227+
map[string]interface{}{"ui64_1": uint64(64)},
228+
},
229+
{
230+
map[string]interface{}{"uip": uintptr(0), "uip_1": uintptr(1)},
231+
[]string{"uip", "uip_1"},
232+
map[string]interface{}{"uip_1": uintptr(1)},
233+
},
234+
// Map, Slice, Interface
235+
{
236+
map[string]interface{}{"m1": m, "m2": map[string]string{"foo": "hi"}, "m3": map[string]string{}},
237+
[]string{"m1", "m2", "m3"},
238+
map[string]interface{}{"m2": map[string]string{"foo": "hi"}},
239+
},
240+
{
241+
map[string]interface{}{"sl1": sl, "sl2": []string{"sl"}, "sl3": []int{}},
242+
[]string{"sl1", "sl2", "sl3"},
243+
map[string]interface{}{"sl2": []string{"sl"}},
244+
},
245+
{
246+
map[string]interface{}{"i": i},
247+
[]string{"i"},
248+
map[string]interface{}{},
249+
},
250+
// struct
251+
{
252+
map[string]interface{}{"stru1": stru{x: "s", y: 0}, "stru2": stru{x: "", y: 0}},
253+
[]string{"stru1", "stru2"},
254+
map[string]interface{}{"stru1": stru{x: "s", y: 0}},
255+
},
256+
}
257+
ass := assert.New(t)
258+
for _, tc := range testData {
259+
r := OmitEmpty(tc.where, tc.omitKey)
260+
ass.True(reflect.DeepEqual(tc.finalWhere, r))
261+
}
262+
}

translation/zhcn/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ cond, values, err := builder.BuildSelect(table, where, selectFields)
6161
rows,err := db.Query(cond, values...)
6262
```
6363

64+
如果你想清除where map中的零值可以使用 builder.OmitEmpty
65+
``` go
66+
where := map[string]interface{}{
67+
"score": 0,
68+
"age": 35,
69+
}
70+
finalWhere := builder.OmitEmpty(where, []string{"score", "age"})
71+
// finalWhere = map[string]interface{}{"age": 35}
72+
73+
// support: Bool, Array, String, Float32, Float64, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Map, Slice, Interface, Struct
74+
```
75+
6476
同时,builder还提供一个便捷方法来进行聚合查询,比如:count,sum,max,min,avg
6577

6678
```go

0 commit comments

Comments
 (0)