diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index d55885f5e..386047350 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -60,6 +60,7 @@ const ( OrmTagForWith = "with" OrmTagForWithWhere = "where" OrmTagForWithOrder = "order" + OrmTagForDto = "dto" ) var ( @@ -70,9 +71,25 @@ var ( structTagPriority = append([]string{OrmTagForStruct}, gconv.StructTagPriority...) ) -// isForDaoModel checks and returns whether given type is for dao model. -func isForDaoModel(t reflect.Type) bool { - return gstr.HasSuffix(t.String(), modelForDaoSuffix) +// isDtoStruct checks and returns whether given type is a DTO struct. +func isDtoStruct(object interface{}) bool { + // It checks by struct name like "XxxForDao", to be compatible with old version. + // TODO remove this compatible codes in future. + reflectType := reflect.TypeOf(object) + if gstr.HasSuffix(reflectType.String(), modelForDaoSuffix) { + return true + } + // It checks by struct meta for DTO struct in version. + if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() { + match, _ := gregex.MatchString( + fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForDto), + ormTag.String(), + ) + if len(match) > 1 { + return gconv.Bool(match[1]) + } + } + return false } // getTableNameFromOrmTag retrieves and returns the table name from struct object. @@ -424,7 +441,7 @@ func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newAr case reflect.Struct: // If the `where` parameter is defined like `xxxForDao`, it then adds `OmitNil` option for this condition, // which will filter all nil parameters in `where`. - if isForDaoModel(reflect.TypeOf(in.Where)) { + if isDtoStruct(in.Where) { in.OmitNil = true } // If `where` struct implements iIterator interface, diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 0333c2445..7c8679e52 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -73,10 +73,10 @@ func (m *Model) Data(data ...interface{}) *Model { switch reflectInfo.OriginKind { case reflect.Slice, reflect.Array: if reflectInfo.OriginValue.Len() > 0 { - // If the `data` parameter is defined like `xxxForDao`, + // If the `data` parameter is a DTO struct, // it then adds `OmitNilData` option for this condition, // which will filter all nil parameters in `data`. - if isForDaoModel(reflectInfo.OriginValue.Index(0).Elem().Type()) { + if isDtoStruct(reflectInfo.OriginValue.Index(0).Interface()) { model = model.OmitNilData() model.option |= optionOmitNilDataInternal } @@ -88,10 +88,10 @@ func (m *Model) Data(data ...interface{}) *Model { model.data = list case reflect.Struct: - // If the `data` parameter is defined like `xxxForDao`, + // If the `data` parameter is a DTO struct, // it then adds `OmitNilData` option for this condition, // which will filter all nil parameters in `data`. - if isForDaoModel(reflect.TypeOf(value)) { + if isDtoStruct(value) { model = model.OmitNilData() } if v, ok := data[0].(iInterfaces); ok { diff --git a/database/gdb/gdb_z_mysql_feature_model_for_dao_test.go b/database/gdb/gdb_z_mysql_feature_model_dto_test.go similarity index 52% rename from database/gdb/gdb_z_mysql_feature_model_for_dao_test.go rename to database/gdb/gdb_z_mysql_feature_model_dto_test.go index 5d4dc7934..e722595fd 100644 --- a/database/gdb/gdb_z_mysql_feature_model_for_dao_test.go +++ b/database/gdb/gdb_z_mysql_feature_model_dto_test.go @@ -13,6 +13,144 @@ import ( "github.com/gogf/gf/v2/test/gtest" ) +func Test_Model_Insert_Data_DTO(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + g.Meta `orm:"dto:true"` + Id interface{} + Passport interface{} + Password interface{} + Nickname interface{} + CreateTime interface{} + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + } + result, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, 1) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one[`id`], `1`) + t.Assert(one[`passport`], `user_1`) + t.Assert(one[`password`], `pass_1`) + t.Assert(one[`nickname`], ``) + t.Assert(one[`create_time`], ``) + }) +} + +func Test_Model_Insert_Data_LIst_DTO(t *testing.T) { + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + g.Meta `orm:"dto:true"` + Id interface{} + Passport interface{} + Password interface{} + Nickname interface{} + CreateTime interface{} + } + data := g.Slice{ + User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + }, + User{ + Id: 2, + Passport: "user_2", + Password: "pass_2", + }, + } + result, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, 2) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one[`id`], `1`) + t.Assert(one[`passport`], `user_1`) + t.Assert(one[`password`], `pass_1`) + t.Assert(one[`nickname`], ``) + t.Assert(one[`create_time`], ``) + + one, err = db.Model(table).WherePri(2).One() + t.AssertNil(err) + t.Assert(one[`id`], `2`) + t.Assert(one[`passport`], `user_2`) + t.Assert(one[`password`], `pass_2`) + t.Assert(one[`nickname`], ``) + t.Assert(one[`create_time`], ``) + }) +} + +func Test_Model_Update_Data_DTO(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + g.Meta `orm:"dto:true"` + Id interface{} + Passport interface{} + Password interface{} + Nickname interface{} + CreateTime interface{} + } + data := User{ + Id: 1, + Passport: "user_100", + Password: "pass_100", + } + _, err := db.Model(table).Data(data).WherePri(1).Update() + t.AssertNil(err) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one[`id`], `1`) + t.Assert(one[`passport`], `user_100`) + t.Assert(one[`password`], `pass_100`) + t.Assert(one[`nickname`], `name_1`) + }) +} + +func Test_Model_Where_DTO(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + g.Meta `orm:"dto:true"` + Id interface{} + Passport interface{} + Password interface{} + Nickname interface{} + CreateTime interface{} + } + where := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + } + one, err := db.Model(table).Where(where).One() + t.AssertNil(err) + t.Assert(one[`id`], `1`) + t.Assert(one[`passport`], `user_1`) + t.Assert(one[`password`], `pass_1`) + t.Assert(one[`nickname`], `name_1`) + }) +} + func Test_Model_Insert_Data_ForDao(t *testing.T) { table := createTable() defer dropTable(table)