github.com/gogf/gf/v2@v2.7.4/database/gdb/gdb_core_utility.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  
     8  package gdb
     9  
    10  import (
    11  	"context"
    12  	"fmt"
    13  
    14  	"github.com/gogf/gf/v2/errors/gcode"
    15  	"github.com/gogf/gf/v2/errors/gerror"
    16  	"github.com/gogf/gf/v2/text/gregex"
    17  	"github.com/gogf/gf/v2/text/gstr"
    18  	"github.com/gogf/gf/v2/util/gutil"
    19  )
    20  
    21  // GetDB returns the underlying DB.
    22  func (c *Core) GetDB() DB {
    23  	return c.db
    24  }
    25  
    26  // GetLink creates and returns the underlying database link object with transaction checks.
    27  // The parameter `master` specifies whether using the master node if master-slave configured.
    28  func (c *Core) GetLink(ctx context.Context, master bool, schema string) (Link, error) {
    29  	tx := TXFromCtx(ctx, c.db.GetGroup())
    30  	if tx != nil {
    31  		return &txLink{tx.GetSqlTX()}, nil
    32  	}
    33  	if master {
    34  		link, err := c.db.GetCore().MasterLink(schema)
    35  		if err != nil {
    36  			return nil, err
    37  		}
    38  		return link, nil
    39  	}
    40  	link, err := c.db.GetCore().SlaveLink(schema)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	return link, nil
    45  }
    46  
    47  // MasterLink acts like function Master but with additional `schema` parameter specifying
    48  // the schema for the connection. It is defined for internal usage.
    49  // Also see Master.
    50  func (c *Core) MasterLink(schema ...string) (Link, error) {
    51  	db, err := c.db.Master(schema...)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	return &dbLink{
    56  		DB:         db,
    57  		isOnMaster: true,
    58  	}, nil
    59  }
    60  
    61  // SlaveLink acts like function Slave but with additional `schema` parameter specifying
    62  // the schema for the connection. It is defined for internal usage.
    63  // Also see Slave.
    64  func (c *Core) SlaveLink(schema ...string) (Link, error) {
    65  	db, err := c.db.Slave(schema...)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return &dbLink{
    70  		DB:         db,
    71  		isOnMaster: false,
    72  	}, nil
    73  }
    74  
    75  // QuoteWord checks given string `s` a word,
    76  // if true it quotes `s` with security chars of the database
    77  // and returns the quoted string; or else it returns `s` without any change.
    78  //
    79  // The meaning of a `word` can be considered as a column name.
    80  func (c *Core) QuoteWord(s string) string {
    81  	s = gstr.Trim(s)
    82  	if s == "" {
    83  		return s
    84  	}
    85  	charLeft, charRight := c.db.GetChars()
    86  	return doQuoteWord(s, charLeft, charRight)
    87  }
    88  
    89  // QuoteString quotes string with quote chars. Strings like:
    90  // "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
    91  //
    92  // The meaning of a `string` can be considered as part of a statement string including columns.
    93  func (c *Core) QuoteString(s string) string {
    94  	if !gregex.IsMatchString(regularFieldNameWithCommaRegPattern, s) {
    95  		return s
    96  	}
    97  	charLeft, charRight := c.db.GetChars()
    98  	return doQuoteString(s, charLeft, charRight)
    99  }
   100  
   101  // QuotePrefixTableName adds prefix string and quotes chars for the table.
   102  // It handles table string like:
   103  // "user", "user u",
   104  // "user,user_detail",
   105  // "user u, user_detail ut",
   106  // "user as u, user_detail as ut".
   107  //
   108  // Note that, this will automatically checks the table prefix whether already added,
   109  // if true it does nothing to the table name, or else adds the prefix to the table name.
   110  func (c *Core) QuotePrefixTableName(table string) string {
   111  	charLeft, charRight := c.db.GetChars()
   112  	return doQuoteTableName(table, c.db.GetPrefix(), charLeft, charRight)
   113  }
   114  
   115  // GetChars returns the security char for current database.
   116  // It does nothing in default.
   117  func (c *Core) GetChars() (charLeft string, charRight string) {
   118  	return "", ""
   119  }
   120  
   121  // Tables retrieves and returns the tables of current schema.
   122  // It's mainly used in cli tool chain for automatically generating the models.
   123  func (c *Core) Tables(ctx context.Context, schema ...string) (tables []string, err error) {
   124  	return
   125  }
   126  
   127  // TableFields retrieves and returns the fields' information of specified table of current
   128  // schema.
   129  //
   130  // The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection
   131  // as its link to proceed necessary sql query.
   132  //
   133  // Note that it returns a map containing the field name and its corresponding fields.
   134  // As a map is unsorted, the TableField struct has an "Index" field marks its sequence in
   135  // the fields.
   136  //
   137  // It's using cache feature to enhance the performance, which is never expired util the
   138  // process restarts.
   139  func (c *Core) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*TableField, err error) {
   140  	return
   141  }
   142  
   143  // ClearTableFields removes certain cached table fields of current configuration group.
   144  func (c *Core) ClearTableFields(ctx context.Context, table string, schema ...string) (err error) {
   145  	tableFieldsCacheKey := genTableFieldsCacheKey(
   146  		c.db.GetGroup(),
   147  		gutil.GetOrDefaultStr(c.db.GetSchema(), schema...),
   148  		table,
   149  	)
   150  	_, err = c.innerMemCache.Remove(ctx, tableFieldsCacheKey)
   151  	return
   152  }
   153  
   154  // ClearTableFieldsAll removes all cached table fields of current configuration group.
   155  func (c *Core) ClearTableFieldsAll(ctx context.Context) (err error) {
   156  	var (
   157  		keys, _     = c.innerMemCache.KeyStrings(ctx)
   158  		cachePrefix = cachePrefixTableFields
   159  		removedKeys = make([]any, 0)
   160  	)
   161  	for _, key := range keys {
   162  		if gstr.HasPrefix(key, cachePrefix) {
   163  			removedKeys = append(removedKeys, key)
   164  		}
   165  	}
   166  
   167  	if len(removedKeys) > 0 {
   168  		err = c.innerMemCache.Removes(ctx, removedKeys)
   169  	}
   170  	return
   171  }
   172  
   173  // ClearCache removes cached sql result of certain table.
   174  func (c *Core) ClearCache(ctx context.Context, table string) (err error) {
   175  	var (
   176  		keys, _     = c.db.GetCache().KeyStrings(ctx)
   177  		cachePrefix = fmt.Sprintf(`%s%s@`, cachePrefixSelectCache, table)
   178  		removedKeys = make([]any, 0)
   179  	)
   180  	for _, key := range keys {
   181  		if gstr.HasPrefix(key, cachePrefix) {
   182  			removedKeys = append(removedKeys, key)
   183  		}
   184  	}
   185  	if len(removedKeys) > 0 {
   186  		err = c.db.GetCache().Removes(ctx, removedKeys)
   187  	}
   188  	return
   189  }
   190  
   191  // ClearCacheAll removes all cached sql result from cache
   192  func (c *Core) ClearCacheAll(ctx context.Context) (err error) {
   193  	if err = c.db.GetCache().Clear(ctx); err != nil {
   194  		return err
   195  	}
   196  	if err = c.GetInnerMemCache().Clear(ctx); err != nil {
   197  		return err
   198  	}
   199  	return
   200  }
   201  
   202  // HasField determine whether the field exists in the table.
   203  func (c *Core) HasField(ctx context.Context, table, field string, schema ...string) (bool, error) {
   204  	table = c.guessPrimaryTableName(table)
   205  	tableFields, err := c.db.TableFields(ctx, table, schema...)
   206  	if err != nil {
   207  		return false, err
   208  	}
   209  	if len(tableFields) == 0 {
   210  		return false, gerror.NewCodef(
   211  			gcode.CodeNotFound,
   212  			`empty table fields for table "%s"`, table,
   213  		)
   214  	}
   215  	fieldsArray := make([]string, len(tableFields))
   216  	for k, v := range tableFields {
   217  		fieldsArray[v.Index] = k
   218  	}
   219  	charLeft, charRight := c.db.GetChars()
   220  	field = gstr.Trim(field, charLeft+charRight)
   221  	for _, f := range fieldsArray {
   222  		if f == field {
   223  			return true, nil
   224  		}
   225  	}
   226  	return false, nil
   227  }
   228  
   229  // guessPrimaryTableName parses and returns the primary table name.
   230  func (c *Core) guessPrimaryTableName(tableStr string) string {
   231  	if tableStr == "" {
   232  		return ""
   233  	}
   234  	var (
   235  		guessedTableName string
   236  		array1           = gstr.SplitAndTrim(tableStr, ",")
   237  		array2           = gstr.SplitAndTrim(array1[0], " ")
   238  		array3           = gstr.SplitAndTrim(array2[0], ".")
   239  	)
   240  	if len(array3) >= 2 {
   241  		guessedTableName = array3[1]
   242  	} else {
   243  		guessedTableName = array3[0]
   244  	}
   245  	charL, charR := c.db.GetChars()
   246  	if charL != "" || charR != "" {
   247  		guessedTableName = gstr.Trim(guessedTableName, charL+charR)
   248  	}
   249  	if !gregex.IsMatchString(regularFieldNameRegPattern, guessedTableName) {
   250  		return ""
   251  	}
   252  	return guessedTableName
   253  }