diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go
index 371840a82..98f0cb75c 100644
--- a/database/gdb/gdb.go
+++ b/database/gdb/gdb.go
@@ -37,9 +37,23 @@ type DB interface {
// "Table" is not proper for that purpose any more.
// Deprecated, use Model instead.
Table(table ...string) *Model
+
+ // Model creates and returns a new ORM model from given schema.
+ // The parameter `table` can be more than one table names, and also alias name, like:
+ // 1. Model names:
+ // Model("user")
+ // Model("user u")
+ // Model("user, user_detail")
+ // Model("user u, user_detail ud")
+ // 2. Model name with alias: Model("user", "u")
Model(table ...string) *Model
+
+ // Schema creates and returns a schema.
Schema(schema string) *Schema
+ // With creates and returns an ORM model based on meta data of given object.
+ With(object interface{}) *Model
+
// Open creates a raw connection object for database with given node configuration.
// Note that it is not recommended using the this function manually.
Open(config *ConfigNode) (*sql.DB, error)
@@ -158,9 +172,9 @@ type DB interface {
FilteredLinkInfo() string
// HandleSqlBeforeCommit is a hook function, which deals with the sql string before
- // it's committed to underlying driver. The parameter specifies the current
- // database connection operation object. You can modify the sql string and its
- // arguments as you wish before they're committed to driver.
+ // it's committed to underlying driver. The parameter `link` specifies the current
+ // database connection operation object. You can modify the sql string `sql` and its
+ // arguments `args` as you wish before they're committed to driver.
HandleSqlBeforeCommit(link Link, sql string, args []interface{}) (string, []interface{})
// ===========================================================================
@@ -174,14 +188,14 @@ type DB interface {
// Core is the base struct for database management.
type Core struct {
- DB DB // DB interface object.
+ db DB // DB interface object.
+ ctx context.Context // Context for chaining operation only.
group string // Configuration group name.
debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime.
cache *gcache.Cache // Cache manager, SQL result cache only.
schema *gtype.String // Custom schema for this object.
logger *glog.Logger // Logger.
config *ConfigNode // Current config node.
- ctx context.Context // Context for chaining operation only.
}
// Driver is the interface for integrating sql drivers into package gdb.
@@ -302,7 +316,7 @@ func Register(name string, driver Driver) error {
}
// New creates and returns an ORM object with global configurations.
-// The parameter specifies the configuration group name,
+// The parameter `name` specifies the configuration group name,
// which is DefaultGroupName in default.
func New(group ...string) (db DB, err error) {
groupName := configs.group
@@ -326,11 +340,11 @@ func New(group ...string) (db DB, err error) {
config: node,
}
if v, ok := driverMap[node.Type]; ok {
- c.DB, err = v.New(c, node)
+ c.db, err = v.New(c, node)
if err != nil {
return nil, err
}
- return c.DB, nil
+ return c.db, nil
} else {
return nil, gerror.New(fmt.Sprintf(`unsupported database type "%s"`, node.Type))
}
@@ -343,7 +357,7 @@ func New(group ...string) (db DB, err error) {
}
// Instance returns an instance for DB operations.
-// The parameter specifies the configuration group name,
+// The parameter `name` specifies the configuration group name,
// which is DefaultGroupName in default.
func Instance(name ...string) (db DB, err error) {
group := configs.group
@@ -363,7 +377,7 @@ func Instance(name ...string) (db DB, err error) {
// getConfigNodeByGroup calculates and returns a configuration node of given group. It
// calculates the value internally using weight algorithm for load balance.
//
-// The parameter specifies whether retrieving a master node, or else a slave node
+// The parameter `master` specifies whether retrieving a master node, or else a slave node
// if master-slave configured.
func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) {
if list, ok := configs.config[group]; ok {
@@ -432,7 +446,7 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
}
// getSqlDb retrieves and returns a underlying database connection object.
-// The parameter specifies whether retrieves master node connection if
+// The parameter `master` specifies whether retrieves master node connection if
// master-slave nodes are configured.
func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
// Load balance.
@@ -457,7 +471,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
}
// Cache the underlying connection pool object by node.
v, _ := internalCache.GetOrSetFuncLock(node.String(), func() (interface{}, error) {
- sqlDb, err = c.DB.Open(node)
+ sqlDb, err = c.db.Open(node)
if err != nil {
intlog.Printf("DB open failed: %v, %+v", err, node)
return nil, err
@@ -489,10 +503,10 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
sqlDb = v.(*sql.DB)
}
if node.Debug {
- c.DB.SetDebug(node.Debug)
+ c.db.SetDebug(node.Debug)
}
if node.DryRun {
- c.DB.SetDryRun(node.DryRun)
+ c.db.SetDryRun(node.DryRun)
}
return
}
diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go
index 08c21c245..d26606226 100644
--- a/database/gdb/gdb_core.go
+++ b/database/gdb/gdb_core.go
@@ -30,21 +30,21 @@ import (
// a global or package variable for long using.
func (c *Core) Ctx(ctx context.Context) DB {
if ctx == nil {
- return c.DB
+ return c.db
}
var (
err error
newCore = &Core{}
- configNode = c.DB.GetConfig()
+ configNode = c.db.GetConfig()
)
*newCore = *c
newCore.ctx = ctx
- newCore.DB, err = driverMap[configNode.Type].New(newCore, configNode)
+ newCore.db, err = driverMap[configNode.Type].New(newCore, configNode)
// Seldom error, just log it.
if err != nil {
- c.DB.GetLogger().Ctx(ctx).Error(err)
+ c.db.GetLogger().Ctx(ctx).Error(err)
}
- return newCore.DB
+ return newCore.db
}
// GetCtx returns the context for current DB.
@@ -59,22 +59,22 @@ func (c *Core) GetCtx() context.Context {
// GetCtxTimeout returns the context and cancel function for specified timeout type.
func (c *Core) GetCtxTimeout(timeoutType int, ctx context.Context) (context.Context, context.CancelFunc) {
if ctx == nil {
- ctx = c.DB.GetCtx()
+ ctx = c.db.GetCtx()
} else {
ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil)
}
switch timeoutType {
case ctxTimeoutTypeExec:
- if c.DB.GetConfig().ExecTimeout > 0 {
- return context.WithTimeout(ctx, c.DB.GetConfig().ExecTimeout)
+ if c.db.GetConfig().ExecTimeout > 0 {
+ return context.WithTimeout(ctx, c.db.GetConfig().ExecTimeout)
}
case ctxTimeoutTypeQuery:
- if c.DB.GetConfig().QueryTimeout > 0 {
- return context.WithTimeout(ctx, c.DB.GetConfig().QueryTimeout)
+ if c.db.GetConfig().QueryTimeout > 0 {
+ return context.WithTimeout(ctx, c.db.GetConfig().QueryTimeout)
}
case ctxTimeoutTypePrepare:
- if c.DB.GetConfig().PrepareTimeout > 0 {
- return context.WithTimeout(ctx, c.DB.GetConfig().PrepareTimeout)
+ if c.db.GetConfig().PrepareTimeout > 0 {
+ return context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout)
}
default:
panic(gerror.Newf("invalid context timeout type: %d", timeoutType))
@@ -97,19 +97,19 @@ func (c *Core) Slave() (*sql.DB, error) {
// Query commits one query SQL to underlying driver and returns the execution result.
// It is most commonly used for data querying.
func (c *Core) Query(sql string, args ...interface{}) (rows *sql.Rows, err error) {
- link, err := c.DB.Slave()
+ link, err := c.db.Slave()
if err != nil {
return nil, err
}
- return c.DB.DoQuery(link, sql, args...)
+ return c.db.DoQuery(link, sql, args...)
}
// DoQuery commits the sql string and its arguments to underlying driver
// through given link object and returns the execution result.
func (c *Core) DoQuery(link Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
sql, args = formatSql(sql, args)
- sql, args = c.DB.HandleSqlBeforeCommit(link, sql, args)
- ctx := c.DB.GetCtx()
+ sql, args = c.db.HandleSqlBeforeCommit(link, sql, args)
+ ctx := c.db.GetCtx()
if c.GetConfig().QueryTimeout > 0 {
var cancelFunc context.CancelFunc
ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().QueryTimeout)
@@ -127,10 +127,10 @@ func (c *Core) DoQuery(link Link, sql string, args ...interface{}) (rows *sql.Ro
Error: err,
Start: mTime1,
End: mTime2,
- Group: c.DB.GetGroup(),
+ Group: c.db.GetGroup(),
}
c.addSqlToTracing(ctx, sqlObj)
- if c.DB.GetDebug() {
+ if c.db.GetDebug() {
c.writeSqlToLogger(sqlObj)
}
if err == nil {
@@ -144,19 +144,19 @@ func (c *Core) DoQuery(link Link, sql string, args ...interface{}) (rows *sql.Ro
// Exec commits one query SQL to underlying driver and returns the execution result.
// It is most commonly used for data inserting and updating.
func (c *Core) Exec(sql string, args ...interface{}) (result sql.Result, err error) {
- link, err := c.DB.Master()
+ link, err := c.db.Master()
if err != nil {
return nil, err
}
- return c.DB.DoExec(link, sql, args...)
+ return c.db.DoExec(link, sql, args...)
}
// DoExec commits the sql string and its arguments to underlying driver
// through given link object and returns the execution result.
func (c *Core) DoExec(link Link, sql string, args ...interface{}) (result sql.Result, err error) {
sql, args = formatSql(sql, args)
- sql, args = c.DB.HandleSqlBeforeCommit(link, sql, args)
- ctx := c.DB.GetCtx()
+ sql, args = c.db.HandleSqlBeforeCommit(link, sql, args)
+ ctx := c.db.GetCtx()
if c.GetConfig().ExecTimeout > 0 {
var cancelFunc context.CancelFunc
ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().ExecTimeout)
@@ -164,7 +164,7 @@ func (c *Core) DoExec(link Link, sql string, args ...interface{}) (result sql.Re
}
mTime1 := gtime.TimestampMilli()
- if !c.DB.GetDryRun() {
+ if !c.db.GetDryRun() {
result, err = link.ExecContext(ctx, sql, args...)
} else {
result = new(SqlResult)
@@ -178,10 +178,10 @@ func (c *Core) DoExec(link Link, sql string, args ...interface{}) (result sql.Re
Error: err,
Start: mTime1,
End: mTime2,
- Group: c.DB.GetGroup(),
+ Group: c.db.GetGroup(),
}
c.addSqlToTracing(ctx, sqlObj)
- if c.DB.GetDebug() {
+ if c.db.GetDebug() {
c.writeSqlToLogger(sqlObj)
}
return result, formatError(err, sql, args...)
@@ -193,7 +193,7 @@ func (c *Core) DoExec(link Link, sql string, args ...interface{}) (result sql.Re
// The caller must call the statement's Close method
// when the statement is no longer needed.
//
-// The parameter specifies whether executing the sql on master node,
+// The parameter `execOnMaster` specifies whether executing the sql on master node,
// or else it executes the sql on slave node if master-slave configured.
func (c *Core) Prepare(sql string, execOnMaster ...bool) (*Stmt, error) {
var (
@@ -201,20 +201,20 @@ func (c *Core) Prepare(sql string, execOnMaster ...bool) (*Stmt, error) {
link Link
)
if len(execOnMaster) > 0 && execOnMaster[0] {
- if link, err = c.DB.Master(); err != nil {
+ if link, err = c.db.Master(); err != nil {
return nil, err
}
} else {
- if link, err = c.DB.Slave(); err != nil {
+ if link, err = c.db.Slave(); err != nil {
return nil, err
}
}
- return c.DB.DoPrepare(link, sql)
+ return c.db.DoPrepare(link, sql)
}
// doPrepare calls prepare function on given link object and returns the statement object.
func (c *Core) DoPrepare(link Link, sql string) (*Stmt, error) {
- ctx := c.DB.GetCtx()
+ ctx := c.db.GetCtx()
if c.GetConfig().PrepareTimeout > 0 {
// DO NOT USE cancel function in prepare statement.
ctx, _ = context.WithTimeout(ctx, c.GetConfig().PrepareTimeout)
@@ -231,11 +231,11 @@ func (c *Core) DoPrepare(link Link, sql string) (*Stmt, error) {
Error: err,
Start: mTime1,
End: mTime2,
- Group: c.DB.GetGroup(),
+ Group: c.db.GetGroup(),
}
)
c.addSqlToTracing(ctx, sqlObj)
- if c.DB.GetDebug() {
+ if c.db.GetDebug() {
c.writeSqlToLogger(sqlObj)
}
return &Stmt{
@@ -247,28 +247,28 @@ func (c *Core) DoPrepare(link Link, sql string) (*Stmt, error) {
// GetAll queries and returns data records from database.
func (c *Core) GetAll(sql string, args ...interface{}) (Result, error) {
- return c.DB.DoGetAll(nil, sql, args...)
+ return c.db.DoGetAll(nil, sql, args...)
}
// DoGetAll queries and returns data records from database.
func (c *Core) DoGetAll(link Link, sql string, args ...interface{}) (result Result, err error) {
if link == nil {
- link, err = c.DB.Slave()
+ link, err = c.db.Slave()
if err != nil {
return nil, err
}
}
- rows, err := c.DB.DoQuery(link, sql, args...)
+ rows, err := c.db.DoQuery(link, sql, args...)
if err != nil || rows == nil {
return nil, err
}
defer rows.Close()
- return c.DB.convertRowsToResult(rows)
+ return c.db.convertRowsToResult(rows)
}
// GetOne queries and returns one record from database.
func (c *Core) GetOne(sql string, args ...interface{}) (Record, error) {
- list, err := c.DB.GetAll(sql, args...)
+ list, err := c.db.GetAll(sql, args...)
if err != nil {
return nil, err
}
@@ -281,7 +281,7 @@ func (c *Core) GetOne(sql string, args ...interface{}) (Record, error) {
// GetArray queries and returns data values as slice from database.
// Note that if there're multiple columns in the result, it returns just one column values randomly.
func (c *Core) GetArray(sql string, args ...interface{}) ([]Value, error) {
- all, err := c.DB.DoGetAll(nil, sql, args...)
+ all, err := c.db.DoGetAll(nil, sql, args...)
if err != nil {
return nil, err
}
@@ -289,9 +289,9 @@ func (c *Core) GetArray(sql string, args ...interface{}) ([]Value, error) {
}
// GetStruct queries one record from database and converts it to given struct.
-// The parameter should be a pointer to struct.
+// The parameter `pointer` should be a pointer to struct.
func (c *Core) GetStruct(pointer interface{}, sql string, args ...interface{}) error {
- one, err := c.DB.GetOne(sql, args...)
+ one, err := c.db.GetOne(sql, args...)
if err != nil {
return err
}
@@ -299,9 +299,9 @@ func (c *Core) GetStruct(pointer interface{}, sql string, args ...interface{}) e
}
// GetStructs queries records from database and converts them to given struct.
-// The parameter should be type of struct slice: []struct/[]*struct.
+// The parameter `pointer` should be type of struct slice: []struct/[]*struct.
func (c *Core) GetStructs(pointer interface{}, sql string, args ...interface{}) error {
- all, err := c.DB.GetAll(sql, args...)
+ all, err := c.db.GetAll(sql, args...)
if err != nil {
return err
}
@@ -311,8 +311,8 @@ func (c *Core) GetStructs(pointer interface{}, sql string, args ...interface{})
// GetScan queries one or more records from database and converts them to given struct or
// struct array.
//
-// If parameter is type of struct pointer, it calls GetStruct internally for
-// the conversion. If parameter is type of slice, it calls GetStructs internally
+// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for
+// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
// for conversion.
func (c *Core) GetScan(pointer interface{}, sql string, args ...interface{}) error {
t := reflect.TypeOf(pointer)
@@ -323,9 +323,9 @@ func (c *Core) GetScan(pointer interface{}, sql string, args ...interface{}) err
k = t.Elem().Kind()
switch k {
case reflect.Array, reflect.Slice:
- return c.DB.GetStructs(pointer, sql, args...)
+ return c.db.GetStructs(pointer, sql, args...)
case reflect.Struct:
- return c.DB.GetStruct(pointer, sql, args...)
+ return c.db.GetStruct(pointer, sql, args...)
}
return fmt.Errorf("element type should be type of struct/slice, unsupported: %v", k)
}
@@ -334,7 +334,7 @@ func (c *Core) GetScan(pointer interface{}, sql string, args ...interface{}) err
// The sql should queries only one field from database, or else it returns only one
// field of the result.
func (c *Core) GetValue(sql string, args ...interface{}) (Value, error) {
- one, err := c.DB.GetOne(sql, args...)
+ one, err := c.db.GetOne(sql, args...)
if err != nil {
return gvar.New(nil), err
}
@@ -351,7 +351,7 @@ func (c *Core) GetCount(sql string, args ...interface{}) (int, error) {
if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) {
sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql)
}
- value, err := c.DB.GetValue(sql, args...)
+ value, err := c.db.GetValue(sql, args...)
if err != nil {
return 0, err
}
@@ -360,7 +360,7 @@ func (c *Core) GetCount(sql string, args ...interface{}) (int, error) {
// PingMaster pings the master node to check authentication or keeps the connection alive.
func (c *Core) PingMaster() error {
- if master, err := c.DB.Master(); err != nil {
+ if master, err := c.db.Master(); err != nil {
return err
} else {
return master.Ping()
@@ -369,7 +369,7 @@ func (c *Core) PingMaster() error {
// PingSlave pings the slave node to check authentication or keeps the connection alive.
func (c *Core) PingSlave() error {
- if slave, err := c.DB.Slave(); err != nil {
+ if slave, err := c.db.Slave(); err != nil {
return err
} else {
return slave.Ping()
@@ -381,10 +381,10 @@ func (c *Core) PingSlave() error {
// if you no longer use the transaction. Commit or Rollback functions will also
// close the transaction automatically.
func (c *Core) Begin() (*TX, error) {
- if master, err := c.DB.Master(); err != nil {
+ if master, err := c.db.Master(); err != nil {
return nil, err
} else {
- ctx := c.DB.GetCtx()
+ ctx := c.db.GetCtx()
if c.GetConfig().TranTimeout > 0 {
var cancelFunc context.CancelFunc
ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().TranTimeout)
@@ -392,7 +392,7 @@ func (c *Core) Begin() (*TX, error) {
}
if tx, err := master.BeginTx(ctx, nil); err == nil {
return &TX{
- db: c.DB,
+ db: c.db,
tx: tx,
master: master,
}, nil
@@ -402,16 +402,16 @@ func (c *Core) Begin() (*TX, error) {
}
}
-// Transaction wraps the transaction logic using function .
-// It rollbacks the transaction and returns the error from function if
+// Transaction wraps the transaction logic using function `f`.
+// It rollbacks the transaction and returns the error from function `f` if
// it returns non-nil error. It commits the transaction and returns nil if
-// function returns nil.
+// function `f` returns nil.
//
-// Note that, you should not Commit or Rollback the transaction in function
+// Note that, you should not Commit or Rollback the transaction in function `f`
// as it is automatically handled by this function.
func (c *Core) Transaction(f func(tx *TX) error) (err error) {
var tx *TX
- tx, err = c.DB.Begin()
+ tx, err = c.db.Begin()
if err != nil {
return err
}
@@ -438,12 +438,12 @@ func (c *Core) Transaction(f func(tx *TX) error) (err error) {
// Insert does "INSERT INTO ..." statement for the table.
// If there's already one unique record of the data in the table, it returns error.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter specifies the batch operation count when given data is slice.
+// The parameter `batch` specifies the batch operation count when given data is slice.
func (c *Core) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(data).Batch(batch[0]).Insert()
@@ -454,12 +454,12 @@ func (c *Core) Insert(table string, data interface{}, batch ...int) (sql.Result,
// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
// If there's already one unique record of the data in the table, it ignores the inserting.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter specifies the batch operation count when given data is slice.
+// The parameter `batch` specifies the batch operation count when given data is slice.
func (c *Core) InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(data).Batch(batch[0]).InsertIgnore()
@@ -471,14 +471,14 @@ func (c *Core) InsertIgnore(table string, data interface{}, batch ...int) (sql.R
// If there's already one unique record of the data in the table, it deletes the record
// and inserts a new one.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// If given data is type of slice, it then does batch replacing, and the optional parameter
-// specifies the batch operation count.
+// `batch` specifies the batch operation count.
func (c *Core) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(data).Batch(batch[0]).Replace()
@@ -490,13 +490,13 @@ func (c *Core) Replace(table string, data interface{}, batch ...int) (sql.Result
// It updates the record if there's primary or unique index in the saving data,
// or else it inserts a new record into the table.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
// If given data is type of slice, it then does batch saving, and the optional parameter
-// specifies the batch operation count.
+// `batch` specifies the batch operation count.
func (c *Core) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(data).Batch(batch[0]).Save()
@@ -506,18 +506,18 @@ func (c *Core) Save(table string, data interface{}, batch ...int) (sql.Result, e
// doInsert inserts or updates data for given table.
// This function is usually used for custom interface definition, you do not need call it manually.
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter values are as follows:
+// The parameter `option` values are as follows:
// 0: insert: just insert, if there's unique/primary key in the data, it returns error;
// 1: replace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;
// 2: save: if there's unique/primary key in the data, it updates it or else inserts a new one;
// 3: ignore: if there's unique/primary key in the data, it ignores the inserting;
func (c *Core) DoInsert(link Link, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
- table = c.DB.QuotePrefixTableName(table)
+ table = c.db.QuotePrefixTableName(table)
var (
fields []string
values []string
@@ -532,10 +532,10 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b
}
switch reflectKind {
case reflect.Slice, reflect.Array:
- return c.DB.DoBatchInsert(link, table, data, option, batch...)
+ return c.db.DoBatchInsert(link, table, data, option, batch...)
case reflect.Struct:
if _, ok := data.(apiInterfaces); ok {
- return c.DB.DoBatchInsert(link, table, data, option, batch...)
+ return c.db.DoBatchInsert(link, table, data, option, batch...)
} else {
dataMap = ConvertDataForTableRecord(data)
}
@@ -548,7 +548,7 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b
return nil, gerror.New("data cannot be empty")
}
var (
- charL, charR = c.DB.GetChars()
+ charL, charR = c.db.GetChars()
operation = GetInsertOperationByOption(option)
updateStr = ""
)
@@ -580,11 +580,11 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b
updateStr = fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", updateStr)
}
if link == nil {
- if link, err = c.DB.Master(); err != nil {
+ if link, err = c.db.Master(); err != nil {
return nil, err
}
}
- return c.DB.DoExec(
+ return c.db.DoExec(
link,
fmt.Sprintf(
"%s INTO %s(%s) VALUES(%s) %s",
@@ -596,7 +596,7 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b
}
// BatchInsert batch inserts data.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (c *Core) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(list).Batch(batch[0]).Insert()
@@ -605,7 +605,7 @@ func (c *Core) BatchInsert(table string, list interface{}, batch ...int) (sql.Re
}
// BatchInsertIgnore batch inserts data with ignore option.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (c *Core) BatchInsertIgnore(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(list).Batch(batch[0]).InsertIgnore()
@@ -614,7 +614,7 @@ func (c *Core) BatchInsertIgnore(table string, list interface{}, batch ...int) (
}
// BatchReplace batch replaces data.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (c *Core) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(list).Batch(batch[0]).Replace()
@@ -623,7 +623,7 @@ func (c *Core) BatchReplace(table string, list interface{}, batch ...int) (sql.R
}
// BatchSave batch replaces data.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (c *Core) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return c.Model(table).Data(list).Batch(batch[0]).Save()
@@ -634,7 +634,7 @@ func (c *Core) BatchSave(table string, list interface{}, batch ...int) (sql.Resu
// DoBatchInsert batch inserts/replaces/saves data.
// This function is usually used for custom interface definition, you do not need call it manually.
func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
- table = c.DB.QuotePrefixTableName(table)
+ table = c.db.QuotePrefixTableName(table)
var (
keys []string // Field names.
values []string // Value holder string array, like: (?,?,?)
@@ -689,7 +689,7 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i
return result, gerror.New("data list cannot be empty")
}
if link == nil {
- if link, err = c.DB.Master(); err != nil {
+ if link, err = c.db.Master(); err != nil {
return
}
}
@@ -699,7 +699,7 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i
}
// Prepare the batch result pointer.
var (
- charL, charR = c.DB.GetChars()
+ charL, charR = c.db.GetChars()
batchResult = new(SqlResult)
keysStr = charL + strings.Join(keys, charR+","+charL) + charR
operation = GetInsertOperationByOption(option)
@@ -745,7 +745,7 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i
}
valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")")
if len(valueHolder) == batchNum || (i == listMapLen-1 && len(valueHolder) > 0) {
- r, err := c.DB.DoExec(
+ r, err := c.db.DoExec(
link,
fmt.Sprintf(
"%s INTO %s(%s) VALUES%s %s",
@@ -773,11 +773,11 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i
// Update does "UPDATE ... " statement for the table.
//
-// The parameter can be type of string/map/gmap/struct/*struct, etc.
+// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.
// Eg: "uid=10000", "uid", 10000, g.Map{"uid": 10000, "name":"john"}
//
-// The parameter can be type of string/map/gmap/slice/struct/*struct, etc.
-// It is commonly used with parameter .
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
// Eg:
// "uid=10000",
// "uid", 10000
@@ -792,7 +792,7 @@ func (c *Core) Update(table string, data interface{}, condition interface{}, arg
// doUpdate does "UPDATE ... " statement for the table.
// This function is usually used for custom interface definition, you do not need call it manually.
func (c *Core) DoUpdate(link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
- table = c.DB.QuotePrefixTableName(table)
+ table = c.db.QuotePrefixTableName(table)
var (
rv = reflect.ValueOf(data)
kind = rv.Kind()
@@ -815,21 +815,21 @@ func (c *Core) DoUpdate(link Link, table string, data interface{}, condition str
switch value := v.(type) {
case *Counter:
if value.Value != 0 {
- column := c.DB.QuoteWord(value.Field)
+ column := c.db.QuoteWord(value.Field)
fields = append(fields, fmt.Sprintf("%s=%s+?", column, column))
params = append(params, value.Value)
}
case Counter:
if value.Value != 0 {
- column := c.DB.QuoteWord(value.Field)
+ column := c.db.QuoteWord(value.Field)
fields = append(fields, fmt.Sprintf("%s=%s+?", column, column))
params = append(params, value.Value)
}
default:
if s, ok := v.(Raw); ok {
- fields = append(fields, c.DB.QuoteWord(k)+"="+gconv.String(s))
+ fields = append(fields, c.db.QuoteWord(k)+"="+gconv.String(s))
} else {
- fields = append(fields, c.DB.QuoteWord(k)+"=?")
+ fields = append(fields, c.db.QuoteWord(k)+"=?")
params = append(params, v)
}
@@ -847,11 +847,11 @@ func (c *Core) DoUpdate(link Link, table string, data interface{}, condition str
}
// If no link passed, it then uses the master link.
if link == nil {
- if link, err = c.DB.Master(); err != nil {
+ if link, err = c.db.Master(); err != nil {
return nil, err
}
}
- return c.DB.DoExec(
+ return c.db.DoExec(
link,
fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition),
args...,
@@ -860,8 +860,8 @@ func (c *Core) DoUpdate(link Link, table string, data interface{}, condition str
// Delete does "DELETE FROM ... " statement for the table.
//
-// The parameter can be type of string/map/gmap/slice/struct/*struct, etc.
-// It is commonly used with parameter .
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
// Eg:
// "uid=10000",
// "uid", 10000
@@ -877,12 +877,12 @@ func (c *Core) Delete(table string, condition interface{}, args ...interface{})
// This function is usually used for custom interface definition, you do not need call it manually.
func (c *Core) DoDelete(link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) {
if link == nil {
- if link, err = c.DB.Master(); err != nil {
+ if link, err = c.db.Master(); err != nil {
return nil, err
}
}
- table = c.DB.QuotePrefixTableName(table)
- return c.DB.DoExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
+ table = c.db.QuotePrefixTableName(table)
+ return c.db.DoExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
}
// convertRowsToResult converts underlying data record type sql.Rows to Result type.
@@ -918,7 +918,7 @@ func (c *Core) convertRowsToResult(rows *sql.Rows) (Result, error) {
if value == nil {
row[columnNames[i]] = gvar.New(nil)
} else {
- row[columnNames[i]] = gvar.New(c.DB.convertFieldValueToLocalValue(value, columnTypes[i]))
+ row[columnNames[i]] = gvar.New(c.db.convertFieldValueToLocalValue(value, columnTypes[i]))
}
}
records = append(records, row)
@@ -944,15 +944,15 @@ func (c *Core) writeSqlToLogger(v *Sql) {
s := fmt.Sprintf("[%3d ms] [%s] %s", v.End-v.Start, v.Group, v.Format)
if v.Error != nil {
s += "\nError: " + v.Error.Error()
- c.logger.Ctx(c.DB.GetCtx()).Error(s)
+ c.logger.Ctx(c.db.GetCtx()).Error(s)
} else {
- c.logger.Ctx(c.DB.GetCtx()).Debug(s)
+ c.logger.Ctx(c.db.GetCtx()).Debug(s)
}
}
// HasTable determine whether the table name exists in the database.
func (c *Core) HasTable(name string) (bool, error) {
- tableList, err := c.DB.Tables()
+ tableList, err := c.db.Tables()
if err != nil {
return false, err
}
@@ -969,7 +969,7 @@ func (c *Core) isSoftCreatedFiledName(fieldName string) bool {
if fieldName == "" {
return false
}
- if config := c.DB.GetConfig(); config.CreatedAt != "" {
+ if config := c.db.GetConfig(); config.CreatedAt != "" {
if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) {
return true
}
diff --git a/database/gdb/gdb_core_config.go b/database/gdb/gdb_core_config.go
index 9f6a6aa4b..ab222cf44 100644
--- a/database/gdb/gdb_core_config.go
+++ b/database/gdb/gdb_core_config.go
@@ -152,7 +152,7 @@ func (c *Core) SetMaxOpenConnCount(n int) {
}
// SetMaxConnLifetime sets the connection TTL for underlying connection pool.
-// If parameter <= 0, it means the connection never expires.
+// If parameter `d` <= 0, it means the connection never expires.
func (c *Core) SetMaxConnLifetime(d time.Duration) {
c.config.MaxConnLifetime = d
}
diff --git a/database/gdb/gdb_core_structure.go b/database/gdb/gdb_core_structure.go
index 9458de0ab..de5b9e770 100644
--- a/database/gdb/gdb_core_structure.go
+++ b/database/gdb/gdb_core_structure.go
@@ -24,8 +24,8 @@ import (
// convertFieldValueToLocalValue automatically checks and converts field value from database type
// to golang variable type.
func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType string) interface{} {
- // If there's no type retrieved, it returns the directly
- // to use its original data type, as is type of interface{}.
+ // If there's no type retrieved, it returns the `fieldValue` directly
+ // to use its original data type, as `fieldValue` is type of interface{}.
if fieldType == "" {
return fieldValue
}
@@ -149,7 +149,7 @@ func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType s
// mappingAndFilterData automatically mappings the map key to table field and removes
// all key-value pairs that are not the field of given table.
func (c *Core) mappingAndFilterData(schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) {
- if fieldsMap, err := c.DB.TableFields(table, schema); err == nil {
+ if fieldsMap, err := c.db.TableFields(table, schema); err == nil {
fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
for k, _ := range fieldsMap {
fieldsKeyMap[k] = nil
@@ -182,7 +182,7 @@ func (c *Core) mappingAndFilterData(schema, table string, data map[string]interf
//func (c *Core) filterFields(schema, table string, data map[string]interface{}) map[string]interface{} {
// // It must use data copy here to avoid its changing the origin data map.
// newDataMap := make(map[string]interface{}, len(data))
-// if fields, err := c.DB.TableFields(table, schema); err == nil {
+// if fields, err := c.db.TableFields(table, schema); err == nil {
// for k, v := range data {
// if _, ok := fields[k]; ok {
// newDataMap[k] = v
diff --git a/database/gdb/gdb_core_tracing.go b/database/gdb/gdb_core_tracing.go
index 1ccfae3c7..08209931c 100644
--- a/database/gdb/gdb_core_tracing.go
+++ b/database/gdb/gdb_core_tracing.go
@@ -51,24 +51,24 @@ func (c *Core) addSqlToTracing(ctx context.Context, sql *Sql) {
labels := make([]label.KeyValue, 0)
labels = append(labels, gtrace.CommonLabels()...)
labels = append(labels,
- label.String(tracingAttrDbType, c.DB.GetConfig().Type),
+ label.String(tracingAttrDbType, c.db.GetConfig().Type),
)
- if c.DB.GetConfig().Host != "" {
- labels = append(labels, label.String(tracingAttrDbHost, c.DB.GetConfig().Host))
+ if c.db.GetConfig().Host != "" {
+ labels = append(labels, label.String(tracingAttrDbHost, c.db.GetConfig().Host))
}
- if c.DB.GetConfig().Port != "" {
- labels = append(labels, label.String(tracingAttrDbPort, c.DB.GetConfig().Port))
+ if c.db.GetConfig().Port != "" {
+ labels = append(labels, label.String(tracingAttrDbPort, c.db.GetConfig().Port))
}
- if c.DB.GetConfig().Name != "" {
- labels = append(labels, label.String(tracingAttrDbName, c.DB.GetConfig().Name))
+ if c.db.GetConfig().Name != "" {
+ labels = append(labels, label.String(tracingAttrDbName, c.db.GetConfig().Name))
}
- if c.DB.GetConfig().User != "" {
- labels = append(labels, label.String(tracingAttrDbUser, c.DB.GetConfig().User))
+ if c.db.GetConfig().User != "" {
+ labels = append(labels, label.String(tracingAttrDbUser, c.db.GetConfig().User))
}
- if filteredLinkInfo := c.DB.FilteredLinkInfo(); filteredLinkInfo != "" {
- labels = append(labels, label.String(tracingAttrDbLink, c.DB.FilteredLinkInfo()))
+ if filteredLinkInfo := c.db.FilteredLinkInfo(); filteredLinkInfo != "" {
+ labels = append(labels, label.String(tracingAttrDbLink, c.db.FilteredLinkInfo()))
}
- if group := c.DB.GetGroup(); group != "" {
+ if group := c.db.GetGroup(); group != "" {
labels = append(labels, label.String(tracingAttrDbGroup, group))
}
span.SetAttributes(labels...)
diff --git a/database/gdb/gdb_core_utility.go b/database/gdb/gdb_core_utility.go
index 70d1aec99..3528d873e 100644
--- a/database/gdb/gdb_core_utility.go
+++ b/database/gdb/gdb_core_utility.go
@@ -11,31 +11,31 @@ import (
"database/sql"
)
-// GetMaster acts like function Master but with additional parameter specifying
+// GetMaster acts like function Master but with additional `schema` parameter specifying
// the schema for the connection. It is defined for internal usage.
// Also see Master.
func (c *Core) GetMaster(schema ...string) (*sql.DB, error) {
return c.getSqlDb(true, schema...)
}
-// GetSlave acts like function Slave but with additional parameter specifying
+// GetSlave acts like function Slave but with additional `schema` parameter specifying
// the schema for the connection. It is defined for internal usage.
// Also see Slave.
func (c *Core) GetSlave(schema ...string) (*sql.DB, error) {
return c.getSqlDb(false, schema...)
}
-// QuoteWord checks given string a word, if true quotes it with security chars of the database
-// and returns the quoted string; or else return without any change.
+// QuoteWord checks given string `s` a word, if true quotes it with security chars of the database
+// and returns the quoted string; or else return `s` without any change.
func (c *Core) QuoteWord(s string) string {
- charLeft, charRight := c.DB.GetChars()
+ charLeft, charRight := c.db.GetChars()
return doQuoteWord(s, charLeft, charRight)
}
// QuoteString quotes string with quote chars. Strings like:
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
func (c *Core) QuoteString(s string) string {
- charLeft, charRight := c.DB.GetChars()
+ charLeft, charRight := c.db.GetChars()
return doQuoteString(s, charLeft, charRight)
}
@@ -49,8 +49,8 @@ func (c *Core) QuoteString(s string) string {
// Note that, this will automatically checks the table prefix whether already added,
// if true it does nothing to the table name, or else adds the prefix to the table name.
func (c *Core) QuotePrefixTableName(table string) string {
- charLeft, charRight := c.DB.GetChars()
- return doHandleTableName(table, c.DB.GetPrefix(), charLeft, charRight)
+ charLeft, charRight := c.db.GetChars()
+ return doHandleTableName(table, c.db.GetPrefix(), charLeft, charRight)
}
// GetChars returns the security char for current database.
diff --git a/database/gdb/gdb_driver_mssql.go b/database/gdb/gdb_driver_mssql.go
index c97387ca8..6ba855489 100644
--- a/database/gdb/gdb_driver_mssql.go
+++ b/database/gdb/gdb_driver_mssql.go
@@ -185,12 +185,12 @@ func (d *DriverMssql) parseSql(sql string) string {
// It's mainly used in cli tool chain for automatically generating the models.
func (d *DriverMssql) Tables(schema ...string) (tables []string, err error) {
var result Result
- link, err := d.DB.GetSlave(schema...)
+ link, err := d.db.GetSlave(schema...)
if err != nil {
return nil, err
}
- result, err = d.DB.DoGetAll(link, `SELECT NAME FROM SYSOBJECTS WHERE XTYPE='U' AND STATUS >= 0 ORDER BY NAME`)
+ result, err = d.db.DoGetAll(link, `SELECT NAME FROM SYSOBJECTS WHERE XTYPE='U' AND STATUS >= 0 ORDER BY NAME`)
if err != nil {
return
}
@@ -209,7 +209,7 @@ func (d *DriverMssql) TableFields(table string, schema ...string) (fields map[st
if gstr.Contains(table, " ") {
return nil, gerror.New("function TableFields supports only single table operations")
}
- checkSchema := d.DB.GetSchema()
+ checkSchema := d.db.GetSchema()
if len(schema) > 0 && schema[0] != "" {
checkSchema = schema[0]
}
@@ -220,7 +220,7 @@ func (d *DriverMssql) TableFields(table string, schema ...string) (fields map[st
result Result
link *sql.DB
)
- link, err = d.DB.GetSlave(checkSchema)
+ link, err = d.db.GetSlave(checkSchema)
if err != nil {
return nil, err
}
@@ -255,7 +255,7 @@ ORDER BY a.id,a.colorder`,
strings.ToUpper(table),
)
structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
- result, err = d.DB.DoGetAll(link, structureSql)
+ result, err = d.db.DoGetAll(link, structureSql)
if err != nil {
return nil, err
}
diff --git a/database/gdb/gdb_driver_mysql.go b/database/gdb/gdb_driver_mysql.go
index e2430a1cf..5ac100350 100644
--- a/database/gdb/gdb_driver_mysql.go
+++ b/database/gdb/gdb_driver_mysql.go
@@ -83,11 +83,11 @@ func (d *DriverMysql) HandleSqlBeforeCommit(link Link, sql string, args []interf
// It's mainly used in cli tool chain for automatically generating the models.
func (d *DriverMysql) Tables(schema ...string) (tables []string, err error) {
var result Result
- link, err := d.DB.GetSlave(schema...)
+ link, err := d.db.GetSlave(schema...)
if err != nil {
return nil, err
}
- result, err = d.DB.DoGetAll(link, `SHOW TABLES`)
+ result, err = d.db.DoGetAll(link, `SHOW TABLES`)
if err != nil {
return
}
@@ -125,13 +125,13 @@ func (d *DriverMysql) TableFields(table string, schema ...string) (fields map[st
result Result
link *sql.DB
)
- link, err = d.DB.GetSlave(checkSchema)
+ link, err = d.db.GetSlave(checkSchema)
if err != nil {
return nil, err
}
- result, err = d.DB.DoGetAll(
+ result, err = d.db.DoGetAll(
link,
- fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.DB.QuoteWord(table)),
+ fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.db.QuoteWord(table)),
)
if err != nil {
return nil, err
diff --git a/database/gdb/gdb_driver_oracle.go b/database/gdb/gdb_driver_oracle.go
index b33db9dc7..e0bac602f 100644
--- a/database/gdb/gdb_driver_oracle.go
+++ b/database/gdb/gdb_driver_oracle.go
@@ -49,7 +49,6 @@ func (d *DriverOracle) Open(config *ConfigNode) (*sql.DB, error) {
if config.LinkInfo != "" {
source = config.LinkInfo
} else {
- // 账号/密码@地址:端口/数据库名称
source = fmt.Sprintf(
"%s/%s@%s:%s/%s",
config.User, config.Pass, config.Host, config.Port, config.Name,
@@ -164,10 +163,10 @@ func (d *DriverOracle) parseSql(sql string) string {
// Tables retrieves and returns the tables of current schema.
// It's mainly used in cli tool chain for automatically generating the models.
-// Note that it ignores the parameter in oracle database, as it is not necessary.
+// Note that it ignores the parameter `schema` in oracle database, as it is not necessary.
func (d *DriverOracle) Tables(schema ...string) (tables []string, err error) {
var result Result
- result, err = d.DB.DoGetAll(nil, "SELECT TABLE_NAME FROM USER_TABLES ORDER BY TABLE_NAME")
+ result, err = d.db.DoGetAll(nil, "SELECT TABLE_NAME FROM USER_TABLES ORDER BY TABLE_NAME")
if err != nil {
return
}
@@ -186,7 +185,7 @@ func (d *DriverOracle) TableFields(table string, schema ...string) (fields map[s
if gstr.Contains(table, " ") {
return nil, gerror.New("function TableFields supports only single table operations")
}
- checkSchema := d.DB.GetSchema()
+ checkSchema := d.db.GetSchema()
if len(schema) > 0 && schema[0] != "" {
checkSchema = schema[0]
}
@@ -205,7 +204,7 @@ FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`,
strings.ToUpper(table),
)
structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
- result, err = d.DB.GetAll(structureSql)
+ result, err = d.db.GetAll(structureSql)
if err != nil {
return nil, err
}
@@ -231,7 +230,7 @@ func (d *DriverOracle) getTableUniqueIndex(table string) (fields map[string]map[
"table_unique_index_"+table,
func() (interface{}, error) {
res := (Result)(nil)
- res, err = d.DB.GetAll(fmt.Sprintf(`
+ res, err = d.db.GetAll(fmt.Sprintf(`
SELECT INDEX_NAME,COLUMN_NAME,CHAR_LENGTH FROM USER_IND_COLUMNS
WHERE TABLE_NAME = '%s'
AND INDEX_NAME IN(SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME='%s' AND UNIQUENESS='UNIQUE')
@@ -268,7 +267,7 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
}
switch kind {
case reflect.Slice, reflect.Array:
- return d.DB.DoBatchInsert(link, table, data, option, batch...)
+ return d.db.DoBatchInsert(link, table, data, option, batch...)
case reflect.Map:
fallthrough
case reflect.Struct:
@@ -303,7 +302,7 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
onStr = make([]string, 0)
updateStr = make([]string, 0)
)
- charL, charR := d.DB.GetChars()
+ charL, charR := d.db.GetChars()
for k, v := range dataMap {
k = strings.ToUpper(k)
@@ -327,7 +326,7 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
}
if link == nil {
- if link, err = d.DB.Master(); err != nil {
+ if link, err = d.db.Master(); err != nil {
return nil, err
}
}
@@ -342,10 +341,10 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
table, tableAlias1, strings.Join(subSqlStr, ","), tableAlias2,
strings.Join(onStr, "AND"), strings.Join(updateStr, ","), strings.Join(fields, ","), strings.Join(values, ","),
)
- return d.DB.DoExec(link, tmp, params...)
+ return d.db.DoExec(link, tmp, params...)
case insertOptionIgnore:
- return d.DB.DoExec(link,
+ return d.db.DoExec(link,
fmt.Sprintf(
"INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(%s(%s)) */ INTO %s(%s) VALUES(%s)",
table, strings.Join(indexes, ","), table, strings.Join(fields, ","), strings.Join(values, ","),
@@ -354,7 +353,7 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
}
}
- return d.DB.DoExec(
+ return d.db.DoExec(
link,
fmt.Sprintf(
"INSERT INTO %s(%s) VALUES(%s)",
@@ -406,7 +405,7 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
return result, gerror.New("empty data list")
}
if link == nil {
- if link, err = d.DB.Master(); err != nil {
+ if link, err = d.db.Master(); err != nil {
return
}
}
@@ -418,13 +417,13 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
}
var (
batchResult = new(SqlResult)
- charL, charR = d.DB.GetChars()
+ charL, charR = d.db.GetChars()
keyStr = charL + strings.Join(keys, charL+","+charR) + charR
valueHolderStr = strings.Join(holders, ",")
)
if option != insertOptionDefault {
for _, v := range listMap {
- r, err := d.DB.DoInsert(link, table, v, option, 1)
+ r, err := d.db.DoInsert(link, table, v, option, 1)
if err != nil {
return r, err
}
@@ -452,7 +451,7 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
values = append(values, valueHolderStr)
intoStr = append(intoStr, fmt.Sprintf(" INTO %s(%s) VALUES(%s) ", table, keyStr, valueHolderStr))
if len(intoStr) == batchNum {
- r, err := d.DB.DoExec(link, fmt.Sprintf("INSERT ALL %s SELECT * FROM DUAL", strings.Join(intoStr, " ")), params...)
+ r, err := d.db.DoExec(link, fmt.Sprintf("INSERT ALL %s SELECT * FROM DUAL", strings.Join(intoStr, " ")), params...)
if err != nil {
return r, err
}
@@ -468,7 +467,7 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
}
// The leftover data.
if len(intoStr) > 0 {
- r, err := d.DB.DoExec(link, fmt.Sprintf("INSERT ALL %s SELECT * FROM DUAL", strings.Join(intoStr, " ")), params...)
+ r, err := d.db.DoExec(link, fmt.Sprintf("INSERT ALL %s SELECT * FROM DUAL", strings.Join(intoStr, " ")), params...)
if err != nil {
return r, err
}
diff --git a/database/gdb/gdb_driver_pgsql.go b/database/gdb/gdb_driver_pgsql.go
index 64c6c7361..a047733a2 100644
--- a/database/gdb/gdb_driver_pgsql.go
+++ b/database/gdb/gdb_driver_pgsql.go
@@ -90,7 +90,7 @@ func (d *DriverPgsql) HandleSqlBeforeCommit(link Link, sql string, args []interf
// It's mainly used in cli tool chain for automatically generating the models.
func (d *DriverPgsql) Tables(schema ...string) (tables []string, err error) {
var result Result
- link, err := d.DB.GetSlave(schema...)
+ link, err := d.db.GetSlave(schema...)
if err != nil {
return nil, err
}
@@ -98,7 +98,7 @@ func (d *DriverPgsql) Tables(schema ...string) (tables []string, err error) {
if len(schema) > 0 && schema[0] != "" {
query = fmt.Sprintf("SELECT TABLENAME FROM PG_TABLES WHERE SCHEMANAME = '%s' ORDER BY TABLENAME", schema[0])
}
- result, err = d.DB.DoGetAll(link, query)
+ result, err = d.db.DoGetAll(link, query)
if err != nil {
return
}
@@ -118,7 +118,7 @@ func (d *DriverPgsql) TableFields(table string, schema ...string) (fields map[st
return nil, gerror.New("function TableFields supports only single table operations")
}
table, _ = gregex.ReplaceString("\"", "", table)
- checkSchema := d.DB.GetSchema()
+ checkSchema := d.db.GetSchema()
if len(schema) > 0 && schema[0] != "" {
checkSchema = schema[0]
}
@@ -129,7 +129,7 @@ func (d *DriverPgsql) TableFields(table string, schema ...string) (fields map[st
result Result
link *sql.DB
)
- link, err = d.DB.GetSlave(checkSchema)
+ link, err = d.db.GetSlave(checkSchema)
if err != nil {
return nil, err
}
@@ -141,7 +141,7 @@ ORDER BY a.attnum`,
strings.ToLower(table),
)
structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
- result, err = d.DB.DoGetAll(link, structureSql)
+ result, err = d.db.DoGetAll(link, structureSql)
if err != nil {
return nil, err
}
diff --git a/database/gdb/gdb_driver_sqlite.go b/database/gdb/gdb_driver_sqlite.go
index 22d5156c6..ed577217a 100644
--- a/database/gdb/gdb_driver_sqlite.go
+++ b/database/gdb/gdb_driver_sqlite.go
@@ -75,12 +75,12 @@ func (d *DriverSqlite) HandleSqlBeforeCommit(link Link, sql string, args []inter
// It's mainly used in cli tool chain for automatically generating the models.
func (d *DriverSqlite) Tables(schema ...string) (tables []string, err error) {
var result Result
- link, err := d.DB.GetSlave(schema...)
+ link, err := d.db.GetSlave(schema...)
if err != nil {
return nil, err
}
- result, err = d.DB.DoGetAll(link, `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`)
+ result, err = d.db.DoGetAll(link, `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`)
if err != nil {
return
}
@@ -99,7 +99,7 @@ func (d *DriverSqlite) TableFields(table string, schema ...string) (fields map[s
if gstr.Contains(table, " ") {
return nil, gerror.New("function TableFields supports only single table operations")
}
- checkSchema := d.DB.GetSchema()
+ checkSchema := d.db.GetSchema()
if len(schema) > 0 && schema[0] != "" {
checkSchema = schema[0]
}
@@ -110,11 +110,11 @@ func (d *DriverSqlite) TableFields(table string, schema ...string) (fields map[s
result Result
link *sql.DB
)
- link, err = d.DB.GetSlave(checkSchema)
+ link, err = d.db.GetSlave(checkSchema)
if err != nil {
return nil, err
}
- result, err = d.DB.DoGetAll(link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, table))
+ result, err = d.db.DoGetAll(link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, table))
if err != nil {
return nil, err
}
diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go
index 2b9076a3f..f36e17395 100644
--- a/database/gdb/gdb_func.go
+++ b/database/gdb/gdb_func.go
@@ -54,10 +54,11 @@ type apiTableName interface {
}
const (
- OrmTagForStruct = "orm"
- OrmTagForUnique = "unique"
- OrmTagForPrimary = "primary"
- metaDataNameForTable = "table"
+ OrmTagForStruct = "orm"
+ OrmTagForUnique = "unique"
+ OrmTagForPrimary = "primary"
+ OrmTagForTable = "table"
+ OrmTagForWith = "with"
)
var (
@@ -68,50 +69,62 @@ var (
structTagPriority = append([]string{OrmTagForStruct}, gconv.StructTagPriority...)
)
-// getTableNameFromObject retrieves and returns the table name from struct object.
-func getTableNameFromObject(object interface{}) string {
+// getTableNameFromOrmTag retrieves and returns the table name from struct object.
+func getTableNameFromOrmTag(object interface{}) string {
+ var tableName string
+ // Use the interface value.
if r, ok := object.(apiTableName); ok {
- // Use the interface value.
- return r.TableName()
- } else if table := gmeta.Get(object, metaDataNameForTable); !table.IsEmpty() {
- // User meta data tag "table".
- return table.String()
- } else {
- // Use the struct name of snake case.
+ tableName = r.TableName()
+ }
+ // User meta data tag "orm".
+ if tableName == "" {
+ if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {
+ match, _ := gregex.MatchString(
+ fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForTable),
+ ormTag.String(),
+ )
+ if len(match) > 1 {
+ tableName = match[1]
+ }
+ }
+ }
+ // Use the struct name of snake case.
+ if tableName == "" {
if t, err := structs.StructType(object); err != nil {
panic(err)
} else {
- return gstr.CaseSnakeFirstUpper(
+ tableName = gstr.CaseSnakeFirstUpper(
gstr.StrEx(t.String(), "."),
)
}
}
+ return tableName
}
-// ListItemValues retrieves and returns the elements of all item struct/map with key .
-// Note that the parameter should be type of slice which contains elements of map or struct,
+// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
// or else it returns an empty slice.
//
-// The parameter supports types like:
+// The parameter `list` supports types like:
// []map[string]interface{}
// []map[string]sub-map
// []struct
// []struct:sub-struct
-// Note that the sub-map/sub-struct makes sense only if the optional parameter is given.
+// Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.
// See gutil.ListItemValues.
func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) {
return gutil.ListItemValues(list, key, subKey...)
}
-// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key .
-// Note that the parameter should be type of slice which contains elements of map or struct,
+// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
// or else it returns an empty slice.
// See gutil.ListItemValuesUnique.
func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} {
return gutil.ListItemValuesUnique(list, key, subKey...)
}
-// GetInsertOperationByOption returns proper insert option with given parameter .
+// GetInsertOperationByOption returns proper insert option with given parameter `option`.
func GetInsertOperationByOption(option int) string {
var operator string
switch option {
@@ -128,7 +141,7 @@ func GetInsertOperationByOption(option int) string {
// ConvertDataForTableRecord is a very important function, which does converting for any data that
// will be inserted into table as a record.
//
-// The parameter should be type of *map/map/*struct/struct.
+// The parameter `obj` should be type of *map/map/*struct/struct.
// It supports inherit struct definition for struct.
func ConvertDataForTableRecord(value interface{}) map[string]interface{} {
var (
@@ -170,8 +183,8 @@ func ConvertDataForTableRecord(value interface{}) map[string]interface{} {
return data
}
-// DataToMapDeep converts to map type recursively.
-// The parameter should be type of *map/map/*struct/struct.
+// DataToMapDeep converts `value` to map type recursively.
+// The parameter `value` should be type of *map/map/*struct/struct.
// It supports inherit struct definition for struct.
func DataToMapDeep(value interface{}) map[string]interface{} {
if v, ok := value.(apiMapStrAny); ok {
@@ -193,7 +206,7 @@ func DataToMapDeep(value interface{}) map[string]interface{} {
rvValue = rvValue.Elem()
rvKind = rvValue.Kind()
}
- // If given is not a struct, it uses gconv.Map for converting.
+ // If given `value` is not a struct, it uses gconv.Map for converting.
if rvKind != reflect.Struct {
return gconv.Map(value, structTagPriority...)
}
@@ -302,8 +315,8 @@ func doHandleTableName(table, prefix, charLeft, charRight string) string {
return gstr.Join(array1, ",")
}
-// doQuoteWord checks given string a word, if true quotes it with and
-// and returns the quoted string; or else returns without any change.
+// doQuoteWord checks given string `s` a word, if true quotes it with `charLeft` and `charRight`
+// and returns the quoted string; or else returns `s` without any change.
func doQuoteWord(s, charLeft, charRight string) string {
if quoteWordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
return charLeft + s + charRight
@@ -350,13 +363,13 @@ func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interf
for _, field := range tagField {
array = strings.Split(field.TagValue, ",")
if len(array) > 1 && gstr.InArray([]string{OrmTagForUnique, OrmTagForPrimary}, array[1]) {
- return array[0], []interface{}{field.Value()}, nil
+ return array[0], []interface{}{field.Value.Interface()}, nil
}
if len(where) > 0 {
where += " AND "
}
where += field.TagValue + "=?"
- args = append(args, field.Value())
+ args = append(args, field.Value.Interface())
}
return
}
@@ -378,7 +391,7 @@ func GetPrimaryKey(pointer interface{}) (string, error) {
}
// GetPrimaryKeyCondition returns a new where condition by primary field name.
-// The optional parameter is like follows:
+// The optional parameter `where` is like follows:
// 123 => primary=123
// []int{1, 2, 3} => primary IN(1,2,3)
// "john" => primary='john'
@@ -387,8 +400,8 @@ func GetPrimaryKey(pointer interface{}) (string, error) {
// g.Map{"id": 1, "name": "john"} => id=1 AND name='john'
// etc.
//
-// Note that it returns the given parameter directly if the is empty
-// or length of > 1.
+// Note that it returns the given `where` parameter directly if the `primary` is empty
+// or length of `where` > 1.
func GetPrimaryKeyCondition(primary string, where ...interface{}) (newWhereCondition []interface{}) {
if len(where) == 0 {
return nil
@@ -407,7 +420,7 @@ func GetPrimaryKeyCondition(primary string, where ...interface{}) (newWhereCondi
}
switch kind {
case reflect.Map, reflect.Struct:
- // Ignore the parameter .
+ // Ignore the parameter `primary`.
break
default:
@@ -454,7 +467,7 @@ func formatWhere(db DB, where interface{}, args []interface{}, omitEmpty bool) (
}
case reflect.Struct:
- // If struct implements apiIterator interface,
+ // If `where` struct implements apiIterator interface,
// it then uses its Iterate function to iterates its key-value pairs.
// For example, ListMap and TreeMap are ordered map,
// which implement apiIterator interface and are index-friendly for where conditions.
@@ -517,7 +530,7 @@ func formatWhere(db DB, where interface{}, args []interface{}, omitEmpty bool) (
return handleArguments(newWhere, newArgs)
}
-// formatWhereInterfaces formats as []interface{}.
+// formatWhereInterfaces formats `where` as []interface{}.
func formatWhereInterfaces(db DB, where []interface{}, buffer *bytes.Buffer, newArgs []interface{}) []interface{} {
if len(where) == 0 {
return newArgs
@@ -771,8 +784,8 @@ func FormatSqlWithArgs(sql string, args []interface{}) string {
return newQuery
}
-// convertMapToStruct maps the to given struct.
-// Note that the given parameter should be a pointer to s struct.
+// convertMapToStruct maps the `data` to given struct.
+// Note that the given parameter `pointer` should be a pointer to s struct.
func convertMapToStruct(data map[string]interface{}, pointer interface{}) error {
tagNameMap, err := structs.TagMapName(pointer, []string{OrmTagForStruct})
if err != nil {
diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go
index 48bea10b0..99333dede 100644
--- a/database/gdb/gdb_model.go
+++ b/database/gdb/gdb_model.go
@@ -54,29 +54,26 @@ type whereHolder struct {
}
const (
- // Deprecated, use OptionOmitEmpty instead.
- OPTION_OMITEMPTY = 1
- // Deprecated, use OptionAllowEmpty instead..
- OPTION_ALLOWEMPTY = 2
-
- OptionOmitEmpty = 1
- OptionAllowEmpty = 2
- linkTypeMaster = 1
- linkTypeSlave = 2
- whereHolderWhere = 1
- whereHolderAnd = 2
- whereHolderOr = 3
+ OPTION_OMITEMPTY = 1 // Deprecated, use OptionOmitEmpty instead.
+ OPTION_ALLOWEMPTY = 2 // Deprecated, use OptionAllowEmpty instead.
+ OptionOmitEmpty = 1
+ OptionAllowEmpty = 2
+ linkTypeMaster = 1
+ linkTypeSlave = 2
+ whereHolderWhere = 1
+ whereHolderAnd = 2
+ whereHolderOr = 3
)
// Table is alias of Core.Model.
// See Core.Model.
// Deprecated, use Model instead.
func (c *Core) Table(table ...string) *Model {
- return c.DB.Model(table...)
+ return c.db.Model(table...)
}
// Model creates and returns a new ORM model from given schema.
-// The parameter can be more than one table names, and also alias name, like:
+// The parameter `table` can be more than one table names, and also alias name, like:
// 1. Model names:
// Model("user")
// Model("user u")
@@ -87,13 +84,13 @@ func (c *Core) Model(table ...string) *Model {
tables := ""
if len(table) > 1 {
tables = fmt.Sprintf(
- `%s AS %s`, c.DB.QuotePrefixTableName(table[0]), c.DB.QuoteWord(table[1]),
+ `%s AS %s`, c.db.QuotePrefixTableName(table[0]), c.db.QuoteWord(table[1]),
)
} else if len(table) == 1 {
- tables = c.DB.QuotePrefixTableName(table[0])
+ tables = c.db.QuotePrefixTableName(table[0])
}
return &Model{
- db: c.DB,
+ db: c.db,
tablesInit: tables,
tables: tables,
fields: "*",
@@ -103,6 +100,11 @@ func (c *Core) Model(table ...string) *Model {
}
}
+// With creates and returns an ORM model based on meta data of given object.
+func (c *Core) With(object interface{}) *Model {
+ return c.db.Model().With(object)
+}
+
// Table is alias of tx.Model.
// Deprecated, use Model instead.
func (tx *TX) Table(table ...string) *Model {
@@ -118,6 +120,12 @@ func (tx *TX) Model(table ...string) *Model {
return model
}
+// With acts like Core.With except it operates on transaction.
+// See Core.With.
+func (tx *TX) With(object interface{}) *Model {
+ return tx.Model().With(object)
+}
+
// Ctx sets the context for current operation.
func (m *Model) Ctx(ctx context.Context) *Model {
if ctx == nil {
diff --git a/database/gdb/gdb_model_cache.go b/database/gdb/gdb_model_cache.go
index 376e02c55..0529bf5f6 100644
--- a/database/gdb/gdb_model_cache.go
+++ b/database/gdb/gdb_model_cache.go
@@ -14,13 +14,13 @@ import (
// if there's another same sql request, it just reads and returns the result from cache, it
// but not committed and executed into the database.
//
-// If the parameter < 0, which means it clear the cache with given .
-// If the parameter = 0, which means it never expires.
-// If the parameter > 0, which means it expires after .
+// If the parameter `duration` < 0, which means it clear the cache with given `name`.
+// If the parameter `duration` = 0, which means it never expires.
+// If the parameter `duration` > 0, which means it expires after `duration`.
//
-// The optional parameter is used to bind a name to the cache, which means you can
-// later control the cache like changing the or clearing the cache with specified
-// .
+// The optional parameter `name` is used to bind a name to the cache, which means you can
+// later control the cache like changing the `duration` or clearing the cache with specified
+// `name`.
//
// Note that, the cache feature is disabled if the model is performing select statement
// on a transaction.
diff --git a/database/gdb/gdb_model_condition.go b/database/gdb/gdb_model_condition.go
index 832508017..e95c284b6 100644
--- a/database/gdb/gdb_model_condition.go
+++ b/database/gdb/gdb_model_condition.go
@@ -10,7 +10,7 @@ import (
"strings"
)
-// Where sets the condition statement for the model. The parameter can be type of
+// Where sets the condition statement for the model. The parameter `where` can be type of
// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
// multiple conditions will be joined into where statement using "AND".
// Eg:
@@ -45,9 +45,9 @@ func (m *Model) Having(having interface{}, args ...interface{}) *Model {
return model
}
-// WherePri does the same logic as Model.Where except that if the parameter
+// WherePri does the same logic as Model.Where except that if the parameter `where`
// is a single condition like int/string/float/slice, it treats the condition as the primary
-// key value. That is, if primary key is "id" and given parameter as "123", the
+// key value. That is, if primary key is "id" and given `where` parameter as "123", the
// WherePri function treats the condition as "id=123", but Model.Where treats the condition
// as string "123".
func (m *Model) WherePri(where interface{}, args ...interface{}) *Model {
@@ -115,7 +115,7 @@ func (m *Model) OrderBy(orderBy string) *Model {
}
// Limit sets the "LIMIT" statement for the model.
-// The parameter can be either one or two number, if passed two number is passed,
+// The parameter `limit` can be either one or two number, if passed two number is passed,
// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
// statement.
func (m *Model) Limit(limit ...int) *Model {
@@ -139,7 +139,7 @@ func (m *Model) Offset(offset int) *Model {
}
// Page sets the paging number for the model.
-// The parameter is started from 1 for paging.
+// The parameter `page` is started from 1 for paging.
// Note that, it differs that the Limit function starts from 0 for "LIMIT" statement.
func (m *Model) Page(page, limit int) *Model {
model := m.getModel()
diff --git a/database/gdb/gdb_model_delete.go b/database/gdb/gdb_model_delete.go
index 9db70dedc..4c56cdcd4 100644
--- a/database/gdb/gdb_model_delete.go
+++ b/database/gdb/gdb_model_delete.go
@@ -15,7 +15,7 @@ import (
)
// Delete does "DELETE FROM ... " statement for the model.
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) {
if len(where) > 0 {
diff --git a/database/gdb/gdb_model_fields.go b/database/gdb/gdb_model_fields.go
index abf3e76cf..6ec438a67 100644
--- a/database/gdb/gdb_model_fields.go
+++ b/database/gdb/gdb_model_fields.go
@@ -26,7 +26,7 @@ func (m *Model) Filter() *Model {
}
// Fields sets the operation fields of the model, multiple fields joined using char ','.
-// The parameter can be type of string/map/*map/struct/*struct.
+// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.
func (m *Model) Fields(fieldNamesOrMapStruct ...interface{}) *Model {
length := len(fieldNamesOrMapStruct)
if length == 0 {
@@ -56,7 +56,7 @@ func (m *Model) Fields(fieldNamesOrMapStruct ...interface{}) *Model {
// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
// Note that this function supports only single table operations.
-// The parameter can be type of string/map/*map/struct/*struct.
+// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.
func (m *Model) FieldsEx(fieldNamesOrMapStruct ...interface{}) *Model {
length := len(fieldNamesOrMapStruct)
if length == 0 {
@@ -88,7 +88,7 @@ func (m *Model) FieldsStr(prefix ...string) string {
}
// FieldsStr retrieves and returns all fields from the table, joined with char ','.
-// The optional parameter specifies the prefix for each field, eg: FieldsStr("u.").
+// The optional parameter `prefix` specifies the prefix for each field, eg: FieldsStr("u.").
func (m *Model) GetFieldsStr(prefix ...string) string {
prefixStr := ""
if len(prefix) > 0 {
@@ -122,10 +122,10 @@ func (m *Model) FieldsExStr(fields string, prefix ...string) string {
return m.GetFieldsExStr(fields, prefix...)
}
-// FieldsExStr retrieves and returns fields which are not in parameter from the table,
+// FieldsExStr retrieves and returns fields which are not in parameter `fields` from the table,
// joined with char ','.
-// The parameter specifies the fields that are excluded.
-// The optional parameter specifies the prefix for each field, eg: FieldsExStr("id", "u.").
+// The parameter `fields` specifies the fields that are excluded.
+// The optional parameter `prefix` specifies the prefix for each field, eg: FieldsExStr("id", "u.").
func (m *Model) GetFieldsExStr(fields string, prefix ...string) string {
prefixStr := ""
if len(prefix) > 0 {
diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go
index 4eca381f3..b0959d304 100644
--- a/database/gdb/gdb_model_insert.go
+++ b/database/gdb/gdb_model_insert.go
@@ -24,7 +24,7 @@ func (m *Model) Batch(batch int) *Model {
}
// Data sets the operation data for the model.
-// The parameter can be type of string/map/gmap/slice/struct/*struct, etc.
+// The parameter `data` can be type of string/map/gmap/slice/struct/*struct, etc.
// Note that, it uses shallow value copying for `data` if `data` is type of map/slice
// to avoid changing it inside function.
// Eg:
@@ -100,7 +100,7 @@ func (m *Model) Data(data ...interface{}) *Model {
}
// Insert does "INSERT INTO ..." statement for the model.
-// The optional parameter is the same as the parameter of Model.Data function,
+// The optional parameter `data` is the same as the parameter of Model.Data function,
// see Model.Data.
func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) {
if len(data) > 0 {
@@ -110,7 +110,7 @@ func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) {
}
// InsertIgnore does "INSERT IGNORE INTO ..." statement for the model.
-// The optional parameter is the same as the parameter of Model.Data function,
+// The optional parameter `data` is the same as the parameter of Model.Data function,
// see Model.Data.
func (m *Model) InsertIgnore(data ...interface{}) (result sql.Result, err error) {
if len(data) > 0 {
@@ -120,7 +120,7 @@ func (m *Model) InsertIgnore(data ...interface{}) (result sql.Result, err error)
}
// Replace does "REPLACE INTO ..." statement for the model.
-// The optional parameter is the same as the parameter of Model.Data function,
+// The optional parameter `data` is the same as the parameter of Model.Data function,
// see Model.Data.
func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
if len(data) > 0 {
@@ -130,7 +130,7 @@ func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
}
// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model.
-// The optional parameter is the same as the parameter of Model.Data function,
+// The optional parameter `data` is the same as the parameter of Model.Data function,
// see Model.Data.
//
// It updates the record if there's primary or unique index in the saving data,
diff --git a/database/gdb/gdb_model_join.go b/database/gdb/gdb_model_join.go
index 1eebb7eb1..847c11abd 100644
--- a/database/gdb/gdb_model_join.go
+++ b/database/gdb/gdb_model_join.go
@@ -23,7 +23,7 @@ func isSubQuery(s string) bool {
}
// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
-// The parameter can be joined table and its joined condition,
+// The parameter `table` can be joined table and its joined condition,
// and also with its alias name, like:
// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
@@ -33,7 +33,7 @@ func (m *Model) LeftJoin(table ...string) *Model {
}
// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
-// The parameter can be joined table and its joined condition,
+// The parameter `table` can be joined table and its joined condition,
// and also with its alias name, like:
// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
@@ -43,7 +43,7 @@ func (m *Model) RightJoin(table ...string) *Model {
}
// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
-// The parameter can be joined table and its joined condition,
+// The parameter `table` can be joined table and its joined condition,
// and also with its alias name, like:
// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
@@ -53,7 +53,7 @@ func (m *Model) InnerJoin(table ...string) *Model {
}
// doJoin does "LEFT/RIGHT/INNER JOIN ... ON ..." statement on the model.
-// The parameter can be joined table and its joined condition,
+// The parameter `table` can be joined table and its joined condition,
// and also with its alias name, like:
// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go
index 3f4ad8723..ed392b6c7 100644
--- a/database/gdb/gdb_model_select.go
+++ b/database/gdb/gdb_model_select.go
@@ -28,7 +28,7 @@ func (m *Model) Select(where ...interface{}) (Result, error) {
// It retrieves the records from table and returns the result as slice type.
// It returns nil if there's no record retrieved with the given conditions from table.
//
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
func (m *Model) All(where ...interface{}) (Result, error) {
return m.doGetAll(false, where...)
@@ -38,8 +38,8 @@ func (m *Model) All(where ...interface{}) (Result, error) {
// It retrieves the records from table and returns the result as slice type.
// It returns nil if there's no record retrieved with the given conditions from table.
//
-// The parameter specifies whether limits querying only one record if m.limit is not set.
-// The optional parameter is the same as the parameter of Model.Where function,
+// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
func (m *Model) doGetAll(limit1 bool, where ...interface{}) (Result, error) {
if len(where) > 0 {
@@ -139,7 +139,7 @@ func (m *Model) Chunk(limit int, callback func(result Result, err error) bool) {
// One retrieves one record from table and returns the result as map type.
// It returns nil if there's no record retrieved with the given conditions from table.
//
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
func (m *Model) One(where ...interface{}) (Record, error) {
if len(where) > 0 {
@@ -158,7 +158,7 @@ func (m *Model) One(where ...interface{}) (Record, error) {
// Value retrieves a specified record value from table and returns the result as interface type.
// It returns nil if there's no record found with the given conditions from table.
//
-// If the optional parameter is given, the fieldsAndWhere[0] is the selected fields
+// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
// and fieldsAndWhere[1:] is treated as where condition fields.
// Also see Model.Fields and Model.Where functions.
func (m *Model) Value(fieldsAndWhere ...interface{}) (Value, error) {
@@ -184,7 +184,7 @@ func (m *Model) Value(fieldsAndWhere ...interface{}) (Value, error) {
// Array queries and returns data values as slice from database.
// Note that if there're multiple columns in the result, it returns just one column values randomly.
//
-// If the optional parameter is given, the fieldsAndWhere[0] is the selected fields
+// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
// and fieldsAndWhere[1:] is treated as where condition fields.
// Also see Model.Fields and Model.Where functions.
func (m *Model) Array(fieldsAndWhere ...interface{}) ([]Value, error) {
@@ -205,14 +205,14 @@ func (m *Model) Array(fieldsAndWhere ...interface{}) ([]Value, error) {
}
// Struct retrieves one record from table and converts it into given struct.
-// The parameter should be type of *struct/**struct. If type **struct is given,
+// The parameter `pointer` should be type of *struct/**struct. If type **struct is given,
// it can create the struct internally during converting.
//
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
//
// Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions
-// from table and is not nil.
+// from table and `pointer` is not nil.
//
// Eg:
// user := new(User)
@@ -225,18 +225,21 @@ func (m *Model) Struct(pointer interface{}, where ...interface{}) error {
if err != nil {
return err
}
- return one.Struct(pointer)
+ if err = one.Struct(pointer); err != nil {
+ return err
+ }
+ return m.doWithScan(pointer)
}
// Structs retrieves records from table and converts them into given struct slice.
-// The parameter should be type of *[]struct/*[]*struct. It can create and fill the struct
+// The parameter `pointer` should be type of *[]struct/*[]*struct. It can create and fill the struct
// slice internally during converting.
//
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
//
// Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions
-// from table and is not empty.
+// from table and `pointer` is not empty.
//
// Eg:
// users := ([]User)(nil)
@@ -252,11 +255,11 @@ func (m *Model) Structs(pointer interface{}, where ...interface{}) error {
return all.Structs(pointer)
}
-// Scan automatically calls Struct or Structs function according to the type of parameter .
-// It calls function Struct if is type of *struct/**struct.
-// It calls function Structs if is type of *[]struct/*[]*struct.
+// Scan automatically calls Struct or Structs function according to the type of parameter `pointer`.
+// It calls function Struct if `pointer` is type of *struct/**struct.
+// It calls function Structs if `pointer` is type of *[]struct/*[]*struct.
//
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
//
// Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions
@@ -275,21 +278,20 @@ func (m *Model) Structs(pointer interface{}, where ...interface{}) error {
// users := ([]*User)(nil)
// err := db.Model("user").Scan(&users)
func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
- t := reflect.TypeOf(pointer)
- k := t.Kind()
- if k != reflect.Ptr {
- return fmt.Errorf("params should be type of pointer, but got: %v", k)
+ var reflectType reflect.Type
+ if v, ok := pointer.(reflect.Value); ok {
+ reflectType = v.Type()
+ } else {
+ reflectType = reflect.TypeOf(pointer)
}
- switch t.Elem().Kind() {
- case reflect.Array, reflect.Slice:
+ if gstr.Contains(reflectType.String(), "[]") {
return m.Structs(pointer, where...)
- default:
- return m.Struct(pointer, where...)
}
+ return m.Struct(pointer, where...)
}
-// ScanList converts to struct slice which contains other complex struct attributes.
-// Note that the parameter should be type of *[]struct/*[]*struct.
+// ScanList converts `r` to struct slice which contains other complex struct attributes.
+// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
// Usage example:
//
// type Entity struct {
@@ -307,7 +309,7 @@ func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
// The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct
// that current result will be bound to.
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
-// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given
+// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given `relation`
// parameter.
// See the example or unit testing cases for clear understanding for this function.
func (m *Model) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) {
@@ -319,7 +321,7 @@ func (m *Model) ScanList(listPointer interface{}, attributeName string, relation
}
// Count does "SELECT COUNT(x) FROM ..." statement for the model.
-// The optional parameter is the same as the parameter of Model.Where function,
+// The optional parameter `where` is the same as the parameter of Model.Where function,
// see Model.Where.
func (m *Model) Count(where ...interface{}) (int, error) {
if len(where) > 0 {
diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go
index 3d7b2f0a6..b1f15ff62 100644
--- a/database/gdb/gdb_model_update.go
+++ b/database/gdb/gdb_model_update.go
@@ -19,7 +19,7 @@ import (
// Update does "UPDATE ... " statement for the model.
//
-// If the optional parameter is given, the dataAndWhere[0] is the updated data field,
+// If the optional parameter `dataAndWhere` is given, the dataAndWhere[0] is the updated data field,
// and dataAndWhere[1:] is treated as where condition fields.
// Also see Model.Data and Model.Where functions.
func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
diff --git a/database/gdb/gdb_model_utility.go b/database/gdb/gdb_model_utility.go
index 2b93696ff..716db7a30 100644
--- a/database/gdb/gdb_model_utility.go
+++ b/database/gdb/gdb_model_utility.go
@@ -18,7 +18,7 @@ import (
"time"
)
-// getModel creates and returns a cloned model of current model if is true, or else it returns
+// getModel creates and returns a cloned model of current model if `safe` is true, or else it returns
// the current model.
func (m *Model) getModel() *Model {
if !m.safe {
@@ -147,8 +147,8 @@ func (m *Model) doMappingAndFilterForInsertOrUpdateDataMap(data Map, allowOmitEm
return data, nil
}
-// getLink returns the underlying database link object with configured attribute.
-// The parameter specifies whether using the master node if master-slave configured.
+// getLink returns the underlying database link object with configured `linkType` attribute.
+// The parameter `master` specifies whether using the master node if master-slave configured.
func (m *Model) getLink(master bool) Link {
if m.tx != nil {
return m.tx.tx
@@ -196,9 +196,9 @@ func (m *Model) getPrimaryKey() string {
}
// formatCondition formats where arguments of the model and returns a new condition sql and its arguments.
-// Note that this function does not change any attribute value of the .
+// Note that this function does not change any attribute value of the `m`.
//
-// The parameter specifies whether limits querying only one record if m.limit is not set.
+// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWhere string, conditionExtra string, conditionArgs []interface{}) {
if len(m.whereHolder) > 0 {
for _, v := range m.whereHolder {
@@ -302,7 +302,7 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
return
}
-// mergeArguments creates and returns new arguments by merging and given .
+// mergeArguments creates and returns new arguments by merging and given `args`.
func (m *Model) mergeArguments(args []interface{}) []interface{} {
if len(m.extraArgs) > 0 {
newArgs := make([]interface{}, len(m.extraArgs)+len(args))
diff --git a/database/gdb/gdb_model_with.go b/database/gdb/gdb_model_with.go
index ec6764585..b31036c75 100644
--- a/database/gdb/gdb_model_with.go
+++ b/database/gdb/gdb_model_with.go
@@ -6,12 +6,90 @@
package gdb
+import (
+ "fmt"
+ "github.com/gogf/gf/errors/gerror"
+ "github.com/gogf/gf/internal/structs"
+ "github.com/gogf/gf/internal/utils"
+ "github.com/gogf/gf/text/gregex"
+ "github.com/gogf/gf/text/gstr"
+)
+
func (m *Model) With(structAttrPointer interface{}) *Model {
model := m.getModel()
if m.tables == "" {
- m.tables = getTableNameFromObject(structAttrPointer)
+ m.tables = m.db.QuotePrefixTableName(getTableNameFromOrmTag(structAttrPointer))
return model
}
model.withArray = append(model.withArray, structAttrPointer)
return model
}
+
+func (m *Model) doWithScan(pointer interface{}) error {
+ if len(m.withArray) == 0 {
+ return nil
+ }
+ fieldMap, err := structs.FieldMap(pointer, nil)
+ if err != nil {
+ return err
+ }
+ for _, withItem := range m.withArray {
+ withItemReflectValueType, err := structs.StructType(withItem)
+ if err != nil {
+ return err
+ }
+ withItemReflectValueTypeStr := gstr.TrimAll(withItemReflectValueType.String(), "*[]")
+ for _, fieldValue := range fieldMap {
+ var (
+ fieldType = fieldValue.Type()
+ fieldTypeStr = gstr.TrimAll(fieldType.String(), "*[]")
+ )
+ if gstr.Compare(fieldTypeStr, withItemReflectValueTypeStr) == 0 {
+ var (
+ withTag string
+ ormTag = fieldValue.Tag(OrmTagForStruct)
+ match, _ = gregex.MatchString(
+ fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForWith),
+ ormTag,
+ )
+ )
+ if len(match) > 1 {
+ withTag = match[1]
+ }
+ if withTag == "" {
+ continue
+ }
+ array := gstr.SplitAndTrim(withTag, "=")
+ if len(array) != 2 {
+ return gerror.Newf(`invalid with tag "%s"`, withTag)
+ }
+ var (
+ relatedFieldName = array[0]
+ relatedAttrName = array[1]
+ relatedFieldValue interface{}
+ )
+ // Find the value of related attribute from `pointer`.
+ for attributeName, attributeValue := range fieldMap {
+ if utils.EqualFoldWithoutChars(attributeName, relatedAttrName) {
+ relatedFieldValue = attributeValue.Value.Interface()
+ break
+ }
+ }
+ if relatedFieldValue == nil {
+ return gerror.Newf(
+ `cannot find the related value for attribute name "%s" of with tag "%s"`,
+ relatedAttrName, withTag,
+ )
+ }
+ err = m.db.With(fieldValue.Value).
+ Fields(withItemReflectValueType.FieldKeys()).
+ Where(relatedFieldName, relatedFieldValue).
+ Scan(fieldValue.Value)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/database/gdb/gdb_schema.go b/database/gdb/gdb_schema.go
index 6f520fa81..c7f5fb2a7 100644
--- a/database/gdb/gdb_schema.go
+++ b/database/gdb/gdb_schema.go
@@ -16,7 +16,7 @@ type Schema struct {
// Schema creates and returns a schema.
func (c *Core) Schema(schema string) *Schema {
return &Schema{
- db: c.DB,
+ db: c.db,
schema: schema,
}
}
@@ -31,7 +31,7 @@ func (tx *TX) Schema(schema string) *Schema {
}
// Table creates and returns a new ORM model.
-// The parameter can be more than one table names, like :
+// The parameter `tables` can be more than one table names, like :
// "user", "user u", "user, user_detail", "user u, user_detail ud"
func (s *Schema) Table(table string) *Model {
var m *Model
diff --git a/database/gdb/gdb_statement.go b/database/gdb/gdb_statement.go
index d861141fd..e856ba0b0 100644
--- a/database/gdb/gdb_statement.go
+++ b/database/gdb/gdb_statement.go
@@ -69,11 +69,11 @@ func (s *Stmt) doStmtCommit(stmtType string, ctx context.Context, args ...interf
Error: err,
Start: timestampMilli1,
End: timestampMilli2,
- Group: s.core.DB.GetGroup(),
+ Group: s.core.db.GetGroup(),
}
)
s.core.addSqlToTracing(ctx, sqlObj)
- if s.core.DB.GetDebug() {
+ if s.core.db.GetDebug() {
s.core.writeSqlToLogger(sqlObj)
}
return result, err
diff --git a/database/gdb/gdb_transaction.go b/database/gdb/gdb_transaction.go
index d59114d2b..5f4a35f79 100644
--- a/database/gdb/gdb_transaction.go
+++ b/database/gdb/gdb_transaction.go
@@ -75,7 +75,7 @@ func (tx *TX) GetOne(sql string, args ...interface{}) (Record, error) {
}
// GetStruct queries one record from database and converts it to given struct.
-// The parameter should be a pointer to struct.
+// The parameter `pointer` should be a pointer to struct.
func (tx *TX) GetStruct(obj interface{}, sql string, args ...interface{}) error {
one, err := tx.GetOne(sql, args...)
if err != nil {
@@ -85,7 +85,7 @@ func (tx *TX) GetStruct(obj interface{}, sql string, args ...interface{}) error
}
// GetStructs queries records from database and converts them to given struct.
-// The parameter should be type of struct slice: []struct/[]*struct.
+// The parameter `pointer` should be type of struct slice: []struct/[]*struct.
func (tx *TX) GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error {
all, err := tx.GetAll(sql, args...)
if err != nil {
@@ -97,8 +97,8 @@ func (tx *TX) GetStructs(objPointerSlice interface{}, sql string, args ...interf
// GetScan queries one or more records from database and converts them to given struct or
// struct array.
//
-// If parameter is type of struct pointer, it calls GetStruct internally for
-// the conversion. If parameter is type of slice, it calls GetStructs internally
+// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for
+// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
// for conversion.
func (tx *TX) GetScan(objPointer interface{}, sql string, args ...interface{}) error {
t := reflect.TypeOf(objPointer)
@@ -146,12 +146,12 @@ func (tx *TX) GetCount(sql string, args ...interface{}) (int, error) {
// Insert does "INSERT INTO ..." statement for the table.
// If there's already one unique record of the data in the table, it returns error.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter specifies the batch operation count when given data is slice.
+// The parameter `batch` specifies the batch operation count when given data is slice.
func (tx *TX) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(data).Batch(batch[0]).Insert()
@@ -162,12 +162,12 @@ func (tx *TX) Insert(table string, data interface{}, batch ...int) (sql.Result,
// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
// If there's already one unique record of the data in the table, it ignores the inserting.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter specifies the batch operation count when given data is slice.
+// The parameter `batch` specifies the batch operation count when given data is slice.
func (tx *TX) InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(data).Batch(batch[0]).InsertIgnore()
@@ -179,14 +179,14 @@ func (tx *TX) InsertIgnore(table string, data interface{}, batch ...int) (sql.Re
// If there's already one unique record of the data in the table, it deletes the record
// and inserts a new one.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// If given data is type of slice, it then does batch replacing, and the optional parameter
-// specifies the batch operation count.
+// `batch` specifies the batch operation count.
func (tx *TX) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(data).Batch(batch[0]).Replace()
@@ -198,13 +198,13 @@ func (tx *TX) Replace(table string, data interface{}, batch ...int) (sql.Result,
// It updates the record if there's primary or unique index in the saving data,
// or else it inserts a new record into the table.
//
-// The parameter can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
// Eg:
// Data(g.Map{"uid": 10000, "name":"john"})
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
//
// If given data is type of slice, it then does batch saving, and the optional parameter
-// specifies the batch operation count.
+// `batch` specifies the batch operation count.
func (tx *TX) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(data).Batch(batch[0]).Save()
@@ -213,7 +213,7 @@ func (tx *TX) Save(table string, data interface{}, batch ...int) (sql.Result, er
}
// BatchInsert batch inserts data.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (tx *TX) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(list).Batch(batch[0]).Insert()
@@ -222,7 +222,7 @@ func (tx *TX) BatchInsert(table string, list interface{}, batch ...int) (sql.Res
}
// BatchInsert batch inserts data with ignore option.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (tx *TX) BatchInsertIgnore(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(list).Batch(batch[0]).InsertIgnore()
@@ -231,7 +231,7 @@ func (tx *TX) BatchInsertIgnore(table string, list interface{}, batch ...int) (s
}
// BatchReplace batch replaces data.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (tx *TX) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(list).Batch(batch[0]).Replace()
@@ -240,7 +240,7 @@ func (tx *TX) BatchReplace(table string, list interface{}, batch ...int) (sql.Re
}
// BatchSave batch replaces data.
-// The parameter must be type of slice of map or struct.
+// The parameter `list` must be type of slice of map or struct.
func (tx *TX) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
if len(batch) > 0 {
return tx.Model(table).Data(list).Batch(batch[0]).Save()
@@ -250,11 +250,11 @@ func (tx *TX) BatchSave(table string, list interface{}, batch ...int) (sql.Resul
// Update does "UPDATE ... " statement for the table.
//
-// The parameter can be type of string/map/gmap/struct/*struct, etc.
+// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.
// Eg: "uid=10000", "uid", 10000, g.Map{"uid": 10000, "name":"john"}
//
-// The parameter can be type of string/map/gmap/slice/struct/*struct, etc.
-// It is commonly used with parameter .
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
// Eg:
// "uid=10000",
// "uid", 10000
@@ -268,8 +268,8 @@ func (tx *TX) Update(table string, data interface{}, condition interface{}, args
// Delete does "DELETE FROM ... " statement for the table.
//
-// The parameter can be type of string/map/gmap/slice/struct/*struct, etc.
-// It is commonly used with parameter .
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
// Eg:
// "uid=10000",
// "uid", 10000
diff --git a/database/gdb/gdb_type_record.go b/database/gdb/gdb_type_record.go
index f469c413f..7f9c4ffb6 100644
--- a/database/gdb/gdb_type_record.go
+++ b/database/gdb/gdb_type_record.go
@@ -16,19 +16,19 @@ import (
"reflect"
)
-// Json converts to JSON format content.
+// Json converts `r` to JSON format content.
func (r Record) Json() string {
content, _ := gparser.VarToJson(r.Map())
return gconv.UnsafeBytesToStr(content)
}
-// Xml converts to XML format content.
+// Xml converts `r` to XML format content.
func (r Record) Xml(rootTag ...string) string {
content, _ := gparser.VarToXml(r.Map(), rootTag...)
return gconv.UnsafeBytesToStr(content)
}
-// Map converts to map[string]interface{}.
+// Map converts `r` to map[string]interface{}.
func (r Record) Map() Map {
m := make(map[string]interface{})
for k, v := range r {
@@ -37,15 +37,15 @@ func (r Record) Map() Map {
return m
}
-// GMap converts to a gmap.
+// GMap converts `r` to a gmap.
func (r Record) GMap() *gmap.StrAnyMap {
return gmap.NewStrAnyMapFrom(r.Map())
}
-// Struct converts to a struct.
-// Note that the parameter should be type of *struct/**struct.
+// Struct converts `r` to a struct.
+// Note that the parameter `pointer` should be type of *struct/**struct.
//
-// Note that it returns sql.ErrNoRows if is empty.
+// Note that it returns sql.ErrNoRows if `r` is empty.
func (r Record) Struct(pointer interface{}) error {
// If the record is empty, it returns error.
if r.IsEmpty() {
@@ -76,7 +76,7 @@ func (r Record) Struct(pointer interface{}) error {
return convertMapToStruct(r.Map(), pointer)
}
-// IsEmpty checks and returns whether is empty.
+// IsEmpty checks and returns whether `r` is empty.
func (r Record) IsEmpty() bool {
return len(r) == 0
}
diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go
index 92377fadc..e832e206c 100644
--- a/database/gdb/gdb_type_result.go
+++ b/database/gdb/gdb_type_result.go
@@ -16,7 +16,7 @@ import (
"github.com/gogf/gf/encoding/gparser"
)
-// IsEmpty checks and returns whether is empty.
+// IsEmpty checks and returns whether `r` is empty.
func (r Result) IsEmpty() bool {
return r.Len() == 0
}
@@ -32,7 +32,7 @@ func (r Result) Size() int {
}
// Chunk splits an Result into multiple Results,
-// the size of each array is determined by .
+// the size of each array is determined by `size`.
// The last chunk may contain less than size elements.
func (r Result) Chunk(size int) []Result {
if size < 1 {
@@ -52,19 +52,19 @@ func (r Result) Chunk(size int) []Result {
return n
}
-// Json converts to JSON format content.
+// Json converts `r` to JSON format content.
func (r Result) Json() string {
content, _ := gparser.VarToJson(r.List())
return string(content)
}
-// Xml converts to XML format content.
+// Xml converts `r` to XML format content.
func (r Result) Xml(rootTag ...string) string {
content, _ := gparser.VarToXml(r.List(), rootTag...)
return string(content)
}
-// List converts to a List.
+// List converts `r` to a List.
func (r Result) List() List {
list := make(List, len(r))
for k, v := range r {
@@ -74,7 +74,7 @@ func (r Result) List() List {
}
// Array retrieves and returns specified column values as slice.
-// The parameter is optional is the column field is only one.
+// The parameter `field` is optional is the column field is only one.
func (r Result) Array(field ...string) []Value {
array := make([]Value, len(r))
if len(r) == 0 {
@@ -95,7 +95,7 @@ func (r Result) Array(field ...string) []Value {
return array
}
-// MapKeyValue converts to a map[string]Value of which key is specified by .
+// MapKeyValue converts `r` to a map[string]Value of which key is specified by `key`.
// Note that the item value may be type of slice.
func (r Result) MapKeyValue(key string) map[string]Value {
var (
@@ -123,7 +123,7 @@ func (r Result) MapKeyValue(key string) map[string]Value {
return m
}
-// MapKeyStr converts to a map[string]Map of which key is specified by .
+// MapKeyStr converts `r` to a map[string]Map of which key is specified by `key`.
func (r Result) MapKeyStr(key string) map[string]Map {
m := make(map[string]Map)
for _, item := range r {
@@ -134,7 +134,7 @@ func (r Result) MapKeyStr(key string) map[string]Map {
return m
}
-// MapKeyInt converts to a map[int]Map of which key is specified by .
+// MapKeyInt converts `r` to a map[int]Map of which key is specified by `key`.
func (r Result) MapKeyInt(key string) map[int]Map {
m := make(map[int]Map)
for _, item := range r {
@@ -145,7 +145,7 @@ func (r Result) MapKeyInt(key string) map[int]Map {
return m
}
-// MapKeyUint converts to a map[uint]Map of which key is specified by .
+// MapKeyUint converts `r` to a map[uint]Map of which key is specified by `key`.
func (r Result) MapKeyUint(key string) map[uint]Map {
m := make(map[uint]Map)
for _, item := range r {
@@ -156,7 +156,7 @@ func (r Result) MapKeyUint(key string) map[uint]Map {
return m
}
-// RecordKeyInt converts to a map[int]Record of which key is specified by .
+// RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`.
func (r Result) RecordKeyStr(key string) map[string]Record {
m := make(map[string]Record)
for _, item := range r {
@@ -167,7 +167,7 @@ func (r Result) RecordKeyStr(key string) map[string]Record {
return m
}
-// RecordKeyInt converts to a map[int]Record of which key is specified by .
+// RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`.
func (r Result) RecordKeyInt(key string) map[int]Record {
m := make(map[int]Record)
for _, item := range r {
@@ -178,7 +178,7 @@ func (r Result) RecordKeyInt(key string) map[int]Record {
return m
}
-// RecordKeyUint converts to a map[uint]Record of which key is specified by .
+// RecordKeyUint converts `r` to a map[uint]Record of which key is specified by `key`.
func (r Result) RecordKeyUint(key string) map[uint]Record {
m := make(map[uint]Record)
for _, item := range r {
@@ -189,8 +189,8 @@ func (r Result) RecordKeyUint(key string) map[uint]Record {
return m
}
-// Structs converts to struct slice.
-// Note that the parameter should be type of *[]struct/*[]*struct.
+// Structs converts `r` to struct slice.
+// Note that the parameter `pointer` should be type of *[]struct/*[]*struct.
func (r Result) Structs(pointer interface{}) (err error) {
var (
reflectValue = reflect.ValueOf(pointer)
diff --git a/database/gdb/gdb_type_result_scanlist.go b/database/gdb/gdb_type_result_scanlist.go
index 07578ffa0..b18f23891 100644
--- a/database/gdb/gdb_type_result_scanlist.go
+++ b/database/gdb/gdb_type_result_scanlist.go
@@ -15,8 +15,8 @@ import (
"reflect"
)
-// ScanList converts to struct slice which contains other complex struct attributes.
-// Note that the parameter should be type of *[]struct/*[]*struct.
+// ScanList converts `r` to struct slice which contains other complex struct attributes.
+// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
// Usage example:
//
// type Entity struct {
@@ -38,7 +38,7 @@ import (
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
// struct attribute name - not the attribute name of the bound to target. In the example codes, it's attribute
// name "Uid" of "User" of entity "Entity". It automatically calculates the HasOne/HasMany relationship with
-// given parameter.
+// given `relation` parameter.
//
// See the example or unit testing cases for clear understanding for this function.
func (r Result) ScanList(listPointer interface{}, bindToAttrName string, relationKV ...string) (err error) {
diff --git a/database/gdb/gdb_z_mysql_association_with_test.go b/database/gdb/gdb_z_mysql_association_with_test.go
index 216e83942..cbeeed29d 100644
--- a/database/gdb/gdb_z_mysql_association_with_test.go
+++ b/database/gdb/gdb_z_mysql_association_with_test.go
@@ -16,9 +16,9 @@ import (
func Test_Table_Relation_With(t *testing.T) {
var (
- tableUser = "user_with"
- tableUserDetail = "user_detail_with"
- tableUserScores = "user_scores_with"
+ tableUser = "user"
+ tableUserDetail = "user_detail"
+ tableUserScores = "user_scores"
)
if _, err := db.Exec(fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s (
@@ -55,20 +55,20 @@ PRIMARY KEY (id)
defer dropTable(tableUserScores)
type UserDetail struct {
- gmeta.Meta `table:"user_detail_with"`
+ gmeta.Meta `orm:"table:user_detail"`
Uid int `json:"uid"`
Address string `json:"address"`
}
type UserScores struct {
- gmeta.Meta `table:"user_scores_with"`
+ gmeta.Meta `orm:"table:user_scores"`
Id int `json:"id"`
Uid int `json:"uid"`
Score int `json:"score"`
}
type User struct {
- gmeta.Meta `table:"user_with"`
+ gmeta.Meta `orm:"table:user"`
Id int `json:"id"`
Name string `json:"name"`
UserDetail *UserDetail `orm:"with:uid=id"`
@@ -101,8 +101,16 @@ PRIMARY KEY (id)
}
gtest.C(t, func(t *gtest.T) {
var user *User
- err := db.Model().With(&user).Where("id", 3).Scan(&user)
+ db.SetDebug(true)
+ err := db.With(User{}).
+ With(User{}.UserDetail).
+ With(User{}.UserScores).
+ Where("id", 3).
+ Scan(&user)
t.AssertNil(err)
t.Assert(user.Id, 3)
+ t.AssertNE(user.UserDetail, nil)
+ t.Assert(user.UserDetail.Uid, 3)
+ t.Assert(user.UserDetail.Address, `address_3`)
})
}
diff --git a/frame/g/g.go b/frame/g/g.go
index f97762ade..2138cbfcf 100644
--- a/frame/g/g.go
+++ b/frame/g/g.go
@@ -6,51 +6,57 @@
package g
-import (
- "github.com/gogf/gf/container/gvar"
-)
+import "github.com/gogf/gf/container/gvar"
// Var is a universal variable interface, like generics.
type Var = gvar.Var
-// Frequently-used map type alias.
-type Map = map[string]interface{}
-type MapAnyAny = map[interface{}]interface{}
-type MapAnyStr = map[interface{}]string
-type MapAnyInt = map[interface{}]int
-type MapStrAny = map[string]interface{}
-type MapStrStr = map[string]string
-type MapStrInt = map[string]int
-type MapIntAny = map[int]interface{}
-type MapIntStr = map[int]string
-type MapIntInt = map[int]int
-type MapAnyBool = map[interface{}]bool
-type MapStrBool = map[string]bool
-type MapIntBool = map[int]bool
+// Frequently-used map alias.
+type (
+ Map = map[string]interface{}
+ MapAnyAny = map[interface{}]interface{}
+ MapAnyStr = map[interface{}]string
+ MapAnyInt = map[interface{}]int
+ MapStrAny = map[string]interface{}
+ MapStrStr = map[string]string
+ MapStrInt = map[string]int
+ MapIntAny = map[int]interface{}
+ MapIntStr = map[int]string
+ MapIntInt = map[int]int
+ MapAnyBool = map[interface{}]bool
+ MapStrBool = map[string]bool
+ MapIntBool = map[int]bool
+)
-// Frequently-used slice type alias.
-type List = []Map
-type ListAnyAny = []MapAnyAny
-type ListAnyStr = []MapAnyStr
-type ListAnyInt = []MapAnyInt
-type ListStrAny = []MapStrAny
-type ListStrStr = []MapStrStr
-type ListStrInt = []MapStrInt
-type ListIntAny = []MapIntAny
-type ListIntStr = []MapIntStr
-type ListIntInt = []MapIntInt
-type ListAnyBool = []MapAnyBool
-type ListStrBool = []MapStrBool
-type ListIntBool = []MapIntBool
+// Frequently-used slice alias.
+type (
+ List = []Map
+ ListAnyAny = []MapAnyAny
+ ListAnyStr = []MapAnyStr
+ ListAnyInt = []MapAnyInt
+ ListStrAny = []MapStrAny
+ ListStrStr = []MapStrStr
+ ListStrInt = []MapStrInt
+ ListIntAny = []MapIntAny
+ ListIntStr = []MapIntStr
+ ListIntInt = []MapIntInt
+ ListAnyBool = []MapAnyBool
+ ListStrBool = []MapStrBool
+ ListIntBool = []MapIntBool
+)
-// Frequently-used slice type alias.
-type Slice = []interface{}
-type SliceAny = []interface{}
-type SliceStr = []string
-type SliceInt = []int
+// Frequently-used slice alias.
+type (
+ Slice = []interface{}
+ SliceAny = []interface{}
+ SliceStr = []string
+ SliceInt = []int
+)
// Array is alias of Slice.
-type Array = []interface{}
-type ArrayAny = []interface{}
-type ArrayStr = []string
-type ArrayInt = []int
+type (
+ Array = []interface{}
+ ArrayAny = []interface{}
+ ArrayStr = []string
+ ArrayInt = []int
+)
diff --git a/frame/g/g_object.go b/frame/g/g_object.go
index 6cfacac4b..6e0dceb64 100644
--- a/frame/g/g_object.go
+++ b/frame/g/g_object.go
@@ -80,13 +80,14 @@ func Log(name ...string) *glog.Logger {
return gins.Log(name...)
}
-// Database returns an instance of database ORM object with specified configuration group name.
+// Database is alias of DB.
+// See DB.
+// Deprecated, use DB instead.
func Database(name ...string) gdb.DB {
return gins.Database(name...)
}
-// DB is alias of Database.
-// See Database.
+// DB returns an instance of database ORM object with specified configuration group name.
func DB(name ...string) gdb.DB {
return gins.Database(name...)
}
@@ -97,7 +98,7 @@ func DB(name ...string) gdb.DB {
// "Table" is not proper for that purpose any more.
// Deprecated, use Model instead.
func Table(tables ...string) *gdb.Model {
- return DB().Table(tables...)
+ return DB().Model(tables...)
}
// Model creates and returns a model based on configuration of default database group.
@@ -105,6 +106,11 @@ func Model(tables ...string) *gdb.Model {
return DB().Model(tables...)
}
+// With creates and returns an ORM model based on meta data of given object.
+func With(object interface{}) *gdb.Model {
+ return DB().With(object)
+}
+
// Redis returns an instance of redis client with specified configuration group name.
func Redis(name ...string) *gredis.Redis {
return gins.Redis(name...)
diff --git a/internal/command/command.go b/internal/command/command.go
index 56f2a9d55..824f83ca3 100644
--- a/internal/command/command.go
+++ b/internal/command/command.go
@@ -59,7 +59,7 @@ func Init(args ...string) {
}
}
-// GetOpt returns the option value named .
+// GetOpt returns the option value named `name`.
func GetOpt(name string, def ...string) string {
Init()
if v, ok := defaultParsedOptions[name]; ok {
@@ -77,14 +77,14 @@ func GetOptAll() map[string]string {
return defaultParsedOptions
}
-// ContainsOpt checks whether option named exist in the arguments.
+// ContainsOpt checks whether option named `name` exist in the arguments.
func ContainsOpt(name string) bool {
Init()
_, ok := defaultParsedOptions[name]
return ok
}
-// GetArg returns the argument at .
+// GetArg returns the argument at `index`.
func GetArg(index int, def ...string) string {
Init()
if index < len(defaultParsedArgs) {
@@ -102,9 +102,9 @@ func GetArgAll() []string {
return defaultParsedArgs
}
-// GetOptWithEnv returns the command line argument of the specified .
-// If the argument does not exist, then it returns the environment variable with specified .
-// It returns the default value if none of them exists.
+// GetOptWithEnv returns the command line argument of the specified `key`.
+// If the argument does not exist, then it returns the environment variable with specified `key`.
+// It returns the default value `def` if none of them exists.
//
// Fetching Rules:
// 1. Command line arguments are in lowercase format, eg: gf..;
diff --git a/internal/empty/empty.go b/internal/empty/empty.go
index 2e59ea5a0..234378aca 100644
--- a/internal/empty/empty.go
+++ b/internal/empty/empty.go
@@ -26,8 +26,8 @@ type apiMapStrAny interface {
MapStrAny() map[string]interface{}
}
-// IsEmpty checks whether given empty.
-// It returns true if is in: 0, nil, false, "", len(slice/map/chan) == 0,
+// IsEmpty checks whether given `value` empty.
+// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0,
// or else it returns false.
func IsEmpty(value interface{}) bool {
if value == nil {
@@ -151,9 +151,9 @@ func IsEmpty(value interface{}) bool {
return false
}
-// IsNil checks whether given is nil.
-// Parameter is used for tracing to the source variable if given is type
-// of a pinter that also points to a pointer. It returns nil if the source is nil when
+// IsNil checks whether given `value` is nil.
+// Parameter `traceSource` is used for tracing to the source variable if given `value` is type
+// of a pinter that also points to a pointer. It returns nil if the source is nil when `traceSource`
// is true.
// Note that it might use reflect feature which affects performance a little bit.
func IsNil(value interface{}, traceSource ...bool) bool {
diff --git a/internal/intlog/intlog.go b/internal/intlog/intlog.go
index d746d5862..4edf5c2ab 100644
--- a/internal/intlog/intlog.go
+++ b/internal/intlog/intlog.go
@@ -31,7 +31,7 @@ func init() {
// SetEnabled enables/disables the internal logging manually.
// Note that this function is not concurrent safe, be aware of the DATA RACE.
func SetEnabled(enabled bool) {
- // If they're the same, it does not write the but only reading operation.
+ // If they're the same, it does not write the `isGFDebug` but only reading operation.
if isGFDebug != enabled {
isGFDebug = enabled
}
@@ -42,8 +42,8 @@ func IsEnabled() bool {
return isGFDebug
}
-// Print prints with newline using fmt.Println.
-// The parameter can be multiple variables.
+// Print prints `v` with newline using fmt.Println.
+// The parameter `v` can be multiple variables.
func Print(v ...interface{}) {
if !isGFDebug {
return
@@ -51,8 +51,8 @@ func Print(v ...interface{}) {
fmt.Println(append([]interface{}{now(), "[INTE]", file()}, v...)...)
}
-// Printf prints with format using fmt.Printf.
-// The parameter can be multiple variables.
+// Printf prints `v` with format `format` using fmt.Printf.
+// The parameter `v` can be multiple variables.
func Printf(format string, v ...interface{}) {
if !isGFDebug {
return
@@ -60,8 +60,8 @@ func Printf(format string, v ...interface{}) {
fmt.Printf(now()+" [INTE] "+file()+" "+format+"\n", v...)
}
-// Error prints with newline using fmt.Println.
-// The parameter can be multiple variables.
+// Error prints `v` with newline using fmt.Println.
+// The parameter `v` can be multiple variables.
func Error(v ...interface{}) {
if !isGFDebug {
return
@@ -71,7 +71,7 @@ func Error(v ...interface{}) {
fmt.Println(array...)
}
-// Errorf prints with format using fmt.Printf.
+// Errorf prints `v` with format `format` using fmt.Printf.
func Errorf(format string, v ...interface{}) {
if !isGFDebug {
return
diff --git a/internal/mutex/mutex.go b/internal/mutex/mutex.go
index 9e04dc6bf..ccb32d037 100644
--- a/internal/mutex/mutex.go
+++ b/internal/mutex/mutex.go
@@ -16,7 +16,7 @@ type Mutex struct {
}
// New creates and returns a new *Mutex.
-// The parameter is used to specify whether using this mutex in concurrent-safety,
+// The parameter `safe` is used to specify whether using this mutex in concurrent-safety,
// which is false in default.
func New(safe ...bool) *Mutex {
mu := new(Mutex)
diff --git a/internal/rwmutex/rwmutex.go b/internal/rwmutex/rwmutex.go
index 0a6a9615b..0d16fb7d3 100644
--- a/internal/rwmutex/rwmutex.go
+++ b/internal/rwmutex/rwmutex.go
@@ -17,7 +17,7 @@ type RWMutex struct {
}
// New creates and returns a new *RWMutex.
-// The parameter is used to specify whether using this mutex in concurrent safety,
+// The parameter `safe` is used to specify whether using this mutex in concurrent safety,
// which is false in default.
func New(safe ...bool) *RWMutex {
mu := Create(safe...)
@@ -25,7 +25,7 @@ func New(safe ...bool) *RWMutex {
}
// Create creates and returns a new RWMutex object.
-// The parameter is used to specify whether using this mutex in concurrent safety,
+// The parameter `safe` is used to specify whether using this mutex in concurrent safety,
// which is false in default.
func Create(safe ...bool) RWMutex {
mu := RWMutex{}
diff --git a/internal/structs/structs.go b/internal/structs/structs.go
index 5ff9190db..d6204497c 100644
--- a/internal/structs/structs.go
+++ b/internal/structs/structs.go
@@ -20,36 +20,7 @@ type Type struct {
// Field contains information of a struct field .
type Field struct {
- value reflect.Value
- field reflect.StructField
- // Retrieved tag value. There might be more than one tags in the field,
- // but only one can be retrieved according to calling function rules.
- TagValue string
-}
-
-// Tag returns the value associated with key in the tag string. If there is no
-// such key in the tag, Tag returns the empty string.
-func (f *Field) Tag(key string) string {
- return f.field.Tag.Get(key)
-}
-
-// Value returns the underlying value of the field. It panics if the field
-// is not exported.
-func (f *Field) Value() interface{} {
- return f.value.Interface()
-}
-
-// IsEmbedded returns true if the given field is an anonymous field (embedded)
-func (f *Field) IsEmbedded() bool {
- return f.field.Anonymous
-}
-
-// IsExported returns true if the given field is exported.
-func (f *Field) IsExported() bool {
- return f.field.PkgPath == ""
-}
-
-// Name returns the name of the given field
-func (f *Field) Name() string {
- return f.field.Name
+ Value reflect.Value // The underlying value of the field.
+ Field reflect.StructField // The underlying field of the field.
+ TagValue string // Retrieved tag value. There might be more than one tags in the field, but only one can be retrieved according to calling function rules.
}
diff --git a/internal/structs/structs_map.go b/internal/structs/structs_field.go
similarity index 52%
rename from internal/structs/structs_map.go
rename to internal/structs/structs_field.go
index aa36050f4..8d3e0afe8 100644
--- a/internal/structs/structs_map.go
+++ b/internal/structs/structs_field.go
@@ -6,14 +6,43 @@
package structs
-// MapField retrieves struct field as map[name/tag]*Field from , and returns the map.
+// Tag returns the value associated with key in the tag string. If there is no
+// such key in the tag, Tag returns the empty string.
+func (f *Field) Tag(key string) string {
+ return f.Field.Tag.Get(key)
+}
+
+// IsEmbedded returns true if the given field is an anonymous field (embedded)
+func (f *Field) IsEmbedded() bool {
+ return f.Field.Anonymous
+}
+
+// IsExported returns true if the given field is exported.
+func (f *Field) IsExported() bool {
+ return f.Field.PkgPath == ""
+}
+
+// Name returns the name of the given field
+func (f *Field) Name() string {
+ return f.Field.Name
+}
+
+// Type returns the type of the given field
+func (f *Field) Type() Type {
+ return Type{
+ Type: f.Field.Type,
+ }
+}
+
+// FieldMap retrieves and returns struct field as map[name/tag]*Field from `pointer`.
//
-// The parameter should be type of struct/*struct.
+// The parameter `pointer` should be type of struct/*struct.
//
-// The parameter specifies the priority tag array for retrieving from high to low.
+// The parameter `priority` specifies the priority tag array for retrieving from high to low.
+// If it's given `nil`, it returns map[name]*Field, of which the `name` is attribute name.
//
// Note that it only retrieves the exported attributes with first letter up-case from struct.
-func MapField(pointer interface{}, priority []string) (map[string]*Field, error) {
+func FieldMap(pointer interface{}, priority []string) (map[string]*Field, error) {
fields, err := getFieldValues(pointer)
if err != nil {
return nil, err
@@ -40,7 +69,7 @@ func MapField(pointer interface{}, priority []string) (map[string]*Field, error)
mapField[tagValue] = tempField
} else {
if field.IsEmbedded() {
- m, err := MapField(field.value, priority)
+ m, err := FieldMap(field.Value, priority)
if err != nil {
return nil, err
}
diff --git a/internal/structs/structs_tag.go b/internal/structs/structs_tag.go
index 1a7ac849c..2746cd29c 100644
--- a/internal/structs/structs_tag.go
+++ b/internal/structs/structs_tag.go
@@ -9,20 +9,73 @@ package structs
import (
"errors"
"reflect"
+ "strconv"
)
-// TagFields retrieves struct tags as []*Field from , and returns it.
+// ParseTag parses tag string into map.
+func ParseTag(tag string) map[string]string {
+ var (
+ key string
+ data = make(map[string]string)
+ )
+ for tag != "" {
+ // Skip leading space.
+ i := 0
+ for i < len(tag) && tag[i] == ' ' {
+ i++
+ }
+ tag = tag[i:]
+ if tag == "" {
+ break
+ }
+ // Scan to colon. A space, a quote or a control character is a syntax error.
+ // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
+ // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
+ // as it is simpler to inspect the tag's bytes than the tag's runes.
+ i = 0
+ for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
+ i++
+ }
+ if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+ break
+ }
+ key = tag[:i]
+ tag = tag[i+1:]
+
+ // Scan quoted string to find value.
+ i = 1
+ for i < len(tag) && tag[i] != '"' {
+ if tag[i] == '\\' {
+ i++
+ }
+ i++
+ }
+ if i >= len(tag) {
+ break
+ }
+ quotedValue := string(tag[:i+1])
+ tag = tag[i+1:]
+ value, err := strconv.Unquote(quotedValue)
+ if err != nil {
+ panic(err)
+ }
+ data[key] = value
+ }
+ return data
+}
+
+// TagFields retrieves and returns struct tags as []*Field from `pointer`.
//
-// The parameter should be type of struct/*struct.
+// The parameter `pointer` should be type of struct/*struct.
//
// Note that it only retrieves the exported attributes with first letter up-case from struct.
func TagFields(pointer interface{}, priority []string) ([]*Field, error) {
return getFieldValuesByTagPriority(pointer, priority, map[string]struct{}{})
}
-// TagMapName retrieves struct tags as map[tag]attribute from , and returns it.
+// TagMapName retrieves and returns struct tags as map[tag]attribute from `pointer`.
//
-// The parameter should be type of struct/*struct.
+// The parameter `pointer` should be type of struct/*struct.
//
// Note that it only retrieves the exported attributes with first letter up-case from struct.
func TagMapName(pointer interface{}, priority []string) (map[string]string, error) {
@@ -37,9 +90,9 @@ func TagMapName(pointer interface{}, priority []string) (map[string]string, erro
return tagMap, nil
}
-// TagMapField retrieves struct tags as map[tag]*Field from , and returns it.
+// TagMapField retrieves struct tags as map[tag]*Field from `pointer`, and returns it.
//
-// The parameter should be type of struct/*struct.
+// The parameter `pointer` should be type of struct/*struct.
//
// Note that it only retrieves the exported attributes with first letter up-case from struct.
func TagMapField(pointer interface{}, priority []string) (map[string]*Field, error) {
@@ -88,8 +141,8 @@ func getFieldValues(value interface{}) ([]*Field, error) {
)
for i := 0; i < length; i++ {
fields[i] = &Field{
- value: reflectValue.Field(i),
- field: structType.Field(i),
+ Value: reflectValue.Field(i),
+ Field: structType.Field(i),
}
}
return fields, nil
@@ -127,7 +180,7 @@ func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap
}
// If this is an embedded attribute, it retrieves the tags recursively.
if field.IsEmbedded() {
- if subTagFields, err := getFieldValuesByTagPriority(field.value, priority, tagMap); err != nil {
+ if subTagFields, err := getFieldValuesByTagPriority(field.Value, priority, tagMap); err != nil {
return nil, err
} else {
tagFields = append(tagFields, subTagFields...)
diff --git a/internal/structs/structs_type.go b/internal/structs/structs_type.go
index cee57b2f7..283eb0498 100644
--- a/internal/structs/structs_type.go
+++ b/internal/structs/structs_type.go
@@ -11,36 +11,45 @@ import (
"reflect"
)
-// StructType retrieves and returns the Type of specified struct/*struct.
-func StructType(structOrPointer interface{}) (*Type, error) {
+// StructType retrieves and returns the struct Type of specified struct/*struct.
+func StructType(object interface{}) (*Type, error) {
var (
reflectValue reflect.Value
reflectKind reflect.Kind
reflectType reflect.Type
)
- if rv, ok := structOrPointer.(reflect.Value); ok {
+ if rv, ok := object.(reflect.Value); ok {
reflectValue = rv
} else {
- reflectValue = reflect.ValueOf(structOrPointer)
+ reflectValue = reflect.ValueOf(object)
}
reflectKind = reflectValue.Kind()
- for reflectKind == reflect.Ptr {
- if !reflectValue.IsValid() || reflectValue.IsNil() {
- // If pointer is type of *struct and nil, then automatically create a temporary struct.
+ for {
+ switch reflectKind {
+ case reflect.Ptr:
+ if !reflectValue.IsValid() || reflectValue.IsNil() {
+ // If pointer is type of *struct and nil, then automatically create a temporary struct.
+ reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
+ reflectKind = reflectValue.Kind()
+ } else {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ case reflect.Array, reflect.Slice:
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
reflectKind = reflectValue.Kind()
- } else {
- reflectValue = reflectValue.Elem()
- reflectKind = reflectValue.Kind()
+ default:
+ goto exitLoop
}
}
+exitLoop:
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
if reflectKind != reflect.Struct {
return nil, gerror.Newf(
- `invalid parameter kind "%s", kind of "struct" is required`,
+ `invalid object kind "%s", kind of "struct" is required`,
reflectKind,
)
}
@@ -50,6 +59,16 @@ func StructType(structOrPointer interface{}) (*Type, error) {
}, nil
}
-func (t *Type) Signature() string {
+// Signature returns an unique string as this type.
+func (t Type) Signature() string {
return t.PkgPath() + "/" + t.String()
}
+
+// FieldKeys returns the keys of current struct/map.
+func (t Type) FieldKeys() []string {
+ keys := make([]string, t.NumField())
+ for i := 0; i < t.NumField(); i++ {
+ keys[i] = t.Field(i).Name
+ }
+ return keys
+}
diff --git a/internal/structs/structs_z_unit_test.go b/internal/structs/structs_z_unit_test.go
index f694aecdf..c4f31d1a2 100644
--- a/internal/structs/structs_z_unit_test.go
+++ b/internal/structs/structs_z_unit_test.go
@@ -102,7 +102,7 @@ func Test_StructOfNilPointer(t *testing.T) {
})
}
-func Test_MapField(t *testing.T) {
+func Test_FieldMap(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
@@ -110,7 +110,7 @@ func Test_MapField(t *testing.T) {
Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"`
}
var user *User
- m, _ := structs.MapField(user, []string{"params"})
+ m, _ := structs.FieldMap(user, []string{"params"})
t.Assert(len(m), 3)
_, ok := m["Id"]
t.Assert(ok, true)
@@ -123,6 +123,26 @@ func Test_MapField(t *testing.T) {
_, ok = m["pass"]
t.Assert(ok, true)
})
+ gtest.C(t, func(t *gtest.T) {
+ type User struct {
+ Id int
+ Name string `params:"name"`
+ Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"`
+ }
+ var user *User
+ m, _ := structs.FieldMap(user, nil)
+ t.Assert(len(m), 3)
+ _, ok := m["Id"]
+ t.Assert(ok, true)
+ _, ok = m["Name"]
+ t.Assert(ok, true)
+ _, ok = m["name"]
+ t.Assert(ok, false)
+ _, ok = m["Pass"]
+ t.Assert(ok, true)
+ _, ok = m["pass"]
+ t.Assert(ok, false)
+ })
}
func Test_StructType(t *testing.T) {
@@ -148,7 +168,6 @@ func Test_StructType(t *testing.T) {
t.AssertNil(err)
t.Assert(r.Signature(), `github.com/gogf/gf/internal/structs_test/structs_test.B`)
})
- // Error.
gtest.C(t, func(t *gtest.T) {
type B struct {
Name string
@@ -156,7 +175,71 @@ func Test_StructType(t *testing.T) {
type A struct {
*B
}
- _, err := structs.StructType(new(A).B)
+ r, err := structs.StructType(new(A).B)
+ t.AssertNil(err)
+ t.Assert(r.String(), `structs_test.B`)
+ })
+ // Error.
+ gtest.C(t, func(t *gtest.T) {
+ type B struct {
+ Name string
+ }
+ type A struct {
+ *B
+ Id int
+ }
+ _, err := structs.StructType(new(A).Id)
t.AssertNE(err, nil)
})
}
+
+func Test_StructTypeBySlice(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ type B struct {
+ Name string
+ }
+ type A struct {
+ Array []*B
+ }
+ r, err := structs.StructType(new(A).Array)
+ t.AssertNil(err)
+ t.Assert(r.Signature(), `github.com/gogf/gf/internal/structs_test/structs_test.B`)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ type B struct {
+ Name string
+ }
+ type A struct {
+ Array []B
+ }
+ r, err := structs.StructType(new(A).Array)
+ t.AssertNil(err)
+ t.Assert(r.Signature(), `github.com/gogf/gf/internal/structs_test/structs_test.B`)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ type B struct {
+ Name string
+ }
+ type A struct {
+ Array *[]B
+ }
+ r, err := structs.StructType(new(A).Array)
+ t.AssertNil(err)
+ t.Assert(r.Signature(), `github.com/gogf/gf/internal/structs_test/structs_test.B`)
+ })
+}
+
+func TestType_FieldKeys(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ type B struct {
+ Id int
+ Name string
+ }
+ type A struct {
+ Array []*B
+ }
+ r, err := structs.StructType(new(A).Array)
+ t.AssertNil(err)
+ t.Assert(r.FieldKeys(), g.Slice{"Id", "Name"})
+ })
+}
diff --git a/internal/utils/utils_str.go b/internal/utils/utils_str.go
index 7ca82b7bf..bd61f0ac9 100644
--- a/internal/utils/utils_str.go
+++ b/internal/utils/utils_str.go
@@ -67,7 +67,7 @@ func UcFirst(s string) string {
return s
}
-// ReplaceByMap returns a copy of ,
+// ReplaceByMap returns a copy of `origin`,
// which is replaced by a map in unordered way, case-sensitively.
func ReplaceByMap(origin string, replaces map[string]string) string {
for k, v := range replaces {
@@ -87,7 +87,7 @@ func RemoveSymbols(s string) string {
return string(b)
}
-// EqualFoldWithoutChars checks string and equal case-insensitively,
+// EqualFoldWithoutChars checks string `s1` and `s2` equal case-insensitively,
// with/without chars '-'/'_'/'.'/' '.
func EqualFoldWithoutChars(s1, s2 string) bool {
return strings.EqualFold(RemoveSymbols(s1), RemoveSymbols(s2))
diff --git a/text/gstr/gstr.go b/text/gstr/gstr.go
index 2758b6091..e1805c713 100644
--- a/text/gstr/gstr.go
+++ b/text/gstr/gstr.go
@@ -23,6 +23,11 @@ import (
"github.com/gogf/gf/util/grand"
)
+const (
+ // NotFoundIndex is the position index for string not found in searching functions.
+ NotFoundIndex = -1
+)
+
// Replace returns a copy of the string
// in which string replaced by case-sensitively.
func Replace(origin, search, replace string, count ...int) string {
@@ -43,8 +48,10 @@ func ReplaceI(origin, search, replace string, count ...int) string {
if n == 0 {
return origin
}
- length := len(search)
- searchLower := strings.ToLower(search)
+ var (
+ length = len(search)
+ searchLower = strings.ToLower(search)
+ )
for {
originLower := strings.ToLower(origin)
if pos := strings.Index(originLower, searchLower); pos != -1 {
@@ -465,11 +472,11 @@ func Str(haystack string, needle string) string {
if needle == "" {
return ""
}
- idx := strings.Index(haystack, needle)
- if idx == -1 {
+ pos := strings.Index(haystack, needle)
+ if pos == NotFoundIndex {
return ""
}
- return haystack[idx+len([]byte(needle))-1:]
+ return haystack[pos+len([]byte(needle))-1:]
}
// StrEx returns part of string starting from and excluding
@@ -481,6 +488,26 @@ func StrEx(haystack string, needle string) string {
return ""
}
+// StrTill returns part of string ending to and including
+// the first occurrence of from the start of .
+func StrTill(haystack string, needle string) string {
+ pos := strings.Index(haystack, needle)
+ if pos == NotFoundIndex || pos == 0 {
+ return ""
+ }
+ return haystack[:pos+1]
+}
+
+// StrTillEx returns part of string ending to and excluding
+// the first occurrence of from the start of .
+func StrTillEx(haystack string, needle string) string {
+ pos := strings.Index(haystack, needle)
+ if pos == NotFoundIndex || pos == 0 {
+ return ""
+ }
+ return haystack[:pos]
+}
+
// Shuffle randomly shuffles a string.
// It considers parameter as unicode string.
func Shuffle(str string) string {
@@ -687,10 +714,10 @@ func SearchArray(a []string, s string) int {
return i
}
}
- return -1
+ return NotFoundIndex
}
// InArray checks whether string in slice .
func InArray(a []string, s string) bool {
- return SearchArray(a, s) != -1
+ return SearchArray(a, s) != NotFoundIndex
}
diff --git a/text/gstr/gstr_pos.go b/text/gstr/gstr_pos.go
index 6fbb4420a..6009cd7cb 100644
--- a/text/gstr/gstr_pos.go
+++ b/text/gstr/gstr_pos.go
@@ -20,13 +20,12 @@ func Pos(haystack, needle string, startOffset ...int) int {
if length == 0 || offset > length || -offset > length {
return -1
}
-
if offset < 0 {
offset += length
}
pos := strings.Index(haystack[offset:], needle)
- if pos == -1 {
- return -1
+ if pos == NotFoundIndex {
+ return NotFoundIndex
}
return pos + offset
}
diff --git a/text/gstr/gstr_trim.go b/text/gstr/gstr_trim.go
index 5b0e466b7..a2cdecf81 100644
--- a/text/gstr/gstr_trim.go
+++ b/text/gstr/gstr_trim.go
@@ -28,11 +28,11 @@ var (
// Trim strips whitespace (or other characters) from the beginning and end of a string.
// The optional parameter specifies the additional stripped characters.
func Trim(str string, characterMask ...string) string {
- if len(characterMask) == 0 {
- return strings.Trim(str, defaultTrimChars)
- } else {
- return strings.Trim(str, defaultTrimChars+characterMask[0])
+ trimChars := defaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
}
+ return strings.Trim(str, trimChars)
}
// TrimStr strips all of the given string from the beginning and end of a string.
@@ -43,11 +43,11 @@ func TrimStr(str string, cut string, count ...int) string {
// TrimLeft strips whitespace (or other characters) from the beginning of a string.
func TrimLeft(str string, characterMask ...string) string {
- if len(characterMask) == 0 {
- return strings.TrimLeft(str, defaultTrimChars)
- } else {
- return strings.TrimLeft(str, defaultTrimChars+characterMask[0])
+ trimChars := defaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
}
+ return strings.TrimLeft(str, trimChars)
}
// TrimLeftStr strips all of the given string from the beginning of a string.
@@ -69,11 +69,11 @@ func TrimLeftStr(str string, cut string, count ...int) string {
// TrimRight strips whitespace (or other characters) from the end of a string.
func TrimRight(str string, characterMask ...string) string {
- if len(characterMask) == 0 {
- return strings.TrimRight(str, defaultTrimChars)
- } else {
- return strings.TrimRight(str, defaultTrimChars+characterMask[0])
+ trimChars := defaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
}
+ return strings.TrimRight(str, trimChars)
}
// TrimRightStr strips all of the given string from the end of a string.
@@ -94,3 +94,28 @@ func TrimRightStr(str string, cut string, count ...int) string {
}
return str
}
+
+// TrimAll trims all characters in string `str`.
+func TrimAll(str string, characterMask ...string) string {
+ trimChars := defaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
+ }
+ var (
+ filtered bool
+ slice = make([]rune, 0, len(str))
+ )
+ for _, char := range str {
+ filtered = false
+ for _, trimChar := range trimChars {
+ if char == trimChar {
+ filtered = true
+ break
+ }
+ }
+ if !filtered {
+ slice = append(slice, char)
+ }
+ }
+ return string(slice)
+}
diff --git a/text/gstr/gstr_z_unit_basic_test.go b/text/gstr/gstr_z_unit_basic_test.go
index 76cb2eadc..6e3934dc3 100644
--- a/text/gstr/gstr_z_unit_basic_test.go
+++ b/text/gstr/gstr_z_unit_basic_test.go
@@ -303,6 +303,22 @@ func Test_StrEx(t *testing.T) {
})
}
+func Test_StrTill(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gstr.StrTill("name@example.com", "@"), "name@")
+ t.Assert(gstr.StrTill("name@example.com", ""), "")
+ t.Assert(gstr.StrTill("name@example.com", "z"), "")
+ })
+}
+
+func Test_StrTillEx(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gstr.StrTillEx("name@example.com", "@"), "name")
+ t.Assert(gstr.StrTillEx("name@example.com", ""), "")
+ t.Assert(gstr.StrTillEx("name@example.com", "z"), "")
+ })
+}
+
func Test_Shuffle(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(len(gstr.Shuffle("123456")), 6)
diff --git a/text/gstr/gstr_z_unit_trim_test.go b/text/gstr/gstr_z_unit_trim_test.go
index dd694c1d8..8415ae731 100644
--- a/text/gstr/gstr_z_unit_trim_test.go
+++ b/text/gstr/gstr_z_unit_trim_test.go
@@ -81,3 +81,17 @@ func Test_TrimLeftStr(t *testing.T) {
t.Assert(gstr.TrimLeftStr("我爱中国人", "我爱中国"), "人")
})
}
+
+func Test_TrimAll(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gstr.TrimAll("gogo我go\n爱gogo\n", "go"), "我爱")
+ })
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gstr.TrimAll("gogo\n我go爱gogo", "go"), "我爱")
+ t.Assert(gstr.TrimAll("gogo\n我go爱gogo\n", "go"), "我爱")
+ t.Assert(gstr.TrimAll("gogo\n我go\n爱gogo", "go"), "我爱")
+ })
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gstr.TrimAll("啊我爱\n啊中国\n人啊", "啊"), "我爱中国人")
+ })
+}
diff --git a/util/gmeta/gmeta.go b/util/gmeta/gmeta.go
index 2a2c357a3..4969537c2 100644
--- a/util/gmeta/gmeta.go
+++ b/util/gmeta/gmeta.go
@@ -11,22 +11,23 @@ import (
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/container/gvar"
"github.com/gogf/gf/internal/structs"
- "strconv"
)
// Meta is used as an embedded attribute for struct to enabled meta data feature.
type Meta struct{}
const (
+ // metaAttributeName is the attribute name of meta data in struct.
metaAttributeName = "Meta"
)
var (
+ // metaDataCacheMap is a cache map for struct type to enhance the performance.
metaDataCacheMap = gmap.NewStrAnyMap(true)
)
// Data retrieves and returns all meta data from `object`.
-// It automatically parses the tag string from "Mata" attribute as its meta data.
+// It automatically parses and caches the tag string from "Mata" attribute as its meta data.
func Data(object interface{}) map[string]interface{} {
reflectType, err := structs.StructType(object)
if err != nil {
@@ -35,52 +36,11 @@ func Data(object interface{}) map[string]interface{} {
return metaDataCacheMap.GetOrSetFuncLock(reflectType.Signature(), func() interface{} {
if field, ok := reflectType.FieldByName(metaAttributeName); ok {
var (
- key string
- tag = field.Tag
- data = make(map[string]interface{})
+ tags = structs.ParseTag(string(field.Tag))
+ data = make(map[string]interface{}, len(tags))
)
- for tag != "" {
- // Skip leading space.
- i := 0
- for i < len(tag) && tag[i] == ' ' {
- i++
- }
- tag = tag[i:]
- if tag == "" {
- break
- }
- // Scan to colon. A space, a quote or a control character is a syntax error.
- // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
- // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
- // as it is simpler to inspect the tag's bytes than the tag's runes.
- i = 0
- for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
- i++
- }
- if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
- break
- }
- key = string(tag[:i])
- tag = tag[i+1:]
-
- // Scan quoted string to find value.
- i = 1
- for i < len(tag) && tag[i] != '"' {
- if tag[i] == '\\' {
- i++
- }
- i++
- }
- if i >= len(tag) {
- break
- }
- quotedValue := string(tag[:i+1])
- tag = tag[i+1:]
- value, err := strconv.Unquote(quotedValue)
- if err != nil {
- panic(err)
- }
- data[key] = value
+ for k, v := range tags {
+ data[k] = v
}
return data
}
diff --git a/util/gvalid/gvalid_validator_check_struct.go b/util/gvalid/gvalid_validator_check_struct.go
index 9fe1b105d..580defc75 100644
--- a/util/gvalid/gvalid_validator_check_struct.go
+++ b/util/gvalid/gvalid_validator_check_struct.go
@@ -24,7 +24,7 @@ var (
// if is type of []string.
// The optional parameter specifies the custom error messages for specified keys and rules.
func (v *Validator) CheckStruct(object interface{}, rules interface{}, messages ...CustomMsg) *Error {
- // It here must use structs.TagFields not structs.MapField to ensure error sequence.
+ // It here must use structs.TagFields not structs.FieldMap to ensure error sequence.
tagField, err := structs.TagFields(object, structTagPriority)
if err != nil {
return newErrorStr("invalid_object", err.Error())
@@ -85,13 +85,13 @@ func (v *Validator) CheckStruct(object interface{}, rules interface{}, messages
return nil
}
// Checks and extends the parameters map with struct alias tag.
- mapField, err := structs.MapField(object, aliasNameTagPriority)
+ mapField, err := structs.FieldMap(object, aliasNameTagPriority)
if err != nil {
return newErrorStr("invalid_object", err.Error())
}
for nameOrTag, field := range mapField {
- params[nameOrTag] = field.Value()
- params[field.Name()] = field.Value()
+ params[nameOrTag] = field.Value.Interface()
+ params[field.Name()] = field.Value.Interface()
}
for _, field := range tagField {
fieldName := field.Name()
@@ -105,7 +105,7 @@ func (v *Validator) CheckStruct(object interface{}, rules interface{}, messages
}
// It here extends the params map using alias names.
if _, ok := params[name]; !ok {
- params[name] = field.Value()
+ params[name] = field.Value.Interface()
}
if _, ok := checkRules[name]; !ok {
if _, ok := checkRules[fieldName]; ok {