github.com/gogf/gf@v1.16.9/frame/gins/gins_database.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gins
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"github.com/gogf/gf/errors/gcode"
    13  	"github.com/gogf/gf/errors/gerror"
    14  	"github.com/gogf/gf/internal/intlog"
    15  	"github.com/gogf/gf/text/gstr"
    16  	"github.com/gogf/gf/util/gutil"
    17  
    18  	"github.com/gogf/gf/database/gdb"
    19  	"github.com/gogf/gf/text/gregex"
    20  	"github.com/gogf/gf/util/gconv"
    21  )
    22  
    23  const (
    24  	frameCoreComponentNameDatabase = "gf.core.component.database"
    25  	configNodeNameDatabase         = "database"
    26  )
    27  
    28  // Database returns an instance of database ORM object
    29  // with specified configuration group name.
    30  func Database(name ...string) gdb.DB {
    31  	group := gdb.DefaultGroupName
    32  	if len(name) > 0 && name[0] != "" {
    33  		group = name[0]
    34  	}
    35  	instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameDatabase, group)
    36  	db := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
    37  		var (
    38  			configMap     map[string]interface{}
    39  			configNodeKey string
    40  		)
    41  		// It firstly searches the configuration of the instance name.
    42  		if Config().Available() {
    43  			configNodeKey, _ = gutil.MapPossibleItemByKey(
    44  				Config().GetMap("."),
    45  				configNodeNameDatabase,
    46  			)
    47  			if configNodeKey == "" {
    48  				configNodeKey = configNodeNameDatabase
    49  			}
    50  			configMap = Config().GetMap(configNodeKey)
    51  		}
    52  		if len(configMap) == 0 && !gdb.IsConfigured() {
    53  			configFilePath, _ := Config().GetFilePath()
    54  			if configFilePath == "" {
    55  				exampleFileName := "config.example.toml"
    56  				if exampleConfigFilePath, _ := Config().GetFilePath(exampleFileName); exampleConfigFilePath != "" {
    57  					panic(gerror.NewCodef(
    58  						gcode.CodeMissingConfiguration,
    59  						`configuration file "%s" not found, but found "%s", did you miss renaming the example configuration file?`,
    60  						Config().GetFileName(),
    61  						exampleFileName,
    62  					))
    63  				} else {
    64  					panic(gerror.NewCodef(
    65  						gcode.CodeMissingConfiguration,
    66  						`configuration file "%s" not found, did you miss the configuration file or the misspell the configuration file name?`,
    67  						Config().GetFileName(),
    68  					))
    69  				}
    70  			}
    71  			panic(gerror.NewCodef(
    72  				gcode.CodeMissingConfiguration,
    73  				`database initialization failed: "%s" node not found, is configuration file or configuration node missing?`,
    74  				configNodeNameDatabase,
    75  			))
    76  		}
    77  		if len(configMap) == 0 {
    78  			configMap = make(map[string]interface{})
    79  		}
    80  		// Parse <m> as map-slice and adds it to gdb's global configurations.
    81  		for g, groupConfig := range configMap {
    82  			cg := gdb.ConfigGroup{}
    83  			switch value := groupConfig.(type) {
    84  			case []interface{}:
    85  				for _, v := range value {
    86  					if node := parseDBConfigNode(v); node != nil {
    87  						cg = append(cg, *node)
    88  					}
    89  				}
    90  			case map[string]interface{}:
    91  				if node := parseDBConfigNode(value); node != nil {
    92  					cg = append(cg, *node)
    93  				}
    94  			}
    95  			if len(cg) > 0 {
    96  				if gdb.GetConfig(group) == nil {
    97  					intlog.Printf(context.TODO(), "add configuration for group: %s, %#v", g, cg)
    98  					gdb.SetConfigGroup(g, cg)
    99  				} else {
   100  					intlog.Printf(context.TODO(), "ignore configuration as it already exists for group: %s, %#v", g, cg)
   101  					intlog.Printf(context.TODO(), "%s, %#v", g, cg)
   102  				}
   103  			}
   104  		}
   105  		// Parse <m> as a single node configuration,
   106  		// which is the default group configuration.
   107  		if node := parseDBConfigNode(configMap); node != nil {
   108  			cg := gdb.ConfigGroup{}
   109  			if node.Link != "" || node.Host != "" {
   110  				cg = append(cg, *node)
   111  			}
   112  
   113  			if len(cg) > 0 {
   114  				if gdb.GetConfig(group) == nil {
   115  					intlog.Printf(context.TODO(), "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
   116  					gdb.SetConfigGroup(gdb.DefaultGroupName, cg)
   117  				} else {
   118  					intlog.Printf(context.TODO(), "ignore configuration as it already exists for group: %s, %#v", gdb.DefaultGroupName, cg)
   119  					intlog.Printf(context.TODO(), "%s, %#v", gdb.DefaultGroupName, cg)
   120  				}
   121  			}
   122  		}
   123  		// Create a new ORM object with given configurations.
   124  		if db, err := gdb.New(name...); err == nil {
   125  			if Config().Available() {
   126  				// Initialize logger for ORM.
   127  				var loggerConfigMap map[string]interface{}
   128  				loggerConfigMap = Config().GetMap(fmt.Sprintf("%s.%s", configNodeKey, configNodeNameLogger))
   129  				if len(loggerConfigMap) == 0 {
   130  					loggerConfigMap = Config().GetMap(configNodeKey)
   131  				}
   132  				if len(loggerConfigMap) > 0 {
   133  					if err := db.GetLogger().SetConfigWithMap(loggerConfigMap); err != nil {
   134  						panic(err)
   135  					}
   136  				}
   137  			}
   138  			return db
   139  		} else {
   140  			// If panics, often because it does not find its configuration for given group.
   141  			panic(err)
   142  		}
   143  		return nil
   144  	})
   145  	if db != nil {
   146  		return db.(gdb.DB)
   147  	}
   148  	return nil
   149  }
   150  
   151  func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
   152  	nodeMap, ok := value.(map[string]interface{})
   153  	if !ok {
   154  		return nil
   155  	}
   156  	node := &gdb.ConfigNode{}
   157  	err := gconv.Struct(nodeMap, node)
   158  	if err != nil {
   159  		panic(err)
   160  	}
   161  	// To be compatible with old version.
   162  	if _, v := gutil.MapPossibleItemByKey(nodeMap, "LinkInfo"); v != nil {
   163  		node.Link = gconv.String(v)
   164  	}
   165  	if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil {
   166  		node.Link = gconv.String(v)
   167  	}
   168  	// Parse link syntax.
   169  	if node.Link != "" && node.Type == "" {
   170  		match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)
   171  		if len(match) == 3 {
   172  			node.Type = gstr.Trim(match[1])
   173  			node.Link = gstr.Trim(match[2])
   174  		}
   175  	}
   176  	return node
   177  }