From 3932e0b15f85c468c2fee0dae5bb84eea3791b28 Mon Sep 17 00:00:00 2001 From: John Guo Date: Tue, 28 Dec 2021 17:15:01 +0800 Subject: [PATCH] add OmitEmpty support for WhereIn --- database/gdb/gdb_func.go | 51 ++++++++-- database/gdb/gdb_model.go | 21 ++-- database/gdb/gdb_model_select.go | 61 ++++++------ database/gdb/gdb_model_where.go | 84 ++++++++++------ database/gdb/gdb_model_where_prefix.go | 5 +- database/gdb/gdb_model_whereor.go | 27 +++-- database/gdb/gdb_model_whereor_prefix.go | 5 +- database/gdb/gdb_z_mysql_model_test.go | 11 +++ internal/empty/empty.go | 120 ----------------------- 9 files changed, 174 insertions(+), 211 deletions(-) diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index c48f5d52d..bc35b8009 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -333,13 +333,36 @@ func formatSql(sql string, args []interface{}) (newSql string, newArgs []interfa } type formatWhereHolderInput struct { - Where interface{} - Args []interface{} + ModelWhereHolder OmitNil bool OmitEmpty bool Schema string Table string // Table is used for fields mapping and filtering internally. - Prefix string // Field prefix, eg: "user.", "order.". +} + +func isKeyValueCanBeOmitEmpty(omitEmpty bool, whereType string, key, value interface{}) bool { + if !omitEmpty { + return false + } + // 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().Where("name", "").All() -> SELECT xxx FROM xxx + // OmitEmpty().Where("1").All() -> SELECT xxx FROM xxx WHERE 1 + switch whereType { + case whereHolderTypeNoArgs: + return false + + case whereHolderTypeIn: + return gutil.IsEmpty(value) + + default: + if gstr.Count(gconv.String(key), "?") == 0 && gutil.IsEmpty(value) { + return true + } + } + return false } // formatWhereHolder formats where statement and its arguments for `Where` and `Having` statements. @@ -369,6 +392,7 @@ func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newAr Key: key, Value: value, Prefix: in.Prefix, + Type: in.Type, }) } @@ -401,6 +425,7 @@ func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newAr Value: value, OmitEmpty: in.OmitEmpty, Prefix: in.Prefix, + Type: in.Type, }) return true }) @@ -447,11 +472,22 @@ func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newAr Value: foundValue, OmitEmpty: in.OmitEmpty, Prefix: in.Prefix, + Type: in.Type, }) } } default: + // Where filter. + var omitEmptyCheckValue interface{} + if len(in.Args) == 1 { + omitEmptyCheckValue = in.Args[0] + } else { + omitEmptyCheckValue = in.Args + } + if isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, in.Where, omitEmptyCheckValue) { + return + } // Usually a string. whereStr := gconv.String(in.Where) // Is `whereStr` a field name which composed as a key-value condition? @@ -467,6 +503,7 @@ func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newAr Value: in.Args[0], OmitEmpty: in.OmitEmpty, Prefix: in.Prefix, + Type: in.Type, }) in.Args = in.Args[:0] break @@ -578,6 +615,7 @@ type formatWhereKeyValueInput struct { Args []interface{} // Args is the full arguments of current operation. Key string // The field name, eg: "id", "name", etc. Value interface{} // The field value, can be any types. + Type string // The value in Where type. OmitEmpty bool // Ignores current condition key if `value` is empty. Prefix string // Field prefix, eg: "user", "order", etc. } @@ -588,12 +626,7 @@ func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) { 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) { + if isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, quotedKey, in.Value) { return in.Args } if in.Prefix != "" && !gstr.Contains(quotedKey, ".") { diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go index 172176029..29fabe314 100644 --- a/database/gdb/gdb_model.go +++ b/database/gdb/gdb_model.go @@ -59,6 +59,7 @@ type ChunkHandler func(result Result, err error) bool // ModelWhereHolder is the holder for where condition preparing. type ModelWhereHolder struct { + Type string // Type of this holder. Operator int // Operator for this holder. Where interface{} // Where parameter, which can commonly be type of string/map/struct. Args []interface{} // Arguments for where parameter. @@ -68,10 +69,13 @@ type ModelWhereHolder struct { const ( linkTypeMaster = 1 linkTypeSlave = 2 + defaultFields = "*" whereHolderOperatorWhere = 1 whereHolderOperatorAnd = 2 whereHolderOperatorOr = 3 - defaultFields = "*" + whereHolderTypeDefault = "Default" + whereHolderTypeNoArgs = "NoArgs" + whereHolderTypeIn = "In" ) // Model creates and returns a new ORM model from given schema. @@ -95,13 +99,16 @@ func (c *Core) Model(tableNameQueryOrStruct ...interface{}) *Model { if len(tableNameQueryOrStruct) > 1 { conditionStr := gconv.String(tableNameQueryOrStruct[0]) if gstr.Contains(conditionStr, "?") { + whereHolder := ModelWhereHolder{ + Where: conditionStr, + Args: tableNameQueryOrStruct[1:], + } tableStr, extraArgs = formatWhereHolder(c.db, formatWhereHolderInput{ - Where: conditionStr, - Args: tableNameQueryOrStruct[1:], - OmitNil: false, - OmitEmpty: false, - Schema: "", - Table: "", + ModelWhereHolder: whereHolder, + OmitNil: false, + OmitEmpty: false, + Schema: "", + Table: "", }) } } diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go index 0f4d6ac91..1ad620aeb 100644 --- a/database/gdb/gdb_model_select.go +++ b/database/gdb/gdb_model_select.go @@ -604,23 +604,21 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh tableForMappingAndFiltering = m.tables ) if len(m.whereHolder) > 0 { - for _, v := range m.whereHolder { + for _, holder := range m.whereHolder { tableForMappingAndFiltering = m.tables - if v.Prefix == "" { - v.Prefix = autoPrefix + if holder.Prefix == "" { + holder.Prefix = autoPrefix } - switch v.Operator { + switch holder.Operator { case whereHolderOperatorWhere: if conditionWhere == "" { newWhere, newArgs := formatWhereHolder(m.db, formatWhereHolderInput{ - Where: v.Where, - Args: v.Args, - OmitNil: m.option&optionOmitNilWhere > 0, - OmitEmpty: m.option&optionOmitEmptyWhere > 0, - Schema: m.schema, - Table: tableForMappingAndFiltering, - Prefix: v.Prefix, + ModelWhereHolder: holder, + OmitNil: m.option&optionOmitNilWhere > 0, + OmitEmpty: m.option&optionOmitEmptyWhere > 0, + Schema: m.schema, + Table: tableForMappingAndFiltering, }) if len(newWhere) > 0 { conditionWhere = newWhere @@ -632,13 +630,11 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh case whereHolderOperatorAnd: newWhere, newArgs := formatWhereHolder(m.db, formatWhereHolderInput{ - Where: v.Where, - Args: v.Args, - OmitNil: m.option&optionOmitNilWhere > 0, - OmitEmpty: m.option&optionOmitEmptyWhere > 0, - Schema: m.schema, - Table: tableForMappingAndFiltering, - Prefix: v.Prefix, + ModelWhereHolder: holder, + OmitNil: m.option&optionOmitNilWhere > 0, + OmitEmpty: m.option&optionOmitEmptyWhere > 0, + Schema: m.schema, + Table: tableForMappingAndFiltering, }) if len(newWhere) > 0 { if len(conditionWhere) == 0 { @@ -653,13 +649,11 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh case whereHolderOperatorOr: newWhere, newArgs := formatWhereHolder(m.db, formatWhereHolderInput{ - Where: v.Where, - Args: v.Args, - OmitNil: m.option&optionOmitNilWhere > 0, - OmitEmpty: m.option&optionOmitEmptyWhere > 0, - Schema: m.schema, - Table: tableForMappingAndFiltering, - Prefix: v.Prefix, + ModelWhereHolder: holder, + OmitNil: m.option&optionOmitNilWhere > 0, + OmitEmpty: m.option&optionOmitEmptyWhere > 0, + Schema: m.schema, + Table: tableForMappingAndFiltering, }) if len(newWhere) > 0 { if len(conditionWhere) == 0 { @@ -700,14 +694,17 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh } // HAVING. if len(m.having) > 0 { + havingHolder := ModelWhereHolder{ + Where: m.having[0], + Args: gconv.Interfaces(m.having[1]), + Prefix: autoPrefix, + } havingStr, havingArgs := formatWhereHolder(m.db, formatWhereHolderInput{ - 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, - Prefix: autoPrefix, + ModelWhereHolder: havingHolder, + 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_where.go b/database/gdb/gdb_model_where.go index 3a123c71e..0b168eb64 100644 --- a/database/gdb/gdb_model_where.go +++ b/database/gdb/gdb_model_where.go @@ -12,6 +12,41 @@ import ( "github.com/gogf/gf/v2/text/gstr" ) +// doWhereType sets the condition statement for the model. The parameter `where` can be type of +// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times, +// multiple conditions will be joined into where statement using "AND". +func (m *Model) doWhereType(t string, where interface{}, args ...interface{}) *Model { + model := m.getModel() + if model.whereHolder == nil { + model.whereHolder = make([]ModelWhereHolder, 0) + } + if t == "" { + if len(args) == 0 { + t = whereHolderTypeNoArgs + } else { + t = whereHolderTypeDefault + } + } + model.whereHolder = append(model.whereHolder, ModelWhereHolder{ + Type: t, + Operator: whereHolderOperatorWhere, + Where: where, + Args: args, + }) + return model +} + +// doWherefType builds condition string using fmt.Sprintf and arguments. +// Note that if the number of `args` is more than the placeholder in `format`, +// the extra `args` will be used as the where condition arguments of the Model. +func (m *Model) doWherefType(t string, format string, args ...interface{}) *Model { + var ( + placeHolderCount = gstr.Count(format, "?") + conditionStr = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...) + ) + return m.doWhereType(t, conditionStr, args[len(args)-placeHolderCount:]...) +} + // Where sets the condition statement for the model. The parameter `where` can be type of // string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times, // multiple conditions will be joined into where statement using "AND". @@ -24,16 +59,17 @@ import ( // Where("age IN(?,?)", 18, 50) // Where(User{ Id : 1, UserName : "john"}). func (m *Model) Where(where interface{}, args ...interface{}) *Model { - model := m.getModel() - if model.whereHolder == nil { - model.whereHolder = make([]ModelWhereHolder, 0) - } - model.whereHolder = append(model.whereHolder, ModelWhereHolder{ - Operator: whereHolderOperatorWhere, - Where: where, - Args: args, - }) - return model + return m.doWhereType(``, where, args...) +} + +// Wheref builds condition string using fmt.Sprintf and arguments. +// Note that if the number of `args` is more than the placeholder in `format`, +// the extra `args` will be used as the where condition arguments of the Model. +// Eg: +// Wheref(`amount WHERE `amount`<100 and status='paid' +// Wheref(`amount<%d and status=%s`, 100, "paid") => WHERE `amount`<100 and status='paid' +func (m *Model) Wheref(format string, args ...interface{}) *Model { + return m.doWherefType(``, format, args...) } // WherePri does the same logic as Model.Where except that if the parameter `where` @@ -49,38 +85,24 @@ func (m *Model) WherePri(where interface{}, args ...interface{}) *Model { return m.Where(newWhere[0], newWhere[1:]...) } -// Wheref builds condition string using fmt.Sprintf and arguments. -// Note that if the number of `args` is more than the placeholder in `format`, -// the extra `args` will be used as the where condition arguments of the Model. -// Eg: -// Wheref(`amount WHERE `amount`<100 and status='paid' -// Wheref(`amount<%d and status=%s`, 100, "paid") => WHERE `amount`<100 and status='paid' -func (m *Model) Wheref(format string, args ...interface{}) *Model { - var ( - placeHolderCount = gstr.Count(format, "?") - conditionStr = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...) - ) - return m.Where(conditionStr, args[len(args)-placeHolderCount:]...) -} - // WhereLT builds `column < value` statement. func (m *Model) WhereLT(column string, value interface{}) *Model { - return m.Wheref(`%s < ?`, column, value) + return m.Wheref(`%s < ?`, m.QuoteWord(column), value) } // WhereLTE builds `column <= value` statement. func (m *Model) WhereLTE(column string, value interface{}) *Model { - return m.Wheref(`%s <= ?`, column, value) + return m.Wheref(`%s <= ?`, m.QuoteWord(column), value) } // WhereGT builds `column > value` statement. func (m *Model) WhereGT(column string, value interface{}) *Model { - return m.Wheref(`%s > ?`, column, value) + return m.Wheref(`%s > ?`, m.QuoteWord(column), value) } // WhereGTE builds `column >= value` statement. func (m *Model) WhereGTE(column string, value interface{}) *Model { - return m.Wheref(`%s >= ?`, column, value) + return m.Wheref(`%s >= ?`, m.QuoteWord(column), value) } // WhereBetween builds `column BETWEEN min AND max` statement. @@ -89,13 +111,13 @@ func (m *Model) WhereBetween(column string, min, max interface{}) *Model { } // WhereLike builds `column LIKE like` statement. -func (m *Model) WhereLike(column string, like interface{}) *Model { +func (m *Model) WhereLike(column string, like string) *Model { return m.Wheref(`%s LIKE ?`, m.QuoteWord(column), like) } // WhereIn builds `column IN (in)` statement. func (m *Model) WhereIn(column string, in interface{}) *Model { - return m.Wheref(`%s IN (?)`, m.QuoteWord(column), in) + return m.doWherefType(whereHolderTypeIn, `%s IN (?)`, m.QuoteWord(column), in) } // WhereNull builds `columns[0] IS NULL AND columns[1] IS NULL ...` statement. @@ -124,7 +146,7 @@ func (m *Model) WhereNot(column string, value interface{}) *Model { // WhereNotIn builds `column NOT IN (in)` statement. func (m *Model) WhereNotIn(column string, in interface{}) *Model { - return m.Wheref(`%s NOT IN (?)`, m.QuoteWord(column), in) + return m.doWherefType(whereHolderTypeIn, `%s NOT IN (?)`, m.QuoteWord(column), in) } // WhereNotNull builds `columns[0] IS NOT NULL AND columns[1] IS NOT NULL ...` statement. diff --git a/database/gdb/gdb_model_where_prefix.go b/database/gdb/gdb_model_where_prefix.go index a8cc761db..382a0b1a7 100644 --- a/database/gdb/gdb_model_where_prefix.go +++ b/database/gdb/gdb_model_where_prefix.go @@ -16,6 +16,7 @@ func (m *Model) WherePrefix(prefix string, where interface{}, args ...interface{ model.whereHolder = make([]ModelWhereHolder, 0) } model.whereHolder = append(model.whereHolder, ModelWhereHolder{ + Type: whereHolderTypeDefault, Operator: whereHolderOperatorWhere, Where: where, Args: args, @@ -56,7 +57,7 @@ func (m *Model) WherePrefixLike(prefix string, column string, like interface{}) // WherePrefixIn builds `prefix.column IN (in)` statement. func (m *Model) WherePrefixIn(prefix string, column string, in interface{}) *Model { - return m.Wheref(`%s.%s IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) + return m.doWherefType(whereHolderTypeIn, `%s.%s IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) } // WherePrefixNull builds `prefix.columns[0] IS NULL AND prefix.columns[1] IS NULL ...` statement. @@ -85,7 +86,7 @@ func (m *Model) WherePrefixNot(prefix string, column string, value interface{}) // WherePrefixNotIn builds `prefix.column NOT IN (in)` statement. func (m *Model) WherePrefixNotIn(prefix string, column string, in interface{}) *Model { - return m.Wheref(`%s.%s NOT IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) + return m.doWherefType(whereHolderTypeIn, `%s.%s NOT IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) } // WherePrefixNotNull builds `prefix.columns[0] IS NOT NULL AND prefix.columns[1] IS NOT NULL ...` statement. diff --git a/database/gdb/gdb_model_whereor.go b/database/gdb/gdb_model_whereor.go index 3b0016f45..3d288459e 100644 --- a/database/gdb/gdb_model_whereor.go +++ b/database/gdb/gdb_model_whereor.go @@ -13,12 +13,13 @@ import ( ) // WhereOr adds "OR" condition to the where statement. -func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model { +func (m *Model) doWhereOrType(t string, where interface{}, args ...interface{}) *Model { model := m.getModel() if model.whereHolder == nil { model.whereHolder = make([]ModelWhereHolder, 0) } model.whereHolder = append(model.whereHolder, ModelWhereHolder{ + Type: t, Operator: whereHolderOperatorOr, Where: where, Args: args, @@ -27,15 +28,25 @@ func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model { } // WhereOrf builds `OR` condition string using fmt.Sprintf and arguments. -// Eg: -// WhereOrf(`amount WHERE xxx OR `amount`<100 and status='paid' -// WhereOrf(`amount<%d and status=%s`, 100, "paid") => WHERE xxx OR `amount`<100 and status='paid' -func (m *Model) WhereOrf(format string, args ...interface{}) *Model { +func (m *Model) doWhereOrfType(t string, format string, args ...interface{}) *Model { var ( placeHolderCount = gstr.Count(format, "?") conditionStr = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...) ) - return m.WhereOr(conditionStr, args[len(args)-placeHolderCount:]...) + return m.doWhereOrType(t, conditionStr, args[len(args)-placeHolderCount:]...) +} + +// WhereOr adds "OR" condition to the where statement. +func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model { + return m.doWhereOrType(``, where, args...) +} + +// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments. +// Eg: +// WhereOrf(`amount WHERE xxx OR `amount`<100 and status='paid' +// WhereOrf(`amount<%d and status=%s`, 100, "paid") => WHERE xxx OR `amount`<100 and status='paid' +func (m *Model) WhereOrf(format string, args ...interface{}) *Model { + return m.doWhereOrfType(``, format, args...) } // WhereOrLT builds `column < value` statement in `OR` conditions.. @@ -70,7 +81,7 @@ func (m *Model) WhereOrLike(column string, like interface{}) *Model { // WhereOrIn builds `column IN (in)` statement in `OR` conditions. func (m *Model) WhereOrIn(column string, in interface{}) *Model { - return m.WhereOrf(`%s IN (?)`, m.QuoteWord(column), in) + return m.doWhereOrfType(whereHolderTypeIn, `%s IN (?)`, m.QuoteWord(column), in) } // WhereOrNull builds `columns[0] IS NULL OR columns[1] IS NULL ...` statement in `OR` conditions. @@ -94,7 +105,7 @@ func (m *Model) WhereOrNotLike(column string, like interface{}) *Model { // WhereOrNotIn builds `column NOT IN (in)` statement. func (m *Model) WhereOrNotIn(column string, in interface{}) *Model { - return m.WhereOrf(`%s NOT IN (?)`, m.QuoteWord(column), in) + return m.doWhereOrfType(whereHolderTypeIn, `%s NOT IN (?)`, m.QuoteWord(column), in) } // WhereOrNotNull builds `columns[0] IS NOT NULL OR columns[1] IS NOT NULL ...` statement in `OR` conditions. diff --git a/database/gdb/gdb_model_whereor_prefix.go b/database/gdb/gdb_model_whereor_prefix.go index 74189a807..7230895cb 100644 --- a/database/gdb/gdb_model_whereor_prefix.go +++ b/database/gdb/gdb_model_whereor_prefix.go @@ -16,6 +16,7 @@ func (m *Model) WhereOrPrefix(prefix string, where interface{}, args ...interfac model.whereHolder = make([]ModelWhereHolder, 0) } model.whereHolder = append(model.whereHolder, ModelWhereHolder{ + Type: whereHolderTypeDefault, Operator: whereHolderOperatorOr, Where: where, Args: args, @@ -56,7 +57,7 @@ func (m *Model) WhereOrPrefixLike(prefix string, column string, like interface{} // WhereOrPrefixIn builds `prefix.column IN (in)` statement in `OR` conditions. func (m *Model) WhereOrPrefixIn(prefix string, column string, in interface{}) *Model { - return m.WhereOrf(`%s.%s IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) + return m.doWhereOrfType(whereHolderTypeIn, `%s.%s IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) } // WhereOrPrefixNull builds `prefix.columns[0] IS NULL OR prefix.columns[1] IS NULL ...` statement in `OR` conditions. @@ -80,7 +81,7 @@ func (m *Model) WhereOrPrefixNotLike(prefix string, column string, like interfac // WhereOrPrefixNotIn builds `prefix.column NOT IN (in)` statement. func (m *Model) WhereOrPrefixNotIn(prefix string, column string, in interface{}) *Model { - return m.WhereOrf(`%s.%s NOT IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) + return m.doWhereOrfType(whereHolderTypeIn, `%s.%s NOT IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in) } // WhereOrPrefixNotNull builds `prefix.columns[0] IS NOT NULL OR prefix.columns[1] IS NOT NULL ...` statement in `OR` conditions. diff --git a/database/gdb/gdb_z_mysql_model_test.go b/database/gdb/gdb_z_mysql_model_test.go index 66482520e..9693d4b60 100644 --- a/database/gdb/gdb_z_mysql_model_test.go +++ b/database/gdb/gdb_z_mysql_model_test.go @@ -2084,6 +2084,7 @@ func Test_Model_Option_Where(t *testing.T) { n, _ := r.RowsAffected() t.Assert(n, TableSize) }) + return gtest.C(t, func(t *gtest.T) { table := createInitTable() defer dropTable(table) @@ -3126,6 +3127,16 @@ func Test_Model_WhereIn(t *testing.T) { t.Assert(result[0]["id"], 3) t.Assert(result[1]["id"], 4) }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereIn("id", g.Slice{}).OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).OmitEmptyWhere().WhereIn("id", g.Slice{}).OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + }) } func Test_Model_WhereNotIn(t *testing.T) { diff --git a/internal/empty/empty.go b/internal/empty/empty.go index 7ee877b51..88b53c814 100644 --- a/internal/empty/empty.go +++ b/internal/empty/empty.go @@ -178,126 +178,6 @@ func IsEmpty(value interface{}) bool { return false } -// IsEmptyLength checks whether given `value` is empty length. -// It returns true if `value` is in: nil, "", len(slice/map/chan) == 0, -// or else it returns false. -//func IsEmptyLength(value interface{}) bool { -// if value == nil { -// return true -// } -// // It firstly checks the variable as common types using assertion to enhance the performance, -// // and then using reflection. -// switch value := value.(type) { -// case -// int, -// int8, -// int16, -// int32, -// int64, -// uint, -// uint8, -// uint16, -// uint32, -// uint64, -// float32, -// float64, -// bool: -// return false -// case string: -// return value == "" -// case []byte: -// return len(value) == 0 -// case []rune: -// return len(value) == 0 -// case []int: -// return len(value) == 0 -// case []string: -// return len(value) == 0 -// case []float32: -// return len(value) == 0 -// case []float64: -// return len(value) == 0 -// case map[string]interface{}: -// return len(value) == 0 -// default: -// // ========================= -// // Common interfaces checks. -// // ========================= -// if f, ok := value.(iTime); ok { -// if f == nil { -// return true -// } -// return f.IsZero() -// } -// if f, ok := value.(iString); ok { -// if f == nil { -// return true -// } -// return f.String() == "" -// } -// if f, ok := value.(iInterfaces); ok { -// if f == nil { -// return true -// } -// return len(f.Interfaces()) == 0 -// } -// if f, ok := value.(iMapStrAny); ok { -// if f == nil { -// return true -// } -// return len(f.MapStrAny()) == 0 -// } -// // Finally using reflect. -// var rv reflect.Value -// if v, ok := value.(reflect.Value); ok { -// rv = v -// } else { -// rv = reflect.ValueOf(value) -// } -// -// switch rv.Kind() { -// case -// reflect.Int, -// reflect.Int8, -// reflect.Int16, -// reflect.Int32, -// reflect.Int64, -// reflect.Uint, -// reflect.Uint8, -// reflect.Uint16, -// reflect.Uint32, -// reflect.Uint64, -// reflect.Uintptr, -// reflect.Float32, -// reflect.Float64, -// reflect.Bool: -// return false -// case reflect.String: -// return rv.Len() == 0 -// case reflect.Struct: -// for i := 0; i < rv.NumField(); i++ { -// if !IsEmpty(rv) { -// return false -// } -// } -// return true -// case reflect.Chan, -// reflect.Map, -// reflect.Slice, -// reflect.Array: -// return rv.Len() == 0 -// case reflect.Func, -// reflect.Ptr, -// reflect.Interface, -// reflect.UnsafePointer: -// if rv.IsNil() { -// return true -// } -// } -// } -// return false -//} - // IsNil checks whether given `value` is nil, especially for interface{} type value. // Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pinter // that also points to a pointer. It returns nil if the source is nil when `traceSource` is true.