2021-01-11 20:48:35 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2017-12-29 16:03:30 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
2019-02-02 16:18:25 +08:00
// You can obtain one at https://github.com/gogf/gf.
2017-12-31 18:19:58 +08:00
2017-12-14 17:32:51 +08:00
package gdb
import (
2019-06-19 09:06:52 +08:00
"sync"
2019-09-24 23:41:18 +08:00
"time"
2019-06-29 10:45:50 +08:00
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/os/gcache"
2021-11-13 23:23:55 +08:00
"github.com/gogf/gf/v2/os/glog"
2022-06-20 12:07:51 +08:00
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
2022-09-30 15:41:51 +08:00
"github.com/gogf/gf/v2/util/gconv"
2017-12-14 17:32:51 +08:00
)
2020-02-10 20:37:53 +08:00
// Config is the configuration management object.
2019-06-19 09:06:52 +08:00
type Config map [ string ] ConfigGroup
2017-12-14 17:32:51 +08:00
2020-02-10 20:37:53 +08:00
// ConfigGroup is a slice of configuration node for specified named group.
2017-12-14 17:32:51 +08:00
type ConfigGroup [ ] ConfigNode
2020-02-10 20:37:53 +08:00
// ConfigNode is configuration for one node.
2019-06-19 09:06:52 +08:00
type ConfigNode struct {
2021-01-12 00:42:33 +08:00
Host string ` json:"host" ` // Host of server, ip or domain like: 127.0.0.1, localhost
Port string ` json:"port" ` // Port, it's commonly 3306.
User string ` json:"user" ` // Authentication username.
Pass string ` json:"pass" ` // Authentication password.
Name string ` json:"name" ` // Default used database name.
Type string ` json:"type" ` // Database type: mysql, sqlite, mssql, pgsql, oracle.
2022-09-26 22:11:13 +08:00
Link string ` json:"link" ` // (Optional) Custom link information for all configuration in one single string.
Extra string ` json:"extra" ` // (Optional) Extra configuration according the registered third-party database driver.
2021-01-12 00:42:33 +08:00
Role string ` json:"role" ` // (Optional, "master" in default) Node role, used for master-slave mode: master, slave.
Debug bool ` json:"debug" ` // (Optional) Debug mode enables debug information logging and output.
Prefix string ` json:"prefix" ` // (Optional) Table prefix.
DryRun bool ` json:"dryRun" ` // (Optional) Dry run, which does SELECT but no INSERT/UPDATE/DELETE statements.
Weight int ` json:"weight" ` // (Optional) Weight for load balance calculating, it's useless if there's just one node.
2023-05-25 22:00:57 +08:00
Charset string ` json:"charset" ` // (Optional, "utf8" in default) Custom charset when operating on database.
2022-09-26 22:11:13 +08:00
Protocol string ` json:"protocol" ` // (Optional, "tcp" in default) See net.Dial for more information which networks are available.
2021-06-04 18:26:41 +08:00
Timezone string ` json:"timezone" ` // (Optional) Sets the time zone for displaying and interpreting time stamps.
2023-01-11 19:19:41 +08:00
Namespace string ` json:"namespace" ` // (Optional) Namespace for some databases. Eg, in pgsql, the `Name` acts as the `catalog`, the `NameSpace` acts as the `schema`.
2021-01-12 00:42:33 +08:00
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.
2021-04-04 12:01:22 +08:00
MaxConnLifeTime time . Duration ` json:"maxLifeTime" ` // (Optional) Max amount of time a connection may be idle before being closed.
2021-01-12 00:42:33 +08:00
QueryTimeout time . Duration ` json:"queryTimeout" ` // (Optional) Max query time for per dql.
ExecTimeout time . Duration ` json:"execTimeout" ` // (Optional) Max exec time for dml.
2022-11-03 20:22:36 +08:00
TranTimeout time . Duration ` json:"tranTimeout" ` // (Optional) Max exec time for a transaction.
PrepareTimeout time . Duration ` json:"prepareTimeout" ` // (Optional) Max exec time for prepare operation.
2021-01-12 00:42:33 +08:00
CreatedAt string ` json:"createdAt" ` // (Optional) The filed name of table for automatic-filled created datetime.
UpdatedAt string ` json:"updatedAt" ` // (Optional) The filed name of table for automatic-filled updated datetime.
DeletedAt string ` json:"deletedAt" ` // (Optional) The filed name of table for automatic-filled updated datetime.
TimeMaintainDisabled bool ` json:"timeMaintainDisabled" ` // (Optional) Disable the automatic time maintaining feature.
2020-02-10 20:37:53 +08:00
}
2021-05-21 13:25:53 +08:00
const (
DefaultGroupName = "default" // Default group name.
)
2022-09-26 22:11:13 +08:00
// configs specifies internal used configuration object.
2019-04-02 14:37:46 +08:00
var configs struct {
2020-02-10 20:37:53 +08:00
sync . RWMutex
config Config // All configurations.
group string // Default configuration group.
2019-04-02 14:37:46 +08:00
}
2017-12-14 17:32:51 +08:00
func init ( ) {
2019-06-19 09:06:52 +08:00
configs . config = make ( Config )
2020-12-14 19:34:02 +08:00
configs . group = DefaultGroupName
2017-12-14 17:32:51 +08:00
}
2020-02-10 20:37:53 +08:00
// SetConfig sets the global configuration for package.
// It will overwrite the old configuration of package.
2019-06-19 09:06:52 +08:00
func SetConfig ( config Config ) {
defer instances . Clear ( )
configs . Lock ( )
defer configs . Unlock ( )
2022-06-20 12:07:51 +08:00
for k , nodes := range config {
for i , node := range nodes {
nodes [ i ] = parseConfigNode ( node )
}
config [ k ] = nodes
}
2019-06-19 09:06:52 +08:00
configs . config = config
2017-12-14 17:32:51 +08:00
}
2020-02-10 20:37:53 +08:00
// SetConfigGroup sets the configuration for given group.
2019-09-02 20:35:29 +08:00
func SetConfigGroup ( group string , nodes ConfigGroup ) {
2019-06-19 09:06:52 +08:00
defer instances . Clear ( )
configs . Lock ( )
defer configs . Unlock ( )
2022-06-20 12:07:51 +08:00
for i , node := range nodes {
nodes [ i ] = parseConfigNode ( node )
}
2019-06-19 09:06:52 +08:00
configs . config [ group ] = nodes
2017-12-14 17:32:51 +08:00
}
2020-02-10 20:37:53 +08:00
// AddConfigNode adds one node configuration to configuration of given group.
2019-06-19 09:06:52 +08:00
func AddConfigNode ( group string , node ConfigNode ) {
defer instances . Clear ( )
configs . Lock ( )
defer configs . Unlock ( )
2022-06-20 12:07:51 +08:00
configs . config [ group ] = append ( configs . config [ group ] , parseConfigNode ( node ) )
}
// parseConfigNode parses `Link` configuration syntax.
func parseConfigNode ( node ConfigNode ) ConfigNode {
2022-09-30 15:41:51 +08:00
if node . Link != "" {
node = * parseConfigNodeLink ( & node )
}
2022-06-20 12:07:51 +08:00
if node . Link != "" && node . Type == "" {
match , _ := gregex . MatchString ( ` ([a-z]+):(.+) ` , node . Link )
if len ( match ) == 3 {
node . Type = gstr . Trim ( match [ 1 ] )
node . Link = gstr . Trim ( match [ 2 ] )
}
}
return node
2017-12-14 17:32:51 +08:00
}
2020-02-10 20:37:53 +08:00
// AddDefaultConfigNode adds one node configuration to configuration of default group.
2019-06-19 09:06:52 +08:00
func AddDefaultConfigNode ( node ConfigNode ) {
2020-12-14 19:34:02 +08:00
AddConfigNode ( DefaultGroupName , node )
2017-12-14 17:32:51 +08:00
}
2020-02-10 20:37:53 +08:00
// AddDefaultConfigGroup adds multiple node configurations to configuration of default group.
2019-06-19 09:06:52 +08:00
func AddDefaultConfigGroup ( nodes ConfigGroup ) {
2020-12-14 19:34:02 +08:00
SetConfigGroup ( DefaultGroupName , nodes )
2017-12-14 17:32:51 +08:00
}
2020-02-10 20:37:53 +08:00
// GetConfig retrieves and returns the configuration of given group.
2019-06-19 09:06:52 +08:00
func GetConfig ( group string ) ConfigGroup {
configs . RLock ( )
defer configs . RUnlock ( )
return configs . config [ group ]
2018-12-19 18:35:44 +08:00
}
2020-02-10 20:37:53 +08:00
// SetDefaultGroup sets the group name for default configuration.
2019-06-19 09:06:52 +08:00
func SetDefaultGroup ( name string ) {
defer instances . Clear ( )
configs . Lock ( )
defer configs . Unlock ( )
2020-02-10 20:37:53 +08:00
configs . group = name
2019-04-02 14:37:46 +08:00
}
2020-02-10 20:37:53 +08:00
// GetDefaultGroup returns the { name of default configuration.
2019-04-02 14:37:46 +08:00
func GetDefaultGroup ( ) string {
2019-06-19 09:06:52 +08:00
defer instances . Clear ( )
2019-06-29 10:45:50 +08:00
configs . RLock ( )
defer configs . RUnlock ( )
2020-02-10 20:37:53 +08:00
return configs . group
2017-12-14 17:32:51 +08:00
}
2018-10-13 20:29:27 +08:00
2020-08-31 15:39:27 +08:00
// IsConfigured checks and returns whether the database configured.
// It returns true if any configuration exists.
func IsConfigured ( ) bool {
configs . RLock ( )
defer configs . RUnlock ( )
return len ( configs . config ) > 0
}
2020-02-10 20:37:53 +08:00
// SetLogger sets the logger for orm.
2022-07-07 21:16:26 +08:00
func ( c * Core ) SetLogger ( logger glog . ILogger ) {
2020-03-08 00:17:42 +08:00
c . logger = logger
2019-08-26 19:39:04 +08:00
}
2021-08-10 15:36:15 +08:00
// GetLogger returns the (logger) of the orm.
2022-07-07 21:16:26 +08:00
func ( c * Core ) GetLogger ( ) glog . ILogger {
2020-03-08 00:17:42 +08:00
return c . logger
2019-12-04 16:04:52 +08:00
}
2021-04-04 12:01:22 +08:00
// SetMaxIdleConnCount sets the maximum number of connections in the idle
// connection pool.
//
// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.
//
// If n <= 0, no idle connections are retained.
//
// The default max idle connections is currently 2. This may change in
// a future release.
2020-03-08 00:17:42 +08:00
func ( c * Core ) SetMaxIdleConnCount ( n int ) {
2022-11-03 20:22:36 +08:00
c . dynamicConfig . MaxIdleConnCount = n
2018-10-13 20:29:27 +08:00
}
2021-04-04 12:01:22 +08:00
// SetMaxOpenConnCount sets the maximum number of open connections to the database.
//
// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than
// MaxIdleConns, then MaxIdleConns will be reduced to match the new
// MaxOpenConns limit.
//
// If n <= 0, then there is no limit on the number of open connections.
// The default is 0 (unlimited).
2020-03-08 00:17:42 +08:00
func ( c * Core ) SetMaxOpenConnCount ( n int ) {
2022-11-03 20:22:36 +08:00
c . dynamicConfig . MaxOpenConnCount = n
2018-10-13 20:29:27 +08:00
}
2021-04-04 12:01:22 +08:00
// SetMaxConnLifeTime sets the maximum amount of time a connection may be reused.
//
// Expired connections may be closed lazily before reuse.
//
// If d <= 0, connections are not closed due to a connection's age.
func ( c * Core ) SetMaxConnLifeTime ( d time . Duration ) {
2022-11-03 20:22:36 +08:00
c . dynamicConfig . MaxConnLifeTime = d
2018-12-12 20:01:10 +08:00
}
2020-11-27 13:24:05 +08:00
// GetConfig returns the current used node configuration.
func ( c * Core ) GetConfig ( ) * ConfigNode {
2022-11-03 20:22:36 +08:00
internalData := c . GetInternalCtxDataFromCtx ( c . db . GetCtx ( ) )
if internalData != nil && internalData . ConfigNode != nil {
2022-11-10 09:55:08 +08:00
// Note:
// It so here checks and returns the config from current DB,
// if different schemas between current DB and config.Name from context,
// for example, in nested transaction scenario, the context is passed all through the logic procedure,
// but the config.Name from context may be still the original one from the first transaction object.
if c . config . Name == internalData . ConfigNode . Name {
return internalData . ConfigNode
}
2022-11-03 20:22:36 +08:00
}
2020-11-27 13:24:05 +08:00
return c . config
}
2020-02-10 20:37:53 +08:00
// SetDebug enables/disables the debug mode.
2020-03-08 00:17:42 +08:00
func ( c * Core ) SetDebug ( debug bool ) {
c . debug . Set ( debug )
2018-12-14 18:35:51 +08:00
}
2020-03-08 00:17:42 +08:00
// GetDebug returns the debug value.
func ( c * Core ) GetDebug ( ) bool {
return c . debug . Val ( )
}
// GetCache returns the internal cache object.
func ( c * Core ) GetCache ( ) * gcache . Cache {
return c . cache
}
2020-04-08 21:26:14 +08:00
// GetGroup returns the group string configured.
func ( c * Core ) GetGroup ( ) string {
return c . group
}
2020-04-02 20:52:37 +08:00
// SetDryRun enables/disables the DryRun feature.
2020-11-27 13:24:05 +08:00
func ( c * Core ) SetDryRun ( enabled bool ) {
c . config . DryRun = enabled
2020-04-02 20:52:37 +08:00
}
// GetDryRun returns the DryRun value.
func ( c * Core ) GetDryRun ( ) bool {
2021-01-26 01:19:55 +08:00
return c . config . DryRun || allDryRun
2020-11-27 13:24:05 +08:00
}
// GetPrefix returns the table prefix string configured.
func ( c * Core ) GetPrefix ( ) string {
return c . config . Prefix
2020-04-02 20:52:37 +08:00
}
2020-03-08 00:17:42 +08:00
// GetSchema returns the schema configured.
func ( c * Core ) GetSchema ( ) string {
2022-11-03 20:22:36 +08:00
schema := c . schema
if schema == "" {
schema = c . db . GetConfig ( ) . Name
}
return schema
2019-06-19 09:06:52 +08:00
}
2022-09-30 15:41:51 +08:00
func parseConfigNodeLink ( node * ConfigNode ) * ConfigNode {
var match [ ] string
if node . Link != "" {
match , _ = gregex . MatchString ( linkPattern , node . Link )
if len ( match ) > 5 {
node . Type = match [ 1 ]
node . User = match [ 2 ]
node . Pass = match [ 3 ]
node . Protocol = match [ 4 ]
array := gstr . Split ( match [ 5 ] , ":" )
2023-02-13 19:18:30 +08:00
if len ( array ) == 2 && node . Protocol != "file" {
2022-09-30 15:41:51 +08:00
node . Host = array [ 0 ]
node . Port = array [ 1 ]
node . Name = match [ 6 ]
} else {
node . Name = match [ 5 ]
}
2023-03-01 19:30:40 +08:00
if len ( match ) > 6 && match [ 7 ] != "" {
2022-09-30 15:41:51 +08:00
node . Extra = match [ 7 ]
}
node . Link = ""
}
}
if node . Extra != "" {
if m , _ := gstr . Parse ( node . Extra ) ; len ( m ) > 0 {
_ = gconv . Struct ( m , & node )
}
}
// Default value checks.
if node . Charset == "" {
node . Charset = defaultCharset
}
if node . Protocol == "" {
node . Protocol = defaultProtocol
}
return node
}