github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf.
     6  
     7  package gins
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  
    13  	"github.com/wangyougui/gf/v2/database/gdb"
    14  	"github.com/wangyougui/gf/v2/errors/gcode"
    15  	"github.com/wangyougui/gf/v2/errors/gerror"
    16  	"github.com/wangyougui/gf/v2/internal/consts"
    17  	"github.com/wangyougui/gf/v2/internal/instance"
    18  	"github.com/wangyougui/gf/v2/internal/intlog"
    19  	"github.com/wangyougui/gf/v2/os/gcfg"
    20  	"github.com/wangyougui/gf/v2/os/glog"
    21  	"github.com/wangyougui/gf/v2/util/gconv"
    22  	"github.com/wangyougui/gf/v2/util/gutil"
    23  )
    24  
    25  // Database returns an instance of database ORM object with specified configuration group name.
    26  // Note that it panics if any error occurs duration instance creating.
    27  func Database(name ...string) gdb.DB {
    28  	var (
    29  		ctx   = context.Background()
    30  		group = gdb.DefaultGroupName
    31  	)
    32  
    33  	if len(name) > 0 && name[0] != "" {
    34  		group = name[0]
    35  	}
    36  	instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameDatabase, group)
    37  	db := instance.GetOrSetFuncLock(instanceKey, func() interface{} {
    38  		// It ignores returned error to avoid file no found error while it's not necessary.
    39  		var (
    40  			configMap     map[string]interface{}
    41  			configNodeKey = consts.ConfigNodeNameDatabase
    42  		)
    43  		// It firstly searches the configuration of the instance name.
    44  		if configData, _ := Config().Data(ctx); len(configData) > 0 {
    45  			if v, _ := gutil.MapPossibleItemByKey(configData, consts.ConfigNodeNameDatabase); v != "" {
    46  				configNodeKey = v
    47  			}
    48  		}
    49  		if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
    50  			configMap = v.Map()
    51  		}
    52  		// No configuration found, it formats and panics error.
    53  		if len(configMap) == 0 && !gdb.IsConfigured() {
    54  			// File configuration object checks.
    55  			var err error
    56  			if fileConfig, ok := Config().GetAdapter().(*gcfg.AdapterFile); ok {
    57  				if _, err = fileConfig.GetFilePath(); err != nil {
    58  					panic(gerror.WrapCode(gcode.CodeMissingConfiguration, err,
    59  						`configuration not found, did you miss the configuration file or misspell the configuration file name`,
    60  					))
    61  				}
    62  			}
    63  			// Panic if nothing found in Config object or in gdb configuration.
    64  			if len(configMap) == 0 && !gdb.IsConfigured() {
    65  				panic(gerror.NewCodef(
    66  					gcode.CodeMissingConfiguration,
    67  					`database initialization failed: configuration missing for database node "%s"`,
    68  					consts.ConfigNodeNameDatabase,
    69  				))
    70  			}
    71  		}
    72  
    73  		if len(configMap) == 0 {
    74  			configMap = make(map[string]interface{})
    75  		}
    76  		// Parse `m` as map-slice and adds it to global configurations for package gdb.
    77  		for g, groupConfig := range configMap {
    78  			cg := gdb.ConfigGroup{}
    79  			switch value := groupConfig.(type) {
    80  			case []interface{}:
    81  				for _, v := range value {
    82  					if node := parseDBConfigNode(v); node != nil {
    83  						cg = append(cg, *node)
    84  					}
    85  				}
    86  			case map[string]interface{}:
    87  				if node := parseDBConfigNode(value); node != nil {
    88  					cg = append(cg, *node)
    89  				}
    90  			}
    91  			if len(cg) > 0 {
    92  				if gdb.GetConfig(group) == nil {
    93  					intlog.Printf(ctx, "add configuration for group: %s, %#v", g, cg)
    94  					gdb.SetConfigGroup(g, cg)
    95  				} else {
    96  					intlog.Printf(ctx, "ignore configuration as it already exists for group: %s, %#v", g, cg)
    97  					intlog.Printf(ctx, "%s, %#v", g, cg)
    98  				}
    99  			}
   100  		}
   101  		// Parse `m` as a single node configuration,
   102  		// which is the default group configuration.
   103  		if node := parseDBConfigNode(configMap); node != nil {
   104  			cg := gdb.ConfigGroup{}
   105  			if node.Link != "" || node.Host != "" {
   106  				cg = append(cg, *node)
   107  			}
   108  			if len(cg) > 0 {
   109  				if gdb.GetConfig(group) == nil {
   110  					intlog.Printf(ctx, "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
   111  					gdb.SetConfigGroup(gdb.DefaultGroupName, cg)
   112  				} else {
   113  					intlog.Printf(
   114  						ctx,
   115  						"ignore configuration as it already exists for group: %s, %#v",
   116  						gdb.DefaultGroupName, cg,
   117  					)
   118  					intlog.Printf(ctx, "%s, %#v", gdb.DefaultGroupName, cg)
   119  				}
   120  			}
   121  		}
   122  
   123  		// Create a new ORM object with given configurations.
   124  		if db, err := gdb.NewByGroup(name...); err == nil {
   125  			// Initialize logger for ORM.
   126  			var (
   127  				loggerConfigMap map[string]interface{}
   128  				loggerNodeName  = fmt.Sprintf("%s.%s", configNodeKey, consts.ConfigNodeNameLogger)
   129  			)
   130  			if v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {
   131  				loggerConfigMap = v.Map()
   132  			}
   133  			if len(loggerConfigMap) == 0 {
   134  				if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
   135  					loggerConfigMap = v.Map()
   136  				}
   137  			}
   138  			if len(loggerConfigMap) > 0 {
   139  				if logger, ok := db.GetLogger().(*glog.Logger); ok {
   140  					if err = logger.SetConfigWithMap(loggerConfigMap); err != nil {
   141  						panic(err)
   142  					}
   143  				}
   144  			}
   145  			return db
   146  		} else {
   147  			// If panics, often because it does not find its configuration for given group.
   148  			panic(err)
   149  		}
   150  		return nil
   151  	})
   152  	if db != nil {
   153  		return db.(gdb.DB)
   154  	}
   155  	return nil
   156  }
   157  
   158  func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
   159  	nodeMap, ok := value.(map[string]interface{})
   160  	if !ok {
   161  		return nil
   162  	}
   163  	var (
   164  		node = &gdb.ConfigNode{}
   165  		err  = gconv.Struct(nodeMap, node)
   166  	)
   167  	if err != nil {
   168  		panic(err)
   169  	}
   170  	// Find possible `Link` configuration content.
   171  	if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil {
   172  		node.Link = gconv.String(v)
   173  	}
   174  	return node
   175  }