diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index d82583538..16e8f480d 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -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. diff --git a/database/gdb/gdb_model_condition.go b/database/gdb/gdb_model_condition.go index 5c9e7f36f..43b898cb8 100644 --- a/database/gdb/gdb_model_condition.go +++ b/database/gdb/gdb_model_condition.go @@ -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 diff --git a/database/gdb/gdb_model_option.go b/database/gdb/gdb_model_option.go index 3f155038e..3311f6b25 100644 --- a/database/gdb/gdb_model_option.go +++ b/database/gdb/gdb_model_option.go @@ -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 diff --git a/database/gdb/gdb_z_mysql_model_test.go b/database/gdb/gdb_z_mysql_model_test.go index 42d308aaf..2cb30d64d 100644 --- a/database/gdb/gdb_z_mysql_model_test.go +++ b/database/gdb/gdb_z_mysql_model_test.go @@ -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) })