diff --git a/container/gmap/gmap_hash_k_v_map.go b/container/gmap/gmap_hash_k_v_map.go index 6d65d59e9..7ad5ac924 100644 --- a/container/gmap/gmap_hash_k_v_map.go +++ b/container/gmap/gmap_hash_k_v_map.go @@ -66,10 +66,11 @@ func NewKVMapWithCheckerFrom[K comparable, V any](data map[K]V, checker NilCheck // This function is used to determine if a value should be considered as nil. // The nil checker function takes a value of type V and returns a boolean indicating // whether the value should be treated as nil. -func (m *KVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) { +func (m *KVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *KVMap[K, V] { m.mu.Lock() defer m.mu.Unlock() m.nilChecker = nilChecker + return m } // isNil checks whether the given value is nil. diff --git a/container/gmap/gmap_list_k_v_map.go b/container/gmap/gmap_list_k_v_map.go index 6b37ed57c..eb273828a 100644 --- a/container/gmap/gmap_list_k_v_map.go +++ b/container/gmap/gmap_list_k_v_map.go @@ -85,10 +85,11 @@ func NewListKVMapWithCheckerFrom[K comparable, V any](data map[K]V, nilChecker N // This function is used to determine if a value should be considered as nil. // The nil checker function takes a value of type V and returns a boolean indicating // whether the value should be treated as nil. -func (m *ListKVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) { +func (m *ListKVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *ListKVMap[K, V] { m.mu.Lock() defer m.mu.Unlock() m.nilChecker = nilChecker + return m } // isNil checks whether the given value is nil. diff --git a/container/gset/gset_t_set.go b/container/gset/gset_t_set.go index 02ffbf6cd..1537f61b9 100644 --- a/container/gset/gset_t_set.go +++ b/container/gset/gset_t_set.go @@ -70,10 +70,11 @@ func NewTSetWithCheckerFrom[T comparable](items []T, checker NilChecker[T], safe // This function is used to determine if an element should be considered as nil. // The nil checker function takes an element of type T and returns a boolean indicating // whether the element should be treated as nil. -func (set *TSet[T]) RegisterNilChecker(nilChecker NilChecker[T]) { +func (set *TSet[T]) RegisterNilChecker(nilChecker NilChecker[T]) *TSet[T] { set.mu.Lock() defer set.mu.Unlock() set.nilChecker = nilChecker + return set } // isNil checks whether the given value is nil. diff --git a/container/gtree/gtree_k_v_avltree.go b/container/gtree/gtree_k_v_avltree.go index 661364751..88a266fa1 100644 --- a/container/gtree/gtree_k_v_avltree.go +++ b/container/gtree/gtree_k_v_avltree.go @@ -82,10 +82,11 @@ func NewAVLKVTreeWithCheckerFrom[K comparable, V any](comparator func(v1, v2 K) // This function is used to determine if a value should be considered as nil. // The nil checker function takes a value of type V and returns a boolean indicating // whether the value should be treated as nil. -func (tree *AVLKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) { +func (tree *AVLKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *AVLKVTree[K, V] { tree.mu.Lock() defer tree.mu.Unlock() tree.nilChecker = nilChecker + return tree } // isNil checks whether the given value is nil. diff --git a/container/gtree/gtree_k_v_btree.go b/container/gtree/gtree_k_v_btree.go index 2adcede1b..eda3a1278 100644 --- a/container/gtree/gtree_k_v_btree.go +++ b/container/gtree/gtree_k_v_btree.go @@ -81,10 +81,11 @@ func NewBKVTreeWithCheckerFrom[K comparable, V any](m int, comparator func(v1, v // This function is used to determine if a value should be considered as nil. // The nil checker function takes a value of type V and returns a boolean indicating // whether the value should be treated as nil. -func (tree *BKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) { +func (tree *BKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *BKVTree[K, V] { tree.mu.Lock() defer tree.mu.Unlock() tree.nilChecker = nilChecker + return tree } // isNil checks whether the given value is nil. diff --git a/container/gtree/gtree_k_v_redblacktree.go b/container/gtree/gtree_k_v_redblacktree.go index 47585716a..b5b94af5b 100644 --- a/container/gtree/gtree_k_v_redblacktree.go +++ b/container/gtree/gtree_k_v_redblacktree.go @@ -100,10 +100,11 @@ func RedBlackKVTreeInitFrom[K comparable, V any](tree *RedBlackKVTree[K, V], com // This function is used to determine if a value should be considered as nil. // The nil checker function takes a value of type V and returns a boolean indicating // whether the value should be treated as nil. -func (tree *RedBlackKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) { +func (tree *RedBlackKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *RedBlackKVTree[K, V] { tree.mu.Lock() defer tree.mu.Unlock() tree.nilChecker = nilChecker + return tree } // isNil checks whether the given value is nil. diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index 9c3bd7f81..cc99d8e5a 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -513,18 +513,18 @@ type StatsItem interface { // Core is the base struct for database management. type Core struct { - db DB // DB interface object. - ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization. - group string // Configuration group name. - schema string // Custom schema for this object. - debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime. - cache *gcache.Cache // Cache manager, SQL result cache only. - links *gmap.Map // links caches all created links by node. - logger glog.ILogger // Logger for logging functionality. - config *ConfigNode // Current config node. - localTypeMap *gmap.StrAnyMap // Local type map for database field type conversion. - dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. - innerMemCache *gcache.Cache // Internal memory cache for storing temporary data. + db DB // DB interface object. + ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization. + group string // Configuration group name. + schema string // Custom schema for this object. + debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime. + cache *gcache.Cache // Cache manager, SQL result cache only. + links *gmap.KVMap[ConfigNode, *sql.DB] // links caches all created links by node. + logger glog.ILogger // Logger for logging functionality. + config *ConfigNode // Current config node. + localTypeMap *gmap.StrAnyMap // Local type map for database field type conversion. + dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. + innerMemCache *gcache.Cache // Internal memory cache for storing temporary data. } type dynamicConfig struct { @@ -944,6 +944,9 @@ func NewByGroup(group ...string) (db DB, err error) { ) } +// linksChecker is the checker function for links map. +var linksChecker = func(v *sql.DB) bool { return v == nil } + // newDBByConfigNode creates and returns an ORM object with given configuration node and group name. // // Very Note: @@ -960,7 +963,7 @@ func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) { group: group, debug: gtype.NewBool(), cache: gcache.New(), - links: gmap.New(true), + links: gmap.NewKVMapWithChecker[ConfigNode, *sql.DB](linksChecker, true), logger: glog.New(), config: node, localTypeMap: gmap.NewStrAnyMap(true), @@ -1127,7 +1130,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error // Cache the underlying connection pool object by node. var ( - instanceCacheFunc = func() any { + instanceCacheFunc = func() *sql.DB { if sqlDb, err = c.db.Open(node); err != nil { return nil } @@ -1159,7 +1162,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error ) if instanceValue != nil && sqlDb == nil { // It reads from instance map. - sqlDb = instanceValue.(*sql.DB) + sqlDb = instanceValue } if node.Debug { c.db.SetDebug(node.Debug) diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 4bb712c02..6cca52c7e 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -113,19 +113,17 @@ func (c *Core) Close(ctx context.Context) (err error) { if err = c.cache.Close(ctx); err != nil { return err } - c.links.LockFunc(func(m map[any]any) { + c.links.LockFunc(func(m map[ConfigNode]*sql.DB) { for k, v := range m { - if db, ok := v.(*sql.DB); ok { - err = db.Close() - if err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`) - } - intlog.Printf(ctx, `close link: %s, err: %v`, k, err) - if err != nil { - return - } - delete(m, k) + err = v.Close() + if err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`) } + intlog.Printf(ctx, `close link: %s, err: %v`, k, err) + if err != nil { + return + } + delete(m, k) } }) return diff --git a/database/gdb/gdb_core_stats.go b/database/gdb/gdb_core_stats.go index 8b64f14e8..de7febdbd 100644 --- a/database/gdb/gdb_core_stats.go +++ b/database/gdb/gdb_core_stats.go @@ -30,14 +30,10 @@ func (item *localStatsItem) Stats() sql.DBStats { // Stats retrieves and returns the pool stat for all nodes that have been established. func (c *Core) Stats(ctx context.Context) []StatsItem { var items = make([]StatsItem, 0) - c.links.Iterator(func(k, v any) bool { - var ( - node = k.(ConfigNode) - sqlDB = v.(*sql.DB) - ) + c.links.Iterator(func(k ConfigNode, v *sql.DB) bool { items = append(items, &localStatsItem{ - node: &node, - stats: sqlDB.Stats(), + node: &k, + stats: v.Stats(), }) return true })