From 734aa5a6fef10b849beac6199695ebef630e6cf5 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 15 Apr 2020 12:56:41 +0800 Subject: [PATCH] improve create_at,update_at,delete_at feature for package gdb --- database/gdb/gdb_model_insert.go | 11 +- database/gdb/gdb_model_update.go | 5 +- database/gdb/gdb_unit_z_mysql_time_test.go | 150 +++++++++++++++++++++ util/gutil/gutil_map.go | 10 ++ 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 590d56863..67fc378b0 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -149,6 +149,7 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql. nowString = gtime.Now().String() fieldNameCreate = m.getSoftFieldNameCreate() fieldNameUpdate = m.getSoftFieldNameUpdate() + fieldNameDelete = m.getSoftFieldNameDelete() ) // Batch operation. if list, ok := m.data.(List); ok { @@ -159,10 +160,11 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql. // Automatic handling for creating/updating time. if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") { for k, v := range list { - if fieldNameCreate != "" && !gutil.MapContainsPossibleKey(v, fieldNameCreate) { + gutil.MapDelete(v, fieldNameCreate, fieldNameUpdate, fieldNameDelete) + if fieldNameCreate != "" { v[fieldNameCreate] = nowString } - if fieldNameUpdate != "" && !gutil.MapContainsPossibleKey(v, fieldNameUpdate) { + if fieldNameUpdate != "" { v[fieldNameUpdate] = nowString } list[k] = v @@ -180,10 +182,11 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql. if data, ok := m.data.(Map); ok { // Automatic handling for creating/updating time. if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") { - if fieldNameCreate != "" && !gutil.MapContainsPossibleKey(data, fieldNameCreate) { + gutil.MapDelete(data, fieldNameCreate, fieldNameUpdate, fieldNameDelete) + if fieldNameCreate != "" { data[fieldNameCreate] = nowString } - if fieldNameUpdate != "" && !gutil.MapContainsPossibleKey(data, fieldNameUpdate) { + if fieldNameUpdate != "" { data[fieldNameUpdate] = nowString } } diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go index 1d9118c44..e80995021 100644 --- a/database/gdb/gdb_model_update.go +++ b/database/gdb/gdb_model_update.go @@ -42,7 +42,9 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro } var ( updateData = m.data + fieldNameCreate = m.getSoftFieldNameCreate() fieldNameUpdate = m.getSoftFieldNameUpdate() + fieldNameDelete = m.getSoftFieldNameDelete() conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false) ) // Automatically update the record updating time. @@ -58,7 +60,8 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro switch refKind { case reflect.Map, reflect.Struct: dataMap := DataToMapDeep(m.data) - if fieldNameUpdate != "" && !gutil.MapContainsPossibleKey(dataMap, fieldNameUpdate) { + gutil.MapDelete(dataMap, fieldNameCreate, fieldNameUpdate, fieldNameDelete) + if fieldNameUpdate != "" { dataMap[fieldNameUpdate] = gtime.Now().String() } updateData = dataMap diff --git a/database/gdb/gdb_unit_z_mysql_time_test.go b/database/gdb/gdb_unit_z_mysql_time_test.go index f32070b0d..8475f6fd7 100644 --- a/database/gdb/gdb_unit_z_mysql_time_test.go +++ b/database/gdb/gdb_unit_z_mysql_time_test.go @@ -218,3 +218,153 @@ CREATE TABLE %s ( t.Assert(one.IsEmpty(), true) }) } + +func Test_CreateUpdateTime_Struct(t *testing.T) { + table := "time_test_table" + if _, err := db.Exec(fmt.Sprintf(` +CREATE TABLE %s ( + id int(11) NOT NULL, + name varchar(45) DEFAULT NULL, + create_at datetime DEFAULT NULL, + update_at datetime DEFAULT NULL, + delete_at datetime DEFAULT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + `, table)); err != nil { + gtest.Error(err) + } + defer dropTable(table) + + type Entity struct { + Id uint64 `orm:"id,primary" json:"id"` + Name string `orm:"name" json:"name"` + CreateAt *gtime.Time `orm:"create_at" json:"create_at"` + UpdateAt *gtime.Time `orm:"update_at" json:"update_at"` + DeleteAt *gtime.Time `orm:"delete_at" json:"delete_at"` + } + gtest.C(t, func(t *gtest.T) { + // Insert + dataInsert := &Entity{ + Id: 1, + Name: "name_1", + CreateAt: nil, + UpdateAt: nil, + DeleteAt: nil, + } + r, err := db.Table(table).Data(dataInsert).Insert() + t.Assert(err, nil) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + oneInsert, err := db.Table(table).FindOne(1) + t.Assert(err, nil) + t.Assert(oneInsert["id"].Int(), 1) + t.Assert(oneInsert["name"].String(), "name_1") + t.Assert(oneInsert["delete_at"].String(), "") + t.AssertGE(oneInsert["create_at"].GTime().Timestamp(), gtime.Timestamp()-2) + t.AssertGE(oneInsert["update_at"].GTime().Timestamp(), gtime.Timestamp()) + + time.Sleep(2 * time.Second) + + // Save + dataSave := &Entity{ + Id: 1, + Name: "name_10", + CreateAt: nil, + UpdateAt: nil, + DeleteAt: nil, + } + r, err = db.Table(table).Data(dataSave).Save() + t.Assert(err, nil) + n, _ = r.RowsAffected() + t.Assert(n, 2) + + oneSave, err := db.Table(table).FindOne(1) + t.Assert(err, nil) + t.Assert(oneSave["id"].Int(), 1) + t.Assert(oneSave["name"].String(), "name_10") + t.Assert(oneSave["delete_at"].String(), "") + t.Assert(oneSave["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp()) + t.AssertNE(oneSave["update_at"].GTime().Timestamp(), oneInsert["update_at"].GTime().Timestamp()) + t.AssertGE(oneSave["update_at"].GTime().Timestamp(), gtime.Now().Timestamp()-2) + + time.Sleep(2 * time.Second) + + // Update + dataUpdate := &Entity{ + Id: 1, + Name: "name_1000", + CreateAt: nil, + UpdateAt: nil, + DeleteAt: nil, + } + r, err = db.Table(table).Data(dataUpdate).WherePri(1).Update() + t.Assert(err, nil) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + oneUpdate, err := db.Table(table).FindOne(1) + t.Assert(err, nil) + t.Assert(oneUpdate["id"].Int(), 1) + t.Assert(oneUpdate["name"].String(), "name_1000") + t.Assert(oneUpdate["delete_at"].String(), "") + t.Assert(oneUpdate["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp()) + t.AssertGE(oneUpdate["update_at"].GTime().Timestamp(), gtime.Now().Timestamp()-2) + + // Replace + dataReplace := &Entity{ + Id: 1, + Name: "name_100", + CreateAt: nil, + UpdateAt: nil, + DeleteAt: nil, + } + r, err = db.Table(table).Data(dataReplace).Replace() + t.Assert(err, nil) + n, _ = r.RowsAffected() + t.Assert(n, 2) + + oneReplace, err := db.Table(table).FindOne(1) + t.Assert(err, nil) + t.Assert(oneReplace["id"].Int(), 1) + t.Assert(oneReplace["name"].String(), "name_100") + t.Assert(oneReplace["delete_at"].String(), "") + t.AssertGE(oneReplace["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp()) + t.AssertGE(oneReplace["update_at"].GTime().Timestamp(), oneInsert["update_at"].GTime().Timestamp()) + + time.Sleep(2 * time.Second) + + // Delete + r, err = db.Table(table).Delete("id", 1) + t.Assert(err, nil) + n, _ = r.RowsAffected() + t.Assert(n, 1) + // Delete Select + one4, err := db.Table(table).FindOne(1) + t.Assert(err, nil) + t.Assert(len(one4), 0) + one5, err := db.Table(table).Unscoped().FindOne(1) + t.Assert(err, nil) + t.Assert(one5["id"].Int(), 1) + t.AssertGE(one5["delete_at"].GTime().Timestamp(), gtime.Now().Timestamp()-2) + // Delete Count + i, err := db.Table(table).FindCount() + t.Assert(err, nil) + t.Assert(i, 0) + i, err = db.Table(table).Unscoped().FindCount() + t.Assert(err, nil) + t.Assert(i, 1) + + // Delete Unscoped + r, err = db.Table(table).Unscoped().Delete("id", 1) + t.Assert(err, nil) + n, _ = r.RowsAffected() + t.Assert(n, 1) + one6, err := db.Table(table).Unscoped().FindOne(1) + t.Assert(err, nil) + t.Assert(len(one6), 0) + i, err = db.Table(table).Unscoped().FindCount() + t.Assert(err, nil) + t.Assert(i, 0) + }) +} diff --git a/util/gutil/gutil_map.go b/util/gutil/gutil_map.go index ff00b5cf8..bc014dc1b 100644 --- a/util/gutil/gutil_map.go +++ b/util/gutil/gutil_map.go @@ -26,6 +26,16 @@ func MapContains(data map[string]interface{}, key string) (ok bool) { return } +// MapDelete deletes all from map . +func MapDelete(data map[string]interface{}, key ...string) { + if data == nil { + return + } + for _, v := range key { + delete(data, v) + } +} + // MapMerge merges all map from to map . func MapMerge(dst map[string]interface{}, src ...map[string]interface{}) { if dst == nil {