From acf47f3907ede0bd4a941eb63cd5a920a1d0ad3b Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 8 Feb 2021 17:57:21 +0800 Subject: [PATCH] orm with feature --- database/gdb/gdb.go | 42 ++-- database/gdb/gdb_core.go | 206 +++++++++--------- database/gdb/gdb_core_config.go | 2 +- database/gdb/gdb_core_structure.go | 8 +- database/gdb/gdb_core_tracing.go | 24 +- database/gdb/gdb_core_utility.go | 16 +- database/gdb/gdb_driver_mssql.go | 10 +- database/gdb/gdb_driver_mysql.go | 10 +- database/gdb/gdb_driver_oracle.go | 33 ++- database/gdb/gdb_driver_pgsql.go | 10 +- database/gdb/gdb_driver_sqlite.go | 10 +- database/gdb/gdb_func.go | 87 ++++---- database/gdb/gdb_model.go | 42 ++-- database/gdb/gdb_model_cache.go | 12 +- database/gdb/gdb_model_condition.go | 10 +- database/gdb/gdb_model_delete.go | 2 +- database/gdb/gdb_model_fields.go | 12 +- database/gdb/gdb_model_insert.go | 10 +- database/gdb/gdb_model_join.go | 8 +- database/gdb/gdb_model_select.go | 60 ++--- database/gdb/gdb_model_update.go | 2 +- database/gdb/gdb_model_utility.go | 12 +- database/gdb/gdb_model_with.go | 80 ++++++- database/gdb/gdb_schema.go | 4 +- database/gdb/gdb_statement.go | 4 +- database/gdb/gdb_transaction.go | 44 ++-- database/gdb/gdb_type_record.go | 16 +- database/gdb/gdb_type_result.go | 30 +-- database/gdb/gdb_type_result_scanlist.go | 6 +- .../gdb/gdb_z_mysql_association_with_test.go | 22 +- frame/g/g.go | 86 ++++---- frame/g/g_object.go | 14 +- internal/command/command.go | 12 +- internal/empty/empty.go | 10 +- internal/intlog/intlog.go | 16 +- internal/mutex/mutex.go | 2 +- internal/rwmutex/rwmutex.go | 4 +- internal/structs/structs.go | 35 +-- .../{structs_map.go => structs_field.go} | 39 +++- internal/structs/structs_tag.go | 71 +++++- internal/structs/structs_type.go | 43 +++- internal/structs/structs_z_unit_test.go | 91 +++++++- internal/utils/utils_str.go | 4 +- text/gstr/gstr.go | 41 +++- text/gstr/gstr_pos.go | 5 +- text/gstr/gstr_trim.go | 49 ++++- text/gstr/gstr_z_unit_basic_test.go | 16 ++ text/gstr/gstr_z_unit_trim_test.go | 14 ++ util/gmeta/gmeta.go | 54 +---- util/gvalid/gvalid_validator_check_struct.go | 10 +- 50 files changed, 890 insertions(+), 560 deletions(-) rename internal/structs/{structs_map.go => structs_field.go} (52%) 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