merge IgnoreEmptySliceWhere feature into OmitEmptyWhere

This commit is contained in:
John Guo
2021-10-29 10:50:14 +08:00
parent e5c6d3f777
commit a6a8d787e4
4 changed files with 117 additions and 111 deletions

View File

@ -402,13 +402,12 @@ func formatSql(sql string, args []interface{}) (newSql string, newArgs []interfa
}
type formatWhereInput struct {
Where interface{}
Args []interface{}
OmitNil bool
OmitEmpty bool
IgnoreEmptySliceWhere bool
Schema string
Table string
Where interface{}
Args []interface{}
OmitNil bool
OmitEmpty bool
Schema string
Table string
}
// formatWhere formats where statement and its arguments for `Where` and `Having` statements.
@ -432,12 +431,11 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
}
}
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
Db: db,
Buffer: buffer,
Args: newArgs,
Key: key,
Value: value,
IgnoreEmptySliceWhere: in.IgnoreEmptySliceWhere,
Db: db,
Buffer: buffer,
Args: newArgs,
Key: key,
Value: value,
})
}
@ -458,12 +456,12 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
}
}
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
Db: db,
Buffer: buffer,
Args: newArgs,
Key: ketStr,
Value: value,
IgnoreEmptySliceWhere: in.IgnoreEmptySliceWhere,
Db: db,
Buffer: buffer,
Args: newArgs,
Key: ketStr,
Value: value,
OmitEmpty: in.OmitEmpty,
})
return true
})
@ -490,12 +488,12 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
continue
}
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
Db: db,
Buffer: buffer,
Args: newArgs,
Key: foundKey,
Value: foundValue,
IgnoreEmptySliceWhere: in.IgnoreEmptySliceWhere,
Db: db,
Buffer: buffer,
Args: newArgs,
Key: foundKey,
Value: foundValue,
OmitEmpty: in.OmitEmpty,
})
}
}
@ -507,13 +505,13 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
whereStr = gconv.String(in.Where)
)
// Eg:
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
// IgnoreEmptySliceWhere().Where("id", []int{}).One() -> SELECT xxx FROM xxx
if in.IgnoreEmptySliceWhere && len(in.Args) == 1 && utils.IsArray(in.Args[0]) {
if gstr.Count(whereStr, "?") == 0 && utils.IsEmpty(in.Args[0]) {
in.Args = in.Args[:0]
break
}
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
// Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
// OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
// OmitEmpty().("name", "").All() -> SELECT xxx FROM xxx
if in.OmitEmpty && len(in.Args) == 1 && gstr.Count(whereStr, "?") == 0 && utils.IsEmpty(in.Args[0]) {
in.Args = in.Args[:0]
break
}
for {
if i >= len(in.Args) {
@ -608,17 +606,31 @@ func formatWhereInterfaces(db DB, where []interface{}, buffer *bytes.Buffer, new
}
type formatWhereKeyValueInput struct {
Db DB
Buffer *bytes.Buffer
Args []interface{}
Key string
Value interface{}
IgnoreEmptySliceWhere bool
Db DB
Buffer *bytes.Buffer
Args []interface{}
Key string
Value interface{}
OmitEmpty bool
}
// formatWhereKeyValue handles each key-value pair of the parameter map.
func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) {
quotedKey := in.Db.GetCore().QuoteWord(in.Key)
var (
quotedKey = in.Db.GetCore().QuoteWord(in.Key)
holderCount = gstr.Count(quotedKey, "?")
)
// Eg:
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
// Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
// OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
// OmitEmpty().("name", "").All() -> SELECT xxx FROM xxx
if in.OmitEmpty && holderCount == 0 && gutil.IsEmpty(in.Value) {
return in.Args
}
if in.Buffer.Len() > 0 {
in.Buffer.WriteString(" AND ")
}
// If the value is type of slice, and there's only one '?' holder in
// the key string, it automatically adds '?' holder chars according to its arguments count
// and converts it to "IN" statement.
@ -629,22 +641,11 @@ func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) {
switch reflectKind {
// Slice argument.
case reflect.Slice, reflect.Array:
count := gstr.Count(quotedKey, "?")
// Eg:
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
// IgnoreEmptySliceWhere().Where("id", []int{}).One() -> SELECT xxx FROM xxx
if count == 0 && reflectValue.Len() == 0 && in.IgnoreEmptySliceWhere {
return in.Args
}
if in.Buffer.Len() > 0 {
in.Buffer.WriteString(" AND ")
}
if count == 0 {
if holderCount == 0 {
in.Buffer.WriteString(quotedKey + " IN(?)")
in.Args = append(in.Args, in.Value)
} else {
if count != reflectValue.Len() {
if holderCount != reflectValue.Len() {
in.Buffer.WriteString(quotedKey)
in.Args = append(in.Args, in.Value)
} else {
@ -654,9 +655,6 @@ func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) {
}
default:
if in.Buffer.Len() > 0 {
in.Buffer.WriteString(" AND ")
}
if in.Value == nil || empty.IsNil(reflectValue) {
if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
// The key is a single field name.

View File

@ -340,13 +340,12 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
case whereHolderOperatorWhere:
if conditionWhere == "" {
newWhere, newArgs := formatWhere(m.db, formatWhereInput{
Where: v.Where,
Args: v.Args,
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
IgnoreEmptySliceWhere: m.option&optionIgnoreEmptySliceWhere > 0,
Schema: m.schema,
Table: m.tables,
Where: v.Where,
Args: v.Args,
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
Schema: m.schema,
Table: m.tables,
})
if len(newWhere) > 0 {
conditionWhere = newWhere
@ -358,13 +357,12 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
case whereHolderOperatorAnd:
newWhere, newArgs := formatWhere(m.db, formatWhereInput{
Where: v.Where,
Args: v.Args,
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
IgnoreEmptySliceWhere: m.option&optionIgnoreEmptySliceWhere > 0,
Schema: m.schema,
Table: m.tables,
Where: v.Where,
Args: v.Args,
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
Schema: m.schema,
Table: m.tables,
})
if len(newWhere) > 0 {
if len(conditionWhere) == 0 {
@ -379,13 +377,12 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
case whereHolderOperatorOr:
newWhere, newArgs := formatWhere(m.db, formatWhereInput{
Where: v.Where,
Args: v.Args,
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
IgnoreEmptySliceWhere: m.option&optionIgnoreEmptySliceWhere > 0,
Schema: m.schema,
Table: m.tables,
Where: v.Where,
Args: v.Args,
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
Schema: m.schema,
Table: m.tables,
})
if len(newWhere) > 0 {
if len(conditionWhere) == 0 {
@ -427,13 +424,12 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
// HAVING.
if len(m.having) > 0 {
havingStr, havingArgs := formatWhere(m.db, formatWhereInput{
Where: m.having[0],
Args: gconv.Interfaces(m.having[1]),
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
IgnoreEmptySliceWhere: m.option&optionIgnoreEmptySliceWhere > 0,
Schema: m.schema,
Table: m.tables,
Where: m.having[0],
Args: gconv.Interfaces(m.having[1]),
OmitNil: m.option&optionOmitNilWhere > 0,
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
Schema: m.schema,
Table: m.tables,
})
if len(havingStr) > 0 {
conditionExtra += " HAVING " + havingStr

View File

@ -7,27 +7,14 @@
package gdb
const (
optionOmitNil = optionOmitNilWhere | optionOmitNilData
optionOmitEmpty = optionOmitEmptyWhere | optionOmitEmptyData
optionOmitEmptyWhere = 1 << iota // 8
optionOmitEmptyData // 16
optionOmitNilWhere // 32
optionOmitNilData // 64
optionIgnoreEmptySliceWhere // 128
optionOmitNil = optionOmitNilWhere | optionOmitNilData
optionOmitEmpty = optionOmitEmptyWhere | optionOmitEmptyData
optionOmitEmptyWhere = 1 << iota // 8
optionOmitEmptyData // 16
optionOmitNilWhere // 32
optionOmitNilData // 64
)
// IgnoreEmptySliceWhere sets optionIgnoreEmptySliceWhere option for the model, which automatically filers
// the where parameters for `empty` slice values.
//
// Eg:
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
// OmitEmptyWhereSlice().Where("id", []int{}).One() -> SELECT xxx FROM xxx
func (m *Model) IgnoreEmptySliceWhere() *Model {
model := m.getModel()
model.option = model.option | optionIgnoreEmptySliceWhere
return model
}
// OmitEmpty sets optionOmitEmpty option for the model, which automatically filers
// the data and where parameters for `empty` values.
func (m *Model) OmitEmpty() *Model {
@ -38,6 +25,12 @@ func (m *Model) OmitEmpty() *Model {
// OmitEmptyWhere sets optionOmitEmptyWhere option for the model, which automatically filers
// the Where/Having parameters for `empty` values.
//
// Eg:
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
// Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
// OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
// OmitEmpty().("name", "").All() -> SELECT xxx FROM xxx
func (m *Model) OmitEmptyWhere() *Model {
model := m.getModel()
model.option = model.option | optionOmitEmptyWhere

View File

@ -3676,11 +3676,27 @@ func Test_Model_FieldAvg(t *testing.T) {
})
}
func Test_Model_IgnoreEmptySliceWhere(t *testing.T) {
func Test_Model_OmitEmptyWhere(t *testing.T) {
table := createInitTable()
defer dropTable(table)
// Key-Value where.
// Basic type where.
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).Where("id", 0).Count()
t.AssertNil(err)
t.Assert(count, 0)
})
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Count()
t.AssertNil(err)
t.Assert(count, TableSize)
})
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Where("nickname", "").Count()
t.AssertNil(err)
t.Assert(count, TableSize)
})
// Slice where.
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).Count()
t.AssertNil(err)
@ -3692,19 +3708,20 @@ func Test_Model_IgnoreEmptySliceWhere(t *testing.T) {
t.Assert(count, 0)
})
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).IgnoreEmptySliceWhere().Where("id", g.Slice{}).Count()
count, err := db.Model(table).OmitEmptyWhere().Where("id", g.Slice{}).Count()
t.AssertNil(err)
t.Assert(count, TableSize)
})
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).Where("id", g.Slice{}).IgnoreEmptySliceWhere().Count()
count, err := db.Model(table).Where("id", g.Slice{}).OmitEmptyWhere().Count()
t.AssertNil(err)
t.Assert(count, TableSize)
})
// Struct Where.
gtest.C(t, func(t *gtest.T) {
type Input struct {
Id []int
Id []int
Name []string
}
count, err := db.Model(table).Where(Input{}).Count()
t.AssertNil(err)
@ -3712,16 +3729,18 @@ func Test_Model_IgnoreEmptySliceWhere(t *testing.T) {
})
gtest.C(t, func(t *gtest.T) {
type Input struct {
Id []int
Id []int
Name []string
}
count, err := db.Model(table).Where(Input{}).IgnoreEmptySliceWhere().Count()
count, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count()
t.AssertNil(err)
t.Assert(count, TableSize)
})
// Map Where.
gtest.C(t, func(t *gtest.T) {
count, err := db.Model(table).Where(g.Map{
"id": []int{},
"id": []int{},
"nickname": []string{},
}).Count()
t.AssertNil(err)
t.Assert(count, 0)
@ -3732,7 +3751,7 @@ func Test_Model_IgnoreEmptySliceWhere(t *testing.T) {
}
count, err := db.Model(table).Where(g.Map{
"id": []int{},
}).IgnoreEmptySliceWhere().Count()
}).OmitEmptyWhere().Count()
t.AssertNil(err)
t.Assert(count, TableSize)
})