From 561a541fa1844d1620220cd07771e61f5224ad98 Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 20 Oct 2020 21:01:39 +0800 Subject: [PATCH] add custom CreatedAt/UpdatedAt/DeletedAt filed name configuration for package gdb --- database/gdb/gdb.go | 3 ++ database/gdb/gdb_core.go | 24 ++++++++- database/gdb/gdb_core_config.go | 8 +++ database/gdb/gdb_model_delete.go | 2 +- database/gdb/gdb_model_insert.go | 6 +-- ...b_model_time.go => gdb_model_soft_time.go} | 49 +++++++++++++------ database/gdb/gdb_model_update.go | 6 +-- database/gdb/gdb_z_mysql_internal_test.go | 6 +-- 8 files changed, 76 insertions(+), 28 deletions(-) rename database/gdb/{gdb_model_time.go => gdb_model_soft_time.go} (73%) diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index 972dfcfda..841ef3a58 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -128,6 +128,7 @@ type DB interface { GetDryRun() bool SetLogger(logger *glog.Logger) GetLogger() *glog.Logger + GetConfig() *ConfigNode SetMaxIdleConnCount(n int) SetMaxOpenConnCount(n int) SetMaxConnLifetime(d time.Duration) @@ -171,6 +172,7 @@ type Core struct { dryrun *gtype.Bool // Dry run. prefix string // Table prefix. logger *glog.Logger // Logger. + config *ConfigNode // Current config node. maxIdleConnCount int // Max idle connection count. maxOpenConnCount int // Max open connection count. maxConnLifetime time.Duration // Max TTL for a connection. @@ -304,6 +306,7 @@ func New(group ...string) (db DB, err error) { dryrun: gtype.NewBool(), logger: glog.New(), prefix: node.Prefix, + config: node, maxIdleConnCount: gDEFAULT_CONN_MAX_IDLE_COUNT, maxConnLifetime: gDEFAULT_CONN_MAX_LIFE_TIME, // Default max connection life time if user does not configure. } diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 05d1fbfaf..af89f54d3 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -11,6 +11,7 @@ import ( "database/sql" "errors" "fmt" + "github.com/gogf/gf/text/gstr" "reflect" "strings" @@ -455,7 +456,7 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b for k, _ := range dataMap { // If it's SAVE operation, // do not automatically update the creating time. - if utils.EqualFoldWithoutChars(k, gSOFT_FIELD_NAME_CREATE) { + if c.isSoftCreatedFiledName(k) { continue } if len(updateStr) > 0 { @@ -602,7 +603,7 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i for _, k := range keys { // If it's SAVE operation, // do not automatically update the creating time. - if utils.EqualFoldWithoutChars(k, gSOFT_FIELD_NAME_CREATE) { + if c.isSoftCreatedFiledName(k) { continue } if len(updateStr) > 0 { @@ -829,3 +830,22 @@ func (c *Core) HasTable(name string) (bool, error) { } return false, nil } + +// isSoftCreatedFiledName checks and returns whether given filed name is an automatic-filled created time. +func (c *Core) isSoftCreatedFiledName(fieldName string) bool { + if fieldName == "" { + return false + } + if config := c.DB.GetConfig(); config.CreatedAt != "" { + if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) { + return true + } + return gstr.InArray(append([]string{config.CreatedAt}, createdFiledNames...), fieldName) + } + for _, v := range createdFiledNames { + if utils.EqualFoldWithoutChars(fieldName, v) { + return true + } + } + return false +} diff --git a/database/gdb/gdb_core_config.go b/database/gdb/gdb_core_config.go index 0a245b9d9..00e941449 100644 --- a/database/gdb/gdb_core_config.go +++ b/database/gdb/gdb_core_config.go @@ -39,6 +39,9 @@ type ConfigNode struct { DryRun bool // (Optional) Dry run, which does SELECT but no INSERT/UPDATE/DELETE statements. Weight int // (Optional) Weight for load balance calculating, it's useless if there's just one node. Charset string // (Optional, "utf8mb4" in default) Custom charset when operating on database. + CreatedAt string // (Optional) The filed name of table for automatic-filled created datetime. + UpdatedAt string // (Optional) The filed name of table for automatic-filled updated datetime. + DeletedAt string // (Optional) The filed name of table for automatic-filled updated datetime. LinkInfo string `json:"link"` // (Optional) Custom link information, when it is used, configuration Host/Port/User/Pass/Name are ignored. MaxIdleConnCount int `json:"maxidle"` // (Optional) Max idle connection configuration for underlying connection pool. MaxOpenConnCount int `json:"maxopen"` // (Optional) Max open connection configuration for underlying connection pool. @@ -212,3 +215,8 @@ func (c *Core) SetSchema(schema string) { func (c *Core) GetSchema() string { return c.schema.Val() } + +// GetConfig returns the current used node configuration. +func (c *Core) GetConfig() *ConfigNode { + return c.config +} diff --git a/database/gdb/gdb_model_delete.go b/database/gdb/gdb_model_delete.go index f60d2ef17..b9bb9ae88 100644 --- a/database/gdb/gdb_model_delete.go +++ b/database/gdb/gdb_model_delete.go @@ -25,7 +25,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) { } }() var ( - fieldNameDelete = m.getSoftFieldNameDelete() + fieldNameDelete = m.getSoftFieldNameDeleted() conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false) ) // Soft deleting. diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 702e2760a..1007b78da 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -149,9 +149,9 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql. } var ( nowString = gtime.Now().String() - fieldNameCreate = m.getSoftFieldNameCreate() - fieldNameUpdate = m.getSoftFieldNameUpdate() - fieldNameDelete = m.getSoftFieldNameDelete() + fieldNameCreate = m.getSoftFieldNameCreated() + fieldNameUpdate = m.getSoftFieldNameUpdated() + fieldNameDelete = m.getSoftFieldNameDeleted() ) // Batch operation. if list, ok := m.data.(List); ok { diff --git a/database/gdb/gdb_model_time.go b/database/gdb/gdb_model_soft_time.go similarity index 73% rename from database/gdb/gdb_model_time.go rename to database/gdb/gdb_model_soft_time.go index 9cc67e44d..bc805a000 100644 --- a/database/gdb/gdb_model_time.go +++ b/database/gdb/gdb_model_soft_time.go @@ -15,10 +15,10 @@ import ( "github.com/gogf/gf/util/gutil" ) -const ( - gSOFT_FIELD_NAME_CREATE = "create_at" - gSOFT_FIELD_NAME_UPDATE = "update_at" - gSOFT_FIELD_NAME_DELETE = "delete_at" +var ( + createdFiledNames = []string{"created_at", "create_at"} // Default filed names of table for automatic-filled created datetime. + updatedFiledNames = []string{"updated_at", "update_at"} // Default filed names of table for automatic-filled updated datetime. + deletedFiledNames = []string{"updated_at", "delete_at"} // Default filed names of table for automatic-filled deleted datetime. ) // Unscoped disables the auto-update time feature for insert, update and delete options. @@ -31,49 +31,66 @@ func (m *Model) Unscoped() *Model { // getSoftFieldNameCreate checks and returns the field name for record creating time. // If there's no field name for storing creating time, it returns an empty string. // It checks the key with or without cases or chars '-'/'_'/'.'/' '. -func (m *Model) getSoftFieldNameCreate(table ...string) string { +func (m *Model) getSoftFieldNameCreated(table ...string) string { tableName := "" if len(table) > 0 { tableName = table[0] } else { tableName = m.getPrimaryTableName() } - return m.getSoftFieldName(tableName, gSOFT_FIELD_NAME_CREATE) + config := m.db.GetConfig() + if config.CreatedAt != "" { + return m.getSoftFieldName(tableName, append([]string{config.CreatedAt}, createdFiledNames...)) + } + return m.getSoftFieldName(tableName, createdFiledNames) } // getSoftFieldNameUpdate checks and returns the field name for record updating time. // If there's no field name for storing updating time, it returns an empty string. // It checks the key with or without cases or chars '-'/'_'/'.'/' '. -func (m *Model) getSoftFieldNameUpdate(table ...string) (field string) { +func (m *Model) getSoftFieldNameUpdated(table ...string) (field string) { tableName := "" if len(table) > 0 { tableName = table[0] } else { tableName = m.getPrimaryTableName() } - return m.getSoftFieldName(tableName, gSOFT_FIELD_NAME_UPDATE) + config := m.db.GetConfig() + if config.UpdatedAt != "" { + return m.getSoftFieldName(tableName, append([]string{config.UpdatedAt}, updatedFiledNames...)) + } + return m.getSoftFieldName(tableName, updatedFiledNames) } // getSoftFieldNameDelete checks and returns the field name for record deleting time. // If there's no field name for storing deleting time, it returns an empty string. // It checks the key with or without cases or chars '-'/'_'/'.'/' '. -func (m *Model) getSoftFieldNameDelete(table ...string) (field string) { +func (m *Model) getSoftFieldNameDeleted(table ...string) (field string) { tableName := "" if len(table) > 0 { tableName = table[0] } else { tableName = m.getPrimaryTableName() } - return m.getSoftFieldName(tableName, gSOFT_FIELD_NAME_DELETE) + config := m.db.GetConfig() + if config.UpdatedAt != "" { + return m.getSoftFieldName(tableName, append([]string{config.DeletedAt}, deletedFiledNames...)) + } + return m.getSoftFieldName(tableName, deletedFiledNames) } // getSoftFieldName retrieves and returns the field name of the table for possible key. -func (m *Model) getSoftFieldName(table string, key string) (field string) { +func (m *Model) getSoftFieldName(table string, keys []string) (field string) { fieldsMap, _ := m.db.TableFields(table) if len(fieldsMap) > 0 { - field, _ = gutil.MapPossibleItemByKey( - gconv.Map(fieldsMap), key, - ) + for _, key := range keys { + field, _ = gutil.MapPossibleItemByKey( + gconv.Map(fieldsMap), key, + ) + if field != "" { + return + } + } } return } @@ -110,7 +127,7 @@ func (m *Model) getConditionForSoftDeleting() string { return conditionArray.Join(" AND ") } // Only one table. - if fieldName := m.getSoftFieldNameDelete(); fieldName != "" { + if fieldName := m.getSoftFieldNameDeleted(); fieldName != "" { return fmt.Sprintf(`%s IS NULL`, m.db.QuoteWord(fieldName)) } return "" @@ -129,7 +146,7 @@ func (m *Model) getConditionOfTableStringForSoftDeleting(s string) string { } else { table = array2[0] } - field = m.getSoftFieldNameDelete(table) + field = m.getSoftFieldNameDeleted(table) if field == "" { return "" } diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go index b3f8b1b04..ef1e5099c 100644 --- a/database/gdb/gdb_model_update.go +++ b/database/gdb/gdb_model_update.go @@ -42,9 +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() + fieldNameCreate = m.getSoftFieldNameCreated() + fieldNameUpdate = m.getSoftFieldNameUpdated() + fieldNameDelete = m.getSoftFieldNameDeleted() conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false) ) // Automatically update the record updating time. diff --git a/database/gdb/gdb_z_mysql_internal_test.go b/database/gdb/gdb_z_mysql_internal_test.go index c9eed95af..74b4d12a0 100644 --- a/database/gdb/gdb_z_mysql_internal_test.go +++ b/database/gdb/gdb_z_mysql_internal_test.go @@ -204,9 +204,9 @@ CREATE TABLE %s ( gtest.C(t, func(t *gtest.T) { model := db.Table(table1) - gtest.Assert(model.getSoftFieldNameCreate(table2), "createat") - gtest.Assert(model.getSoftFieldNameUpdate(table2), "updateat") - gtest.Assert(model.getSoftFieldNameDelete(table2), "deleteat") + gtest.Assert(model.getSoftFieldNameCreated(table2), "createat") + gtest.Assert(model.getSoftFieldNameUpdated(table2), "updateat") + gtest.Assert(model.getSoftFieldNameDeleted(table2), "deleteat") }) }