mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
improving package gdb
This commit is contained in:
121
.example/database/gdb/driver/driver.go
Normal file
121
.example/database/gdb/driver/driver.go
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
|
||||
_ "github.com/gf-third/mysql"
|
||||
)
|
||||
|
||||
type MyDriver struct {
|
||||
*gdb.Core
|
||||
}
|
||||
|
||||
// Open creates and returns a underlying sql.DB object for mysql.
|
||||
func (d *MyDriver) Open(config *gdb.ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
} else {
|
||||
source = fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%s)/%s?charset=%s&multiStatements=true&parseTime=true&loc=Local",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name, config.Charset,
|
||||
)
|
||||
}
|
||||
intlog.Printf("Open: %s", source)
|
||||
if db, err := sql.Open("gf-mysql", source); err == nil {
|
||||
return db, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// getChars returns the security char for this type of database.
|
||||
func (d *MyDriver) GetChars() (charLeft string, charRight string) {
|
||||
return "`", "`"
|
||||
}
|
||||
|
||||
// handleSqlBeforeExec handles the sql before posts it to database.
|
||||
func (d *MyDriver) HandleSqlBeforeExec(sql string) string {
|
||||
return sql
|
||||
}
|
||||
|
||||
// Tables retrieves and returns the tables of current schema.
|
||||
func (d *MyDriver) Tables(schema ...string) (tables []string, err error) {
|
||||
var result gdb.Result
|
||||
link, err := d.DB.GetSlave(schema...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = d.DB.DoGetAll(link, `SHOW TABLES`)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, m := range result {
|
||||
for _, v := range m {
|
||||
tables = append(tables, v.String())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// gdb.TableFields retrieves and returns the fields information of specified table of current schema.
|
||||
//
|
||||
// Note that it returns a map containing the field name and its corresponding fields.
|
||||
// As a map is unsorted, the gdb.TableField struct has a "Index" field marks its sequence in the fields.
|
||||
//
|
||||
// It's using cache feature to enhance the performance, which is never expired util the process restarts.
|
||||
func (d *MyDriver) TableFields(table string, schema ...string) (fields map[string]*gdb.TableField, err error) {
|
||||
table = gstr.Trim(table)
|
||||
if gstr.Contains(table, " ") {
|
||||
panic("function gdb.TableFields supports only single table operations")
|
||||
}
|
||||
checkSchema := d.DB.GetSchema()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := d.DB.GetCache().GetOrSetFunc(
|
||||
fmt.Sprintf(`mysql_table_fields_%s_%s`, table, checkSchema),
|
||||
func() interface{} {
|
||||
var result gdb.Result
|
||||
var link *sql.DB
|
||||
link, err = d.DB.GetSlave(checkSchema)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
result, err = d.DB.DoGetAll(
|
||||
link,
|
||||
fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.DB.QuoteWord(table)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
fields = make(map[string]*gdb.TableField)
|
||||
for i, m := range result {
|
||||
fields[m["Field"].String()] = &gdb.TableField{
|
||||
Index: i,
|
||||
Name: m["Field"].String(),
|
||||
Type: m["Type"].String(),
|
||||
Null: m["Null"].Bool(),
|
||||
Key: m["Key"].String(),
|
||||
Default: m["Default"].Val(),
|
||||
Extra: m["Extra"].String(),
|
||||
Comment: m["Comment"].String(),
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
if err == nil {
|
||||
fields = v.(map[string]*gdb.TableField)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -11,11 +11,11 @@ func main() {
|
||||
// 开启调试模式,以便于记录所有执行的SQL
|
||||
db.SetDebug(true)
|
||||
|
||||
r, e := db.Table("test").OrderBy("id asc").All()
|
||||
r, e := db.Table("test").Order("id asc").All()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
fmt.Println(e)
|
||||
}
|
||||
if r != nil {
|
||||
fmt.Println(r.ToList())
|
||||
fmt.Println(r.List())
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,5 +9,4 @@ func main() {
|
||||
db.SetDebug(true)
|
||||
|
||||
db.Table("user").Fields("DISTINCT id,nickname").Filter().All()
|
||||
|
||||
}
|
||||
|
||||
@ -34,14 +34,14 @@ type DB interface {
|
||||
Prepare(sql string, execOnMaster ...bool) (*sql.Stmt, error)
|
||||
|
||||
// Internal APIs for CURD, which can be overwrote for custom CURD implements.
|
||||
doQuery(link dbLink, query string, args ...interface{}) (rows *sql.Rows, err error)
|
||||
doGetAll(link dbLink, query string, args ...interface{}) (result Result, err error)
|
||||
doExec(link dbLink, query string, args ...interface{}) (result sql.Result, err error)
|
||||
doPrepare(link dbLink, query string) (*sql.Stmt, error)
|
||||
doInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error)
|
||||
doBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error)
|
||||
doUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error)
|
||||
doDelete(link dbLink, table string, condition string, args ...interface{}) (result sql.Result, err error)
|
||||
DoQuery(link dbLink, query string, args ...interface{}) (rows *sql.Rows, err error)
|
||||
DoGetAll(link dbLink, query string, args ...interface{}) (result Result, err error)
|
||||
DoExec(link dbLink, query string, args ...interface{}) (result sql.Result, err error)
|
||||
DoPrepare(link dbLink, query string) (*sql.Stmt, error)
|
||||
DoInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error)
|
||||
DoBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error)
|
||||
DoUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error)
|
||||
DoDelete(link dbLink, table string, condition string, args ...interface{}) (result sql.Result, err error)
|
||||
|
||||
// Query APIs for convenience purpose.
|
||||
GetAll(query string, args ...interface{}) (Result, error)
|
||||
@ -52,11 +52,11 @@ type DB interface {
|
||||
GetStructs(objPointerSlice interface{}, query string, args ...interface{}) error
|
||||
GetScan(objPointer interface{}, query string, args ...interface{}) error
|
||||
|
||||
// Master/Slave support.
|
||||
// Master/Slave specification support.
|
||||
Master() (*sql.DB, error)
|
||||
Slave() (*sql.DB, error)
|
||||
|
||||
// Ping.
|
||||
// Ping-Pong.
|
||||
PingMaster() error
|
||||
PingSlave() error
|
||||
|
||||
@ -75,48 +75,44 @@ type DB interface {
|
||||
Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)
|
||||
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)
|
||||
|
||||
// Create model.
|
||||
// Model creation.
|
||||
From(tables string) *Model
|
||||
Table(tables string) *Model
|
||||
Schema(schema string) *Schema
|
||||
|
||||
// Configuration methods.
|
||||
GetCache() *gcache.Cache
|
||||
SetDebug(debug bool)
|
||||
GetDebug() bool
|
||||
SetSchema(schema string)
|
||||
GetSchema() string
|
||||
GetPrefix() string
|
||||
SetLogger(logger *glog.Logger)
|
||||
GetLogger() *glog.Logger
|
||||
SetMaxIdleConnCount(n int)
|
||||
SetMaxOpenConnCount(n int)
|
||||
SetMaxConnLifetime(d time.Duration)
|
||||
|
||||
// Utility methods.
|
||||
GetChars() (charLeft string, charRight string)
|
||||
GetMaster(schema ...string) (*sql.DB, error)
|
||||
GetSlave(schema ...string) (*sql.DB, error)
|
||||
QuoteWord(s string) string
|
||||
QuoteString(s string) string
|
||||
HandleSqlBeforeExec(sql string) string
|
||||
Tables(schema ...string) (tables []string, err error)
|
||||
TableFields(table string, schema ...string) (map[string]*TableField, error)
|
||||
|
||||
// Internal methods.
|
||||
getCache() *gcache.Cache
|
||||
getChars() (charLeft string, charRight string)
|
||||
getDebug() bool
|
||||
getPrefix() string
|
||||
getMaster(schema ...string) (*sql.DB, error)
|
||||
getSlave(schema ...string) (*sql.DB, error)
|
||||
quoteWord(s string) string
|
||||
quoteString(s string) string
|
||||
handleTableName(table string) string
|
||||
filterFields(schema, table string, data map[string]interface{}) map[string]interface{}
|
||||
convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
rowsToResult(rows *sql.Rows) (Result, error)
|
||||
handleSqlBeforeExec(sql string) string
|
||||
}
|
||||
|
||||
// dbLink is a common database function wrapper interface for internal usage.
|
||||
type dbLink interface {
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
Exec(sql string, args ...interface{}) (sql.Result, error)
|
||||
Prepare(sql string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// dbBase is the base struct for database management.
|
||||
type dbBase struct {
|
||||
db DB // DB interface object.
|
||||
// Core is the base struct for database management.
|
||||
type Core struct {
|
||||
DB DB // DB interface object.
|
||||
group string // Configuration group name.
|
||||
debug *gtype.Bool // Enable debug mode for the database.
|
||||
cache *gcache.Cache // Cache manager.
|
||||
@ -128,6 +124,11 @@ type dbBase struct {
|
||||
maxConnLifetime time.Duration // Max TTL for a connection.
|
||||
}
|
||||
|
||||
// Driver is the interface for integrating sql drivers into package gdb.
|
||||
type Driver interface {
|
||||
New(core *Core, node *ConfigNode) (DB, error)
|
||||
}
|
||||
|
||||
// Sql is the sql recording struct.
|
||||
type Sql struct {
|
||||
Sql string // SQL string(may contain reserved char '?').
|
||||
@ -150,6 +151,13 @@ type TableField struct {
|
||||
Comment string // Comment.
|
||||
}
|
||||
|
||||
// dbLink is a common database function wrapper interface for internal usage.
|
||||
type dbLink interface {
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
Exec(sql string, args ...interface{}) (sql.Result, error)
|
||||
Prepare(sql string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// Value is the field value type.
|
||||
type Value = *gvar.Var
|
||||
|
||||
@ -176,10 +184,23 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Instance map.
|
||||
// instances is the management map for instances.
|
||||
instances = gmap.NewStrAnyMap(true)
|
||||
// driverMap manages all custom registered driver.
|
||||
driverMap = map[string]Driver{
|
||||
"mysql": &DriverMysql{},
|
||||
"mssql": &DriverMssql{},
|
||||
"oracle": &DriverOracle{},
|
||||
"sqlite": &DriverSqlite{},
|
||||
}
|
||||
)
|
||||
|
||||
// Register registers custom database driver to gdb.
|
||||
func Register(name string, driver Driver) error {
|
||||
driverMap[name] = driver
|
||||
return nil
|
||||
}
|
||||
|
||||
// New creates and returns an ORM object with global configurations.
|
||||
// The parameter <name> specifies the configuration group name,
|
||||
// which is DEFAULT_GROUP_NAME in default.
|
||||
@ -196,31 +217,24 @@ func New(name ...string) (db DB, err error) {
|
||||
}
|
||||
if _, ok := configs.config[group]; ok {
|
||||
if node, err := getConfigNodeByGroup(group, true); err == nil {
|
||||
base := &dbBase{
|
||||
group: group,
|
||||
debug: gtype.NewBool(),
|
||||
cache: gcache.New(),
|
||||
schema: gtype.NewString(),
|
||||
logger: glog.New(),
|
||||
prefix: node.Prefix,
|
||||
// Default max connection life time if user does not configure.
|
||||
maxConnLifetime: gDEFAULT_CONN_MAX_LIFE_TIME,
|
||||
c := &Core{
|
||||
group: group,
|
||||
debug: gtype.NewBool(),
|
||||
cache: gcache.New(),
|
||||
schema: gtype.NewString(),
|
||||
logger: glog.New(),
|
||||
prefix: node.Prefix,
|
||||
maxConnLifetime: gDEFAULT_CONN_MAX_LIFE_TIME, // Default max connection life time if user does not configure.
|
||||
}
|
||||
switch node.Type {
|
||||
case "mysql":
|
||||
base.db = &dbMysql{dbBase: base}
|
||||
case "pgsql":
|
||||
base.db = &dbPgsql{dbBase: base}
|
||||
case "mssql":
|
||||
base.db = &dbMssql{dbBase: base}
|
||||
case "sqlite":
|
||||
base.db = &dbSqlite{dbBase: base}
|
||||
case "oracle":
|
||||
base.db = &dbOracle{dbBase: base}
|
||||
default:
|
||||
if v, ok := driverMap[node.Type]; ok {
|
||||
c.DB, err = v.New(c, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.DB, nil
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf(`unsupported database type "%s"`, node.Type))
|
||||
}
|
||||
return base.db, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
@ -321,9 +335,9 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
|
||||
// getSqlDb retrieves and returns a underlying database connection object.
|
||||
// The parameter <master> specifies whether retrieves master node connection if
|
||||
// master-slave nodes are configured.
|
||||
func (bs *dbBase) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
|
||||
func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
|
||||
// Load balance.
|
||||
node, err := getConfigNodeByGroup(bs.group, master)
|
||||
node, err := getConfigNodeByGroup(c.group, master)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -332,7 +346,7 @@ func (bs *dbBase) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err er
|
||||
node.Charset = "utf8"
|
||||
}
|
||||
// Changes the schema.
|
||||
nodeSchema := bs.schema.Val()
|
||||
nodeSchema := c.schema.Val()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
nodeSchema = schema[0]
|
||||
}
|
||||
@ -343,25 +357,25 @@ func (bs *dbBase) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err er
|
||||
node = &n
|
||||
}
|
||||
// Cache the underlying connection object by node.
|
||||
v := bs.cache.GetOrSetFuncLock(node.String(), func() interface{} {
|
||||
sqlDb, err = bs.db.Open(node)
|
||||
v := c.cache.GetOrSetFuncLock(node.String(), func() interface{} {
|
||||
sqlDb, err = c.DB.Open(node)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if bs.maxIdleConnCount > 0 {
|
||||
sqlDb.SetMaxIdleConns(bs.maxIdleConnCount)
|
||||
if c.maxIdleConnCount > 0 {
|
||||
sqlDb.SetMaxIdleConns(c.maxIdleConnCount)
|
||||
} else if node.MaxIdleConnCount > 0 {
|
||||
sqlDb.SetMaxIdleConns(node.MaxIdleConnCount)
|
||||
}
|
||||
|
||||
if bs.maxOpenConnCount > 0 {
|
||||
sqlDb.SetMaxOpenConns(bs.maxOpenConnCount)
|
||||
if c.maxOpenConnCount > 0 {
|
||||
sqlDb.SetMaxOpenConns(c.maxOpenConnCount)
|
||||
} else if node.MaxOpenConnCount > 0 {
|
||||
sqlDb.SetMaxOpenConns(node.MaxOpenConnCount)
|
||||
}
|
||||
|
||||
if bs.maxConnLifetime > 0 {
|
||||
sqlDb.SetConnMaxLifetime(bs.maxConnLifetime * time.Second)
|
||||
if c.maxConnLifetime > 0 {
|
||||
sqlDb.SetConnMaxLifetime(c.maxConnLifetime * time.Second)
|
||||
} else if node.MaxConnLifetime > 0 {
|
||||
sqlDb.SetConnMaxLifetime(node.MaxConnLifetime * time.Second)
|
||||
}
|
||||
@ -371,40 +385,7 @@ func (bs *dbBase) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err er
|
||||
sqlDb = v.(*sql.DB)
|
||||
}
|
||||
if node.Debug {
|
||||
bs.db.SetDebug(node.Debug)
|
||||
c.DB.SetDebug(node.Debug)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetSchema changes the schema for this database connection object.
|
||||
// Importantly note that when schema configuration changed for the database,
|
||||
// it affects all operations on the database object in the future.
|
||||
func (bs *dbBase) SetSchema(schema string) {
|
||||
bs.schema.Set(schema)
|
||||
}
|
||||
|
||||
// Master creates and returns a connection from master node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (bs *dbBase) Master() (*sql.DB, error) {
|
||||
return bs.getSqlDb(true, bs.schema.Val())
|
||||
}
|
||||
|
||||
// Slave creates and returns a connection from slave node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (bs *dbBase) Slave() (*sql.DB, error) {
|
||||
return bs.getSqlDb(false, bs.schema.Val())
|
||||
}
|
||||
|
||||
// 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 (bs *dbBase) getMaster(schema ...string) (*sql.DB, error) {
|
||||
return bs.getSqlDb(true, schema...)
|
||||
}
|
||||
|
||||
// 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 (bs *dbBase) getSlave(schema ...string) (*sql.DB, error) {
|
||||
return bs.getSqlDb(false, schema...)
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -32,22 +31,34 @@ var (
|
||||
lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`)
|
||||
)
|
||||
|
||||
// Master creates and returns a connection from master node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (c *Core) Master() (*sql.DB, error) {
|
||||
return c.getSqlDb(true, c.schema.Val())
|
||||
}
|
||||
|
||||
// Slave creates and returns a connection from slave node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (c *Core) Slave() (*sql.DB, error) {
|
||||
return c.getSqlDb(false, c.schema.Val())
|
||||
}
|
||||
|
||||
// Query commits one query SQL to underlying driver and returns the execution result.
|
||||
// It is most commonly used for data querying.
|
||||
func (bs *dbBase) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
link, err := bs.db.Slave()
|
||||
func (c *Core) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
link, err := c.DB.Slave()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bs.db.doQuery(link, query, args...)
|
||||
return c.DB.DoQuery(link, query, args...)
|
||||
}
|
||||
|
||||
// doQuery commits the query string and its arguments to underlying driver
|
||||
// through given link object and returns the execution result.
|
||||
func (bs *dbBase) doQuery(link dbLink, query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
func (c *Core) DoQuery(link dbLink, query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
query, args = formatQuery(query, args)
|
||||
query = bs.db.handleSqlBeforeExec(query)
|
||||
if bs.db.getDebug() {
|
||||
query = c.DB.HandleSqlBeforeExec(query)
|
||||
if c.DB.GetDebug() {
|
||||
mTime1 := gtime.TimestampMilli()
|
||||
rows, err = link.Query(query, args...)
|
||||
mTime2 := gtime.TimestampMilli()
|
||||
@ -59,7 +70,7 @@ func (bs *dbBase) doQuery(link dbLink, query string, args ...interface{}) (rows
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
}
|
||||
bs.printSql(s)
|
||||
c.printSql(s)
|
||||
} else {
|
||||
rows, err = link.Query(query, args...)
|
||||
}
|
||||
@ -73,20 +84,20 @@ func (bs *dbBase) doQuery(link dbLink, query string, args ...interface{}) (rows
|
||||
|
||||
// Exec commits one query SQL to underlying driver and returns the execution result.
|
||||
// It is most commonly used for data inserting and updating.
|
||||
func (bs *dbBase) Exec(query string, args ...interface{}) (result sql.Result, err error) {
|
||||
link, err := bs.db.Master()
|
||||
func (c *Core) Exec(query string, args ...interface{}) (result sql.Result, err error) {
|
||||
link, err := c.DB.Master()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bs.db.doExec(link, query, args...)
|
||||
return c.DB.DoExec(link, query, args...)
|
||||
}
|
||||
|
||||
// doExec commits the query string and its arguments to underlying driver
|
||||
// through given link object and returns the execution result.
|
||||
func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result sql.Result, err error) {
|
||||
func (c *Core) DoExec(link dbLink, query string, args ...interface{}) (result sql.Result, err error) {
|
||||
query, args = formatQuery(query, args)
|
||||
query = bs.db.handleSqlBeforeExec(query)
|
||||
if bs.db.getDebug() {
|
||||
query = c.DB.HandleSqlBeforeExec(query)
|
||||
if c.DB.GetDebug() {
|
||||
mTime1 := gtime.TimestampMilli()
|
||||
result, err = link.Exec(query, args...)
|
||||
mTime2 := gtime.TimestampMilli()
|
||||
@ -98,7 +109,7 @@ func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
}
|
||||
bs.printSql(s)
|
||||
c.printSql(s)
|
||||
} else {
|
||||
result, err = link.Exec(query, args...)
|
||||
}
|
||||
@ -113,50 +124,50 @@ func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result
|
||||
//
|
||||
// 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 (bs *dbBase) Prepare(query string, execOnMaster ...bool) (*sql.Stmt, error) {
|
||||
func (c *Core) Prepare(query string, execOnMaster ...bool) (*sql.Stmt, error) {
|
||||
err := (error)(nil)
|
||||
link := (dbLink)(nil)
|
||||
if len(execOnMaster) > 0 && execOnMaster[0] {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
if link, err = c.DB.Master(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if link, err = bs.db.Slave(); err != nil {
|
||||
if link, err = c.DB.Slave(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return bs.db.doPrepare(link, query)
|
||||
return c.DB.DoPrepare(link, query)
|
||||
}
|
||||
|
||||
// doPrepare calls prepare function on given link object and returns the statement object.
|
||||
func (bs *dbBase) doPrepare(link dbLink, query string) (*sql.Stmt, error) {
|
||||
func (c *Core) DoPrepare(link dbLink, query string) (*sql.Stmt, error) {
|
||||
return link.Prepare(query)
|
||||
}
|
||||
|
||||
// GetAll queries and returns data records from database.
|
||||
func (bs *dbBase) GetAll(query string, args ...interface{}) (Result, error) {
|
||||
return bs.db.doGetAll(nil, query, args...)
|
||||
func (c *Core) GetAll(query string, args ...interface{}) (Result, error) {
|
||||
return c.DB.DoGetAll(nil, query, args...)
|
||||
}
|
||||
|
||||
// doGetAll queries and returns data records from database.
|
||||
func (bs *dbBase) doGetAll(link dbLink, query string, args ...interface{}) (result Result, err error) {
|
||||
func (c *Core) DoGetAll(link dbLink, query string, args ...interface{}) (result Result, err error) {
|
||||
if link == nil {
|
||||
link, err = bs.db.Slave()
|
||||
link, err = c.DB.Slave()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rows, err := bs.doQuery(link, query, args...)
|
||||
rows, err := c.DB.DoQuery(link, query, args...)
|
||||
if err != nil || rows == nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
return bs.db.rowsToResult(rows)
|
||||
return c.DB.rowsToResult(rows)
|
||||
}
|
||||
|
||||
// GetOne queries and returns one record from database.
|
||||
func (bs *dbBase) GetOne(query string, args ...interface{}) (Record, error) {
|
||||
list, err := bs.GetAll(query, args...)
|
||||
func (c *Core) GetOne(query string, args ...interface{}) (Record, error) {
|
||||
list, err := c.DB.GetAll(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -168,8 +179,8 @@ func (bs *dbBase) GetOne(query string, args ...interface{}) (Record, error) {
|
||||
|
||||
// GetStruct queries one record from database and converts it to given struct.
|
||||
// The parameter <pointer> should be a pointer to struct.
|
||||
func (bs *dbBase) GetStruct(pointer interface{}, query string, args ...interface{}) error {
|
||||
one, err := bs.GetOne(query, args...)
|
||||
func (c *Core) GetStruct(pointer interface{}, query string, args ...interface{}) error {
|
||||
one, err := c.DB.GetOne(query, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -181,8 +192,8 @@ func (bs *dbBase) GetStruct(pointer interface{}, query string, args ...interface
|
||||
|
||||
// GetStructs queries records from database and converts them to given struct.
|
||||
// The parameter <pointer> should be type of struct slice: []struct/[]*struct.
|
||||
func (bs *dbBase) GetStructs(pointer interface{}, query string, args ...interface{}) error {
|
||||
all, err := bs.GetAll(query, args...)
|
||||
func (c *Core) GetStructs(pointer interface{}, query string, args ...interface{}) error {
|
||||
all, err := c.DB.GetAll(query, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -198,7 +209,7 @@ func (bs *dbBase) GetStructs(pointer interface{}, query string, args ...interfac
|
||||
// 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 (bs *dbBase) GetScan(pointer interface{}, query string, args ...interface{}) error {
|
||||
func (c *Core) GetScan(pointer interface{}, query string, args ...interface{}) error {
|
||||
t := reflect.TypeOf(pointer)
|
||||
k := t.Kind()
|
||||
if k != reflect.Ptr {
|
||||
@ -207,9 +218,9 @@ func (bs *dbBase) GetScan(pointer interface{}, query string, args ...interface{}
|
||||
k = t.Elem().Kind()
|
||||
switch k {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return bs.db.GetStructs(pointer, query, args...)
|
||||
return c.DB.GetStructs(pointer, query, args...)
|
||||
case reflect.Struct:
|
||||
return bs.db.GetStruct(pointer, query, args...)
|
||||
return c.DB.GetStruct(pointer, query, args...)
|
||||
}
|
||||
return fmt.Errorf("element type should be type of struct/slice, unsupported: %v", k)
|
||||
}
|
||||
@ -217,8 +228,8 @@ func (bs *dbBase) GetScan(pointer interface{}, query string, args ...interface{}
|
||||
// GetValue queries and returns the field value from database.
|
||||
// The sql should queries only one field from database, or else it returns only one
|
||||
// field of the result.
|
||||
func (bs *dbBase) GetValue(query string, args ...interface{}) (Value, error) {
|
||||
one, err := bs.GetOne(query, args...)
|
||||
func (c *Core) GetValue(query string, args ...interface{}) (Value, error) {
|
||||
one, err := c.DB.GetOne(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -229,13 +240,13 @@ func (bs *dbBase) GetValue(query string, args ...interface{}) (Value, error) {
|
||||
}
|
||||
|
||||
// GetCount queries and returns the count from database.
|
||||
func (bs *dbBase) GetCount(query string, args ...interface{}) (int, error) {
|
||||
func (c *Core) GetCount(query string, args ...interface{}) (int, error) {
|
||||
// If the query fields do not contains function "COUNT",
|
||||
// it replaces the query string and adds the "COUNT" function to the fields.
|
||||
if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, query) {
|
||||
query, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, query)
|
||||
}
|
||||
value, err := bs.GetValue(query, args...)
|
||||
value, err := c.DB.GetValue(query, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -243,8 +254,8 @@ func (bs *dbBase) GetCount(query string, args ...interface{}) (int, error) {
|
||||
}
|
||||
|
||||
// PingMaster pings the master node to check authentication or keeps the connection alive.
|
||||
func (bs *dbBase) PingMaster() error {
|
||||
if master, err := bs.db.Master(); err != nil {
|
||||
func (c *Core) PingMaster() error {
|
||||
if master, err := c.DB.Master(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return master.Ping()
|
||||
@ -252,8 +263,8 @@ func (bs *dbBase) PingMaster() error {
|
||||
}
|
||||
|
||||
// PingSlave pings the slave node to check authentication or keeps the connection alive.
|
||||
func (bs *dbBase) PingSlave() error {
|
||||
if slave, err := bs.db.Slave(); err != nil {
|
||||
func (c *Core) PingSlave() error {
|
||||
if slave, err := c.DB.Slave(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return slave.Ping()
|
||||
@ -264,13 +275,13 @@ func (bs *dbBase) PingSlave() error {
|
||||
// You should call Commit or Rollback functions of the transaction object
|
||||
// if you no longer use the transaction. Commit or Rollback functions will also
|
||||
// close the transaction automatically.
|
||||
func (bs *dbBase) Begin() (*TX, error) {
|
||||
if master, err := bs.db.Master(); err != nil {
|
||||
func (c *Core) Begin() (*TX, error) {
|
||||
if master, err := c.DB.Master(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if tx, err := master.Begin(); err == nil {
|
||||
return &TX{
|
||||
db: bs.db,
|
||||
db: c.DB,
|
||||
tx: tx,
|
||||
master: master,
|
||||
}, nil
|
||||
@ -289,8 +300,8 @@ func (bs *dbBase) Begin() (*TX, error) {
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
//
|
||||
// The parameter <batch> specifies the batch operation count when given data is slice.
|
||||
func (bs *dbBase) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_DEFAULT, batch...)
|
||||
func (c *Core) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoInsert(nil, table, data, gINSERT_OPTION_DEFAULT, batch...)
|
||||
}
|
||||
|
||||
// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
|
||||
@ -302,8 +313,8 @@ func (bs *dbBase) Insert(table string, data interface{}, batch ...int) (sql.Resu
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
//
|
||||
// The parameter <batch> specifies the batch operation count when given data is slice.
|
||||
func (bs *dbBase) InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_IGNORE, batch...)
|
||||
func (c *Core) InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoInsert(nil, table, data, gINSERT_OPTION_IGNORE, batch...)
|
||||
}
|
||||
|
||||
// Replace does "REPLACE INTO ..." statement for the table.
|
||||
@ -318,8 +329,8 @@ func (bs *dbBase) InsertIgnore(table string, data interface{}, batch ...int) (sq
|
||||
// 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
|
||||
// <batch> specifies the batch operation count.
|
||||
func (bs *dbBase) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_REPLACE, batch...)
|
||||
func (c *Core) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoInsert(nil, table, data, gINSERT_OPTION_REPLACE, batch...)
|
||||
}
|
||||
|
||||
// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table.
|
||||
@ -333,8 +344,8 @@ func (bs *dbBase) Replace(table string, data interface{}, batch ...int) (sql.Res
|
||||
//
|
||||
// If given data is type of slice, it then does batch saving, and the optional parameter
|
||||
// <batch> specifies the batch operation count.
|
||||
func (bs *dbBase) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_SAVE, batch...)
|
||||
func (c *Core) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoInsert(nil, table, data, gINSERT_OPTION_SAVE, batch...)
|
||||
}
|
||||
|
||||
// doInsert inserts or updates data for given table.
|
||||
@ -344,12 +355,12 @@ func (bs *dbBase) Save(table string, data interface{}, batch ...int) (sql.Result
|
||||
// 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 (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
func (c *Core) DoInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var fields []string
|
||||
var values []string
|
||||
var params []interface{}
|
||||
var dataMap Map
|
||||
table = bs.db.handleTableName(table)
|
||||
table = c.DB.handleTableName(table)
|
||||
rv := reflect.ValueOf(data)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
@ -358,7 +369,7 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
return bs.db.doBatchInsert(link, table, data, option, batch...)
|
||||
return c.DB.DoBatchInsert(link, table, data, option, batch...)
|
||||
case reflect.Map, reflect.Struct:
|
||||
dataMap = varToMapDeep(data)
|
||||
default:
|
||||
@ -367,7 +378,7 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
if len(dataMap) == 0 {
|
||||
return nil, errors.New("data cannot be empty")
|
||||
}
|
||||
charL, charR := bs.db.getChars()
|
||||
charL, charR := c.DB.GetChars()
|
||||
for k, v := range dataMap {
|
||||
fields = append(fields, charL+k+charR)
|
||||
values = append(values, "?")
|
||||
@ -388,11 +399,11 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
updateStr = fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", updateStr)
|
||||
}
|
||||
if link == nil {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
if link, err = c.DB.Master(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return bs.db.doExec(link, fmt.Sprintf("%s INTO %s(%s) VALUES(%s) %s",
|
||||
return c.DB.DoExec(link, fmt.Sprintf("%s INTO %s(%s) VALUES(%s) %s",
|
||||
operation, table, strings.Join(fields, ","),
|
||||
strings.Join(values, ","), updateStr),
|
||||
params...)
|
||||
@ -400,33 +411,33 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
|
||||
// BatchInsert batch inserts data.
|
||||
// The parameter <list> must be type of slice of map or struct.
|
||||
func (bs *dbBase) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_DEFAULT, batch...)
|
||||
func (c *Core) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoBatchInsert(nil, table, list, gINSERT_OPTION_DEFAULT, batch...)
|
||||
}
|
||||
|
||||
// BatchInsert batch inserts data with ignore option.
|
||||
// The parameter <list> must be type of slice of map or struct.
|
||||
func (bs *dbBase) BatchInsertIgnore(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_IGNORE, batch...)
|
||||
func (c *Core) BatchInsertIgnore(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoBatchInsert(nil, table, list, gINSERT_OPTION_IGNORE, batch...)
|
||||
}
|
||||
|
||||
// BatchReplace batch replaces data.
|
||||
// The parameter <list> must be type of slice of map or struct.
|
||||
func (bs *dbBase) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_REPLACE, batch...)
|
||||
func (c *Core) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoBatchInsert(nil, table, list, gINSERT_OPTION_REPLACE, batch...)
|
||||
}
|
||||
|
||||
// BatchSave batch replaces data.
|
||||
// The parameter <list> must be type of slice of map or struct.
|
||||
func (bs *dbBase) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_SAVE, batch...)
|
||||
func (c *Core) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return c.DB.DoBatchInsert(nil, table, list, gINSERT_OPTION_SAVE, batch...)
|
||||
}
|
||||
|
||||
// doBatchInsert batch inserts/replaces/saves data.
|
||||
func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
func (c *Core) DoBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var keys, values []string
|
||||
var params []interface{}
|
||||
table = bs.db.handleTableName(table)
|
||||
table = c.DB.handleTableName(table)
|
||||
listMap := (List)(nil)
|
||||
switch v := list.(type) {
|
||||
case Result:
|
||||
@ -461,7 +472,7 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
return result, errors.New("data list cannot be empty")
|
||||
}
|
||||
if link == nil {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
if link, err = c.DB.Master(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -473,7 +484,7 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
}
|
||||
// Prepare the result pointer.
|
||||
batchResult := new(batchSqlResult)
|
||||
charL, charR := bs.db.getChars()
|
||||
charL, charR := c.DB.GetChars()
|
||||
keysStr := charL + strings.Join(keys, charR+","+charL) + charR
|
||||
valueHolderStr := "(" + strings.Join(holders, ",") + ")"
|
||||
|
||||
@ -504,7 +515,7 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
}
|
||||
values = append(values, valueHolderStr)
|
||||
if len(values) == batchNum || (i == listMapLen-1 && len(values) > 0) {
|
||||
r, err := bs.db.doExec(
|
||||
r, err := c.DB.DoExec(
|
||||
link,
|
||||
fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES%s %s",
|
||||
@ -546,18 +557,18 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
// "status IN (?)", g.Slice{1,2,3}
|
||||
// "age IN(?,?)", 18, 50
|
||||
// User{ Id : 1, UserName : "john"}
|
||||
func (bs *dbBase) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
newWhere, newArgs := formatWhere(bs.db, condition, args, false)
|
||||
func (c *Core) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
newWhere, newArgs := formatWhere(c.DB, condition, args, false)
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return bs.db.doUpdate(nil, table, data, newWhere, newArgs...)
|
||||
return c.DB.DoUpdate(nil, table, data, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
// doUpdate does "UPDATE ... " statement for the table.
|
||||
// Also see Update.
|
||||
func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
table = bs.db.handleTableName(table)
|
||||
func (c *Core) DoUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
table = c.DB.handleTableName(table)
|
||||
updates := ""
|
||||
rv := reflect.ValueOf(data)
|
||||
kind := rv.Kind()
|
||||
@ -570,7 +581,7 @@ func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, conditio
|
||||
case reflect.Map, reflect.Struct:
|
||||
var fields []string
|
||||
for k, v := range varToMapDeep(data) {
|
||||
fields = append(fields, bs.db.quoteWord(k)+"=?")
|
||||
fields = append(fields, c.DB.QuoteWord(k)+"=?")
|
||||
params = append(params, v)
|
||||
}
|
||||
updates = strings.Join(fields, ",")
|
||||
@ -585,11 +596,11 @@ func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, conditio
|
||||
}
|
||||
// If no link passed, it then uses the master link.
|
||||
if link == nil {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
if link, err = c.DB.Master(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return bs.db.doExec(link, fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition), args...)
|
||||
return c.DB.DoExec(link, fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition), args...)
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM ... " statement for the table.
|
||||
@ -603,38 +614,28 @@ func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, conditio
|
||||
// "status IN (?)", g.Slice{1,2,3}
|
||||
// "age IN(?,?)", 18, 50
|
||||
// User{ Id : 1, UserName : "john"}
|
||||
func (bs *dbBase) Delete(table string, condition interface{}, args ...interface{}) (result sql.Result, err error) {
|
||||
newWhere, newArgs := formatWhere(bs.db, condition, args, false)
|
||||
func (c *Core) Delete(table string, condition interface{}, args ...interface{}) (result sql.Result, err error) {
|
||||
newWhere, newArgs := formatWhere(c.DB, condition, args, false)
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return bs.db.doDelete(nil, table, newWhere, newArgs...)
|
||||
return c.DB.DoDelete(nil, table, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
// doDelete does "DELETE FROM ... " statement for the table.
|
||||
// Also see Delete.
|
||||
func (bs *dbBase) doDelete(link dbLink, table string, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
func (c *Core) DoDelete(link dbLink, table string, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
if link == nil {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
if link, err = c.DB.Master(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
table = bs.db.handleTableName(table)
|
||||
return bs.db.doExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
|
||||
}
|
||||
|
||||
// getCache returns the internal cache object.
|
||||
func (bs *dbBase) getCache() *gcache.Cache {
|
||||
return bs.cache
|
||||
}
|
||||
|
||||
// getPrefix returns the table prefix string configured.
|
||||
func (bs *dbBase) getPrefix() string {
|
||||
return bs.prefix
|
||||
table = c.DB.handleTableName(table)
|
||||
return c.DB.DoExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
|
||||
}
|
||||
|
||||
// rowsToResult converts underlying data record type sql.Rows to Result type.
|
||||
func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
func (c *Core) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
@ -671,7 +672,7 @@ func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
// it should do a copy of it.
|
||||
v := make([]byte, len(value))
|
||||
copy(v, value)
|
||||
row[columnNames[i]] = gvar.New(bs.db.convertValue(v, columnTypes[i]))
|
||||
row[columnNames[i]] = gvar.New(c.DB.convertValue(v, columnTypes[i]))
|
||||
}
|
||||
}
|
||||
records = append(records, row)
|
||||
@ -687,34 +688,20 @@ func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
//
|
||||
// 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 (bs *dbBase) handleTableName(table string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
prefix := bs.db.getPrefix()
|
||||
func (c *Core) handleTableName(table string) string {
|
||||
charLeft, charRight := c.DB.GetChars()
|
||||
prefix := c.DB.GetPrefix()
|
||||
return doHandleTableName(table, prefix, charLeft, charRight)
|
||||
}
|
||||
|
||||
// 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 (bs *dbBase) quoteWord(s string) string {
|
||||
charLeft, charRight := bs.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 (bs *dbBase) quoteString(s string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
return doQuoteString(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// printSql outputs the sql object to logger.
|
||||
// It is enabled when configuration "debug" is true.
|
||||
func (bs *dbBase) printSql(v *Sql) {
|
||||
func (c *Core) printSql(v *Sql) {
|
||||
s := fmt.Sprintf("[%d ms] %s", v.End-v.Start, v.Format)
|
||||
if v.Error != nil {
|
||||
s += "\nError: " + v.Error.Error()
|
||||
bs.logger.StackWithFilter(gPATH_FILTER_KEY).Error(s)
|
||||
c.logger.StackWithFilter(gPATH_FILTER_KEY).Error(s)
|
||||
} else {
|
||||
bs.logger.StackWithFilter(gPATH_FILTER_KEY).Debug(s)
|
||||
c.logger.StackWithFilter(gPATH_FILTER_KEY).Debug(s)
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ package gdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -114,29 +115,29 @@ func GetDefaultGroup() string {
|
||||
}
|
||||
|
||||
// SetLogger sets the logger for orm.
|
||||
func (bs *dbBase) SetLogger(logger *glog.Logger) {
|
||||
bs.logger = logger
|
||||
func (c *Core) SetLogger(logger *glog.Logger) {
|
||||
c.logger = logger
|
||||
}
|
||||
|
||||
// GetLogger returns the logger of the orm.
|
||||
func (bs *dbBase) GetLogger() *glog.Logger {
|
||||
return bs.logger
|
||||
func (c *Core) GetLogger() *glog.Logger {
|
||||
return c.logger
|
||||
}
|
||||
|
||||
// SetMaxIdleConnCount sets the max idle connection count for underlying connection pool.
|
||||
func (bs *dbBase) SetMaxIdleConnCount(n int) {
|
||||
bs.maxIdleConnCount = n
|
||||
func (c *Core) SetMaxIdleConnCount(n int) {
|
||||
c.maxIdleConnCount = n
|
||||
}
|
||||
|
||||
// SetMaxOpenConnCount sets the max open connection count for underlying connection pool.
|
||||
func (bs *dbBase) SetMaxOpenConnCount(n int) {
|
||||
bs.maxOpenConnCount = n
|
||||
func (c *Core) SetMaxOpenConnCount(n int) {
|
||||
c.maxOpenConnCount = n
|
||||
}
|
||||
|
||||
// SetMaxConnLifetime sets the connection TTL for underlying connection pool.
|
||||
// If parameter <d> <= 0, it means the connection never expires.
|
||||
func (bs *dbBase) SetMaxConnLifetime(d time.Duration) {
|
||||
bs.maxConnLifetime = d
|
||||
func (c *Core) SetMaxConnLifetime(d time.Duration) {
|
||||
c.maxConnLifetime = d
|
||||
}
|
||||
|
||||
// String returns the node as string.
|
||||
@ -155,14 +156,36 @@ func (node *ConfigNode) String() string {
|
||||
}
|
||||
|
||||
// SetDebug enables/disables the debug mode.
|
||||
func (bs *dbBase) SetDebug(debug bool) {
|
||||
if bs.debug.Val() == debug {
|
||||
func (c *Core) SetDebug(debug bool) {
|
||||
if c.debug.Val() == debug {
|
||||
return
|
||||
}
|
||||
bs.debug.Set(debug)
|
||||
c.debug.Set(debug)
|
||||
}
|
||||
|
||||
// getDebug returns the debug value.
|
||||
func (bs *dbBase) getDebug() bool {
|
||||
return bs.debug.Val()
|
||||
// GetDebug returns the debug value.
|
||||
func (c *Core) GetDebug() bool {
|
||||
return c.debug.Val()
|
||||
}
|
||||
|
||||
// GetCache returns the internal cache object.
|
||||
func (c *Core) GetCache() *gcache.Cache {
|
||||
return c.cache
|
||||
}
|
||||
|
||||
// GetPrefix returns the table prefix string configured.
|
||||
func (c *Core) GetPrefix() string {
|
||||
return c.prefix
|
||||
}
|
||||
|
||||
// SetSchema changes the schema for this database connection object.
|
||||
// Importantly note that when schema configuration changed for the database,
|
||||
// it affects all operations on the database object in the future.
|
||||
func (c *Core) SetSchema(schema string) {
|
||||
c.schema.Set(schema)
|
||||
}
|
||||
|
||||
// GetSchema returns the schema configured.
|
||||
func (c *Core) GetSchema() string {
|
||||
return c.schema.Val()
|
||||
}
|
||||
50
database/gdb/gdb_core_utility.go
Normal file
50
database/gdb/gdb_core_utility.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
//
|
||||
|
||||
package gdb
|
||||
|
||||
import "database/sql"
|
||||
|
||||
// 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 <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 <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()
|
||||
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()
|
||||
return doQuoteString(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// GetChars returns the security char for current database.
|
||||
// It does nothing in default.
|
||||
func (c *Core) GetChars() (charLeft string, charRight string) {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// HandleSqlBeforeExec handles the sql before posts it to database.
|
||||
// It does nothing in default.
|
||||
func (c *Core) HandleSqlBeforeExec(sql string) string {
|
||||
return sql
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
//
|
||||
// Note:
|
||||
// 1. It needs manually import: _ "github.com/lib/pq"
|
||||
// 1. It needs manually import: _ "github.com/denisenkom/go-mssqldb"
|
||||
// 2. It does not support Save/Replace features.
|
||||
// 3. It does not support LastInsertId.
|
||||
|
||||
@ -22,12 +22,20 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
type dbMssql struct {
|
||||
*dbBase
|
||||
// DriverMssql is the driver for SQL server database.
|
||||
type DriverMssql struct {
|
||||
*Core
|
||||
}
|
||||
|
||||
// New creates and returns a database object for SQL server.
|
||||
func (d *DriverMssql) New(core *Core, node *ConfigNode) (DB, error) {
|
||||
return &DriverMssql{
|
||||
Core: core,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Open creates and returns a underlying sql.DB object for mssql.
|
||||
func (db *dbMssql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
func (d *DriverMssql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
source := ""
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
@ -45,13 +53,13 @@ func (db *dbMssql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// getChars returns the security char for this type of database.
|
||||
func (db *dbMssql) getChars() (charLeft string, charRight string) {
|
||||
// GetChars returns the security char for this type of database.
|
||||
func (d *DriverMssql) GetChars() (charLeft string, charRight string) {
|
||||
return "\"", "\""
|
||||
}
|
||||
|
||||
// handleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
func (db *dbMssql) handleSqlBeforeExec(query string) string {
|
||||
// HandleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
func (d *DriverMssql) HandleSqlBeforeExec(query string) string {
|
||||
var index int
|
||||
// Convert place holder char '?' to string "@px".
|
||||
str, _ := gregex.ReplaceStringFunc("\\?", query, func(s string) string {
|
||||
@ -59,10 +67,10 @@ func (db *dbMssql) handleSqlBeforeExec(query string) string {
|
||||
return fmt.Sprintf("@p%d", index)
|
||||
})
|
||||
str, _ = gregex.ReplaceString("\"", "", str)
|
||||
return db.parseSql(str)
|
||||
return d.parseSql(str)
|
||||
}
|
||||
|
||||
func (db *dbMssql) parseSql(sql string) string {
|
||||
func (d *DriverMssql) parseSql(sql string) string {
|
||||
// SELECT * FROM USER WHERE ID=1 LIMIT 1
|
||||
if m, _ := gregex.MatchString(`^SELECT(.+)LIMIT 1$`, sql); len(m) > 1 {
|
||||
return fmt.Sprintf(`SELECT TOP 1 %s`, m[1])
|
||||
@ -163,14 +171,14 @@ func (db *dbMssql) parseSql(sql string) string {
|
||||
}
|
||||
|
||||
// Tables retrieves and returns the tables of current schema.
|
||||
func (db *dbMssql) Tables(schema ...string) (tables []string, err error) {
|
||||
func (d *DriverMssql) Tables(schema ...string) (tables []string, err error) {
|
||||
var result Result
|
||||
link, err := db.getSlave(schema...)
|
||||
link, err := d.DB.GetSlave(schema...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err = 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
|
||||
}
|
||||
@ -183,24 +191,24 @@ func (db *dbMssql) Tables(schema ...string) (tables []string, err error) {
|
||||
}
|
||||
|
||||
// TableFields retrieves and returns the fields information of specified table of current schema.
|
||||
func (db *dbMssql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
func (d *DriverMssql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
table = gstr.Trim(table)
|
||||
if gstr.Contains(table, " ") {
|
||||
panic("function TableFields supports only single table operations")
|
||||
}
|
||||
checkSchema := db.schema.Val()
|
||||
checkSchema := d.DB.GetSchema()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := db.cache.GetOrSetFunc(
|
||||
v := d.DB.GetCache().GetOrSetFunc(
|
||||
fmt.Sprintf(`mssql_table_fields_%s_%s`, table, checkSchema), func() interface{} {
|
||||
var result Result
|
||||
var link *sql.DB
|
||||
link, err = db.getSlave(checkSchema)
|
||||
link, err = d.DB.GetSlave(checkSchema)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
result, err = db.doGetAll(link, fmt.Sprintf(`
|
||||
result, err = d.DB.DoGetAll(link, fmt.Sprintf(`
|
||||
SELECT c.name as FIELD, CASE t.name
|
||||
WHEN 'numeric' THEN t.name + '(' + convert(varchar(20),c.xprec) + ',' + convert(varchar(20),c.xscale) + ')'
|
||||
WHEN 'char' THEN t.name + '(' + convert(varchar(20),c.length)+ ')'
|
||||
@ -12,15 +12,23 @@ import (
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
|
||||
_ "github.com/gf-third/mysql"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
type dbMysql struct {
|
||||
*dbBase
|
||||
// DriverMysql is the driver for mysql database.
|
||||
type DriverMysql struct {
|
||||
*Core
|
||||
}
|
||||
|
||||
// New creates and returns a database object for mysql.
|
||||
func (d *DriverMysql) New(core *Core, node *ConfigNode) (DB, error) {
|
||||
return &DriverMysql{
|
||||
Core: core,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Open creates and returns a underlying sql.DB object for mysql.
|
||||
func (db *dbMysql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
func (d *DriverMysql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
@ -31,31 +39,31 @@ func (db *dbMysql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
)
|
||||
}
|
||||
intlog.Printf("Open: %s", source)
|
||||
if db, err := sql.Open("gf-mysql", source); err == nil {
|
||||
if db, err := sql.Open("mysql", source); err == nil {
|
||||
return db, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// getChars returns the security char for this type of database.
|
||||
func (db *dbMysql) getChars() (charLeft string, charRight string) {
|
||||
// GetChars returns the security char for this type of database.
|
||||
func (d *DriverMysql) GetChars() (charLeft string, charRight string) {
|
||||
return "`", "`"
|
||||
}
|
||||
|
||||
// handleSqlBeforeExec handles the sql before posts it to database.
|
||||
func (db *dbMysql) handleSqlBeforeExec(sql string) string {
|
||||
// HandleSqlBeforeExec handles the sql before posts it to database.
|
||||
func (d *DriverMysql) HandleSqlBeforeExec(sql string) string {
|
||||
return sql
|
||||
}
|
||||
|
||||
// Tables retrieves and returns the tables of current schema.
|
||||
func (bs *dbBase) Tables(schema ...string) (tables []string, err error) {
|
||||
func (d *DriverMysql) Tables(schema ...string) (tables []string, err error) {
|
||||
var result Result
|
||||
link, err := bs.db.getSlave(schema...)
|
||||
link, err := d.DB.GetSlave(schema...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = bs.db.doGetAll(link, `SHOW TABLES`)
|
||||
result, err = d.DB.DoGetAll(link, `SHOW TABLES`)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -73,27 +81,27 @@ func (bs *dbBase) Tables(schema ...string) (tables []string, err error) {
|
||||
// As a map is unsorted, the TableField struct has a "Index" field marks its sequence in the fields.
|
||||
//
|
||||
// It's using cache feature to enhance the performance, which is never expired util the process restarts.
|
||||
func (bs *dbBase) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
func (d *DriverMysql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
table = gstr.Trim(table)
|
||||
if gstr.Contains(table, " ") {
|
||||
panic("function TableFields supports only single table operations")
|
||||
}
|
||||
checkSchema := bs.schema.Val()
|
||||
checkSchema := d.schema.Val()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := bs.cache.GetOrSetFunc(
|
||||
v := d.cache.GetOrSetFunc(
|
||||
fmt.Sprintf(`mysql_table_fields_%s_%s`, table, checkSchema),
|
||||
func() interface{} {
|
||||
var result Result
|
||||
var link *sql.DB
|
||||
link, err = bs.db.getSlave(checkSchema)
|
||||
link, err = d.DB.GetSlave(checkSchema)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
result, err = bs.doGetAll(
|
||||
result, err = d.DB.DoGetAll(
|
||||
link,
|
||||
fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, bs.db.quoteWord(table)),
|
||||
fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.DB.QuoteWord(table)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -24,8 +24,9 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
type dbOracle struct {
|
||||
*dbBase
|
||||
// DriverOracle is the driver for oracle database.
|
||||
type DriverOracle struct {
|
||||
*Core
|
||||
}
|
||||
|
||||
const (
|
||||
@ -33,8 +34,15 @@ const (
|
||||
tableAlias2 = "GFORM2"
|
||||
)
|
||||
|
||||
// New creates and returns a database object for oracle.
|
||||
func (d *DriverOracle) New(core *Core, node *ConfigNode) (DB, error) {
|
||||
return &DriverOracle{
|
||||
Core: core,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Open creates and returns a underlying sql.DB object for oracle.
|
||||
func (db *dbOracle) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
func (d *DriverOracle) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
@ -49,13 +57,13 @@ func (db *dbOracle) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// getChars returns the security char for this type of database.
|
||||
func (db *dbOracle) getChars() (charLeft string, charRight string) {
|
||||
// GetChars returns the security char for this type of database.
|
||||
func (d *DriverOracle) GetChars() (charLeft string, charRight string) {
|
||||
return "\"", "\""
|
||||
}
|
||||
|
||||
// handleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
func (db *dbOracle) handleSqlBeforeExec(query string) string {
|
||||
// HandleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
func (d *DriverOracle) HandleSqlBeforeExec(query string) string {
|
||||
var index int
|
||||
// Convert place holder char '?' to string ":x".
|
||||
str, _ := gregex.ReplaceStringFunc("\\?", query, func(s string) string {
|
||||
@ -63,10 +71,10 @@ func (db *dbOracle) handleSqlBeforeExec(query string) string {
|
||||
return fmt.Sprintf(":%d", index)
|
||||
})
|
||||
str, _ = gregex.ReplaceString("\"", "", str)
|
||||
return db.parseSql(str)
|
||||
return d.parseSql(str)
|
||||
}
|
||||
|
||||
func (db *dbOracle) parseSql(sql string) string {
|
||||
func (d *DriverOracle) parseSql(sql string) string {
|
||||
patten := `^\s*(?i)(SELECT)|(LIMIT\s*(\d+)\s*,\s*(\d+))`
|
||||
if gregex.IsMatchString(patten, sql) == false {
|
||||
return sql
|
||||
@ -124,9 +132,9 @@ func (db *dbOracle) parseSql(sql string) string {
|
||||
|
||||
// Tables retrieves and returns the tables of current schema.
|
||||
// Note that it ignores the parameter <schema> in oracle database, as it is not necessary.
|
||||
func (db *dbOracle) Tables(schema ...string) (tables []string, err error) {
|
||||
func (d *DriverOracle) Tables(schema ...string) (tables []string, err error) {
|
||||
var result Result
|
||||
result, err = 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
|
||||
}
|
||||
@ -139,20 +147,20 @@ func (db *dbOracle) Tables(schema ...string) (tables []string, err error) {
|
||||
}
|
||||
|
||||
// TableFields retrieves and returns the fields information of specified table of current schema.
|
||||
func (db *dbOracle) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
func (d *DriverOracle) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
table = gstr.Trim(table)
|
||||
if gstr.Contains(table, " ") {
|
||||
panic("function TableFields supports only single table operations")
|
||||
}
|
||||
checkSchema := db.schema.Val()
|
||||
checkSchema := d.DB.GetSchema()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := db.cache.GetOrSetFunc(
|
||||
v := d.DB.GetCache().GetOrSetFunc(
|
||||
fmt.Sprintf(`oracle_table_fields_%s_%s`, table, checkSchema),
|
||||
func() interface{} {
|
||||
result := (Result)(nil)
|
||||
result, err = db.GetAll(fmt.Sprintf(`
|
||||
result, err = d.DB.GetAll(fmt.Sprintf(`
|
||||
SELECT COLUMN_NAME AS FIELD, CASE DATA_TYPE
|
||||
WHEN 'NUMBER' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
|
||||
WHEN 'FLOAT' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
|
||||
@ -177,11 +185,11 @@ func (db *dbOracle) TableFields(table string, schema ...string) (fields map[stri
|
||||
return
|
||||
}
|
||||
|
||||
func (db *dbOracle) getTableUniqueIndex(table string) (fields map[string]map[string]string, err error) {
|
||||
func (d *DriverOracle) getTableUniqueIndex(table string) (fields map[string]map[string]string, err error) {
|
||||
table = strings.ToUpper(table)
|
||||
v := db.cache.GetOrSetFunc("table_unique_index_"+table, func() interface{} {
|
||||
v := d.DB.GetCache().GetOrSetFunc("table_unique_index_"+table, func() interface{} {
|
||||
res := (Result)(nil)
|
||||
res, err = 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')
|
||||
@ -203,7 +211,7 @@ func (db *dbOracle) getTableUniqueIndex(table string) (fields map[string]map[str
|
||||
return
|
||||
}
|
||||
|
||||
func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
func (d *DriverOracle) DoInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var fields []string
|
||||
var values []string
|
||||
var params []interface{}
|
||||
@ -218,7 +226,7 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
case reflect.Slice:
|
||||
fallthrough
|
||||
case reflect.Array:
|
||||
return db.db.doBatchInsert(link, table, data, option, batch...)
|
||||
return d.DB.DoBatchInsert(link, table, data, option, batch...)
|
||||
case reflect.Map:
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
@ -231,7 +239,7 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
indexMap := make(map[string]string)
|
||||
indexExists := false
|
||||
if option != gINSERT_OPTION_DEFAULT {
|
||||
index, err := db.getTableUniqueIndex(table)
|
||||
index, err := d.getTableUniqueIndex(table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -253,7 +261,7 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
onStr := make([]string, 0)
|
||||
updateStr := make([]string, 0)
|
||||
|
||||
charL, charR := db.db.getChars()
|
||||
charL, charR := d.DB.GetChars()
|
||||
for k, v := range dataMap {
|
||||
k = strings.ToUpper(k)
|
||||
|
||||
@ -279,7 +287,7 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
}
|
||||
|
||||
if link == nil {
|
||||
if link, err = db.db.Master(); err != nil {
|
||||
if link, err = d.DB.Master(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -294,9 +302,9 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
table, tableAlias1, strings.Join(subSqlStr, ","), tableAlias2,
|
||||
strings.Join(onStr, "AND"), strings.Join(updateStr, ","), strings.Join(fields, ","), strings.Join(values, ","),
|
||||
)
|
||||
return db.db.doExec(link, tmp, params...)
|
||||
return d.DB.DoExec(link, tmp, params...)
|
||||
case gINSERT_OPTION_IGNORE:
|
||||
return db.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(indexs, ","), table, strings.Join(fields, ","), strings.Join(values, ","),
|
||||
@ -305,7 +313,7 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
}
|
||||
}
|
||||
|
||||
return db.db.doExec(
|
||||
return d.DB.DoExec(
|
||||
link,
|
||||
fmt.Sprintf(
|
||||
"INSERT INTO %s(%s) VALUES(%s)",
|
||||
@ -314,7 +322,7 @@ func (db *dbOracle) doInsert(link dbLink, table string, data interface{}, option
|
||||
params...)
|
||||
}
|
||||
|
||||
func (db *dbOracle) doBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
func (d *DriverOracle) DoBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var keys []string
|
||||
var values []string
|
||||
var params []interface{}
|
||||
@ -357,7 +365,7 @@ func (db *dbOracle) doBatchInsert(link dbLink, table string, list interface{}, o
|
||||
return result, errors.New("empty data list")
|
||||
}
|
||||
if link == nil {
|
||||
if link, err = db.db.Master(); err != nil {
|
||||
if link, err = d.DB.Master(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -368,14 +376,14 @@ func (db *dbOracle) doBatchInsert(link dbLink, table string, list interface{}, o
|
||||
holders = append(holders, "?")
|
||||
}
|
||||
batchResult := new(batchSqlResult)
|
||||
charL, charR := db.db.getChars()
|
||||
charL, charR := d.DB.GetChars()
|
||||
keyStr := charL + strings.Join(keys, charL+","+charR) + charR
|
||||
valueHolderStr := strings.Join(holders, ",")
|
||||
|
||||
// 当操作类型非insert时调用单笔的insert功能
|
||||
if option != gINSERT_OPTION_DEFAULT {
|
||||
for _, v := range listMap {
|
||||
r, err := db.doInsert(link, table, v, option, 1)
|
||||
r, err := d.DB.DoInsert(link, table, v, option, 1)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
@ -402,10 +410,9 @@ func (db *dbOracle) doBatchInsert(link dbLink, table string, list interface{}, o
|
||||
params = append(params, listMap[i][k])
|
||||
}
|
||||
values = append(values, valueHolderStr)
|
||||
|
||||
intoStr = append(intoStr, fmt.Sprintf(" INTO %s(%s) VALUES(%s) ", table, keyStr, valueHolderStr))
|
||||
if len(intoStr) == batchNum {
|
||||
r, err := db.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
|
||||
}
|
||||
@ -421,7 +428,7 @@ func (db *dbOracle) doBatchInsert(link dbLink, table string, list interface{}, o
|
||||
}
|
||||
// 处理最后不构成指定批量的数据
|
||||
if len(intoStr) > 0 {
|
||||
r, err := db.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
|
||||
}
|
||||
@ -21,12 +21,20 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
type dbPgsql struct {
|
||||
*dbBase
|
||||
// DriverPgsql is the driver for postgresql database.
|
||||
type DriverPgsql struct {
|
||||
*Core
|
||||
}
|
||||
|
||||
// New creates and returns a database object for postgresql.
|
||||
func (d *DriverPgsql) New(core *Core, node *ConfigNode) (DB, error) {
|
||||
return &DriverPgsql{
|
||||
Core: core,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Open creates and returns a underlying sql.DB object for pgsql.
|
||||
func (db *dbPgsql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
func (d *DriverPgsql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
@ -44,13 +52,13 @@ func (db *dbPgsql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// getChars returns the security char for this type of database.
|
||||
func (db *dbPgsql) getChars() (charLeft string, charRight string) {
|
||||
// GetChars returns the security char for this type of database.
|
||||
func (d *DriverPgsql) GetChars() (charLeft string, charRight string) {
|
||||
return "\"", "\""
|
||||
}
|
||||
|
||||
// handleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
func (db *dbPgsql) handleSqlBeforeExec(sql string) string {
|
||||
// HandleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
func (d *DriverPgsql) HandleSqlBeforeExec(sql string) string {
|
||||
var index int
|
||||
// Convert place holder char '?' to string "$x".
|
||||
sql, _ = gregex.ReplaceStringFunc("\\?", sql, func(s string) string {
|
||||
@ -62,9 +70,9 @@ func (db *dbPgsql) handleSqlBeforeExec(sql string) string {
|
||||
}
|
||||
|
||||
// Tables retrieves and returns the tables of current schema.
|
||||
func (db *dbPgsql) Tables(schema ...string) (tables []string, err error) {
|
||||
func (d *DriverPgsql) Tables(schema ...string) (tables []string, err error) {
|
||||
var result Result
|
||||
link, err := db.getSlave(schema...)
|
||||
link, err := d.DB.GetSlave(schema...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -73,7 +81,7 @@ func (db *dbPgsql) 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 = db.doGetAll(link, query)
|
||||
result, err = d.DB.DoGetAll(link, query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -86,25 +94,25 @@ func (db *dbPgsql) Tables(schema ...string) (tables []string, err error) {
|
||||
}
|
||||
|
||||
// TableFields retrieves and returns the fields information of specified table of current schema.
|
||||
func (db *dbPgsql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
func (d *DriverPgsql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
table = gstr.Trim(table)
|
||||
if gstr.Contains(table, " ") {
|
||||
panic("function TableFields supports only single table operations")
|
||||
}
|
||||
table, _ = gregex.ReplaceString("\"", "", table)
|
||||
checkSchema := db.schema.Val()
|
||||
checkSchema := d.DB.GetSchema()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := db.cache.GetOrSetFunc(
|
||||
v := d.DB.GetCache().GetOrSetFunc(
|
||||
fmt.Sprintf(`pgsql_table_fields_%s_%s`, table, checkSchema), func() interface{} {
|
||||
var result Result
|
||||
var link *sql.DB
|
||||
link, err = db.getSlave(checkSchema)
|
||||
link, err = d.DB.GetSlave(checkSchema)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
result, err = db.doGetAll(link, fmt.Sprintf(`
|
||||
result, err = d.DB.DoGetAll(link, fmt.Sprintf(`
|
||||
SELECT a.attname AS field, t.typname AS type FROM pg_class c, pg_attribute a
|
||||
LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,pg_type t
|
||||
WHERE c.relname = '%s' and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid
|
||||
@ -16,12 +16,20 @@ import (
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
)
|
||||
|
||||
type dbSqlite struct {
|
||||
*dbBase
|
||||
// DriverSqlite is the driver for sqlite database.
|
||||
type DriverSqlite struct {
|
||||
*Core
|
||||
}
|
||||
|
||||
// New creates and returns a database object for sqlite.
|
||||
func (d *DriverSqlite) New(core *Core, node *ConfigNode) (DB, error) {
|
||||
return &DriverSqlite{
|
||||
Core: core,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Open creates and returns a underlying sql.DB object for sqlite.
|
||||
func (db *dbSqlite) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
func (d *DriverSqlite) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
@ -36,20 +44,20 @@ func (db *dbSqlite) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// getChars returns the security char for this type of database.
|
||||
func (db *dbSqlite) getChars() (charLeft string, charRight string) {
|
||||
// GetChars returns the security char for this type of database.
|
||||
func (d *DriverSqlite) GetChars() (charLeft string, charRight string) {
|
||||
return "`", "`"
|
||||
}
|
||||
|
||||
// Tables retrieves and returns the tables of current schema.
|
||||
// TODO
|
||||
func (db *dbSqlite) Tables(schema ...string) (tables []string, err error) {
|
||||
func (d *DriverSqlite) Tables(schema ...string) (tables []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// TableFields retrieves and returns the fields information of specified table of current schema.
|
||||
// TODO
|
||||
func (db *dbSqlite) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
func (d *DriverSqlite) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
table = gstr.Trim(table)
|
||||
if gstr.Contains(table, " ") {
|
||||
panic("function TableFields supports only single table operations")
|
||||
@ -57,9 +65,9 @@ func (db *dbSqlite) TableFields(table string, schema ...string) (fields map[stri
|
||||
return
|
||||
}
|
||||
|
||||
// handleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
// HandleSqlBeforeExec deals with the sql string before commits it to underlying sql driver.
|
||||
// @todo 需要增加对Save方法的支持,可使用正则来实现替换,
|
||||
// @todo 将ON DUPLICATE KEY UPDATE触发器修改为两条SQL语句(INSERT OR IGNORE & UPDATE)
|
||||
func (db *dbSqlite) handleSqlBeforeExec(sql string) string {
|
||||
func (d *DriverSqlite) HandleSqlBeforeExec(sql string) string {
|
||||
return sql
|
||||
}
|
||||
@ -269,7 +269,7 @@ func formatWhereInterfaces(db DB, where []interface{}, buffer *bytes.Buffer, new
|
||||
|
||||
// formatWhereKeyValue handles each key-value pair of the parameter map.
|
||||
func formatWhereKeyValue(db DB, buffer *bytes.Buffer, newArgs []interface{}, key string, value interface{}) []interface{} {
|
||||
key = db.quoteWord(key)
|
||||
key = db.QuoteWord(key)
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteString(" AND ")
|
||||
}
|
||||
|
||||
@ -68,10 +68,10 @@ const (
|
||||
// Table creates and returns a new ORM model from given schema.
|
||||
// The parameter <tables> can be more than one table names, like :
|
||||
// "user", "user u", "user, user_detail", "user u, user_detail ud"
|
||||
func (bs *dbBase) Table(table string) *Model {
|
||||
table = bs.db.handleTableName(table)
|
||||
func (c *Core) Table(table string) *Model {
|
||||
table = c.DB.handleTableName(table)
|
||||
return &Model{
|
||||
db: bs.db,
|
||||
db: c.DB,
|
||||
tablesInit: table,
|
||||
tables: table,
|
||||
fields: "*",
|
||||
@ -82,21 +82,21 @@ func (bs *dbBase) Table(table string) *Model {
|
||||
}
|
||||
}
|
||||
|
||||
// Model is alias of dbBase.Table.
|
||||
// See dbBase.Table.
|
||||
func (bs *dbBase) Model(table string) *Model {
|
||||
return bs.db.Table(table)
|
||||
// Model is alias of Core.Table.
|
||||
// See Core.Table.
|
||||
func (c *Core) Model(table string) *Model {
|
||||
return c.DB.Table(table)
|
||||
}
|
||||
|
||||
// From is alias of dbBase.Table.
|
||||
// See dbBase.Table.
|
||||
// From is alias of Core.Table.
|
||||
// See Core.Table.
|
||||
// Deprecated.
|
||||
func (bs *dbBase) From(table string) *Model {
|
||||
return bs.db.Table(table)
|
||||
func (c *Core) From(table string) *Model {
|
||||
return c.DB.Table(table)
|
||||
}
|
||||
|
||||
// Table acts like dbBase.Table except it operates on transaction.
|
||||
// See dbBase.Table.
|
||||
// Table acts like Core.Table except it operates on transaction.
|
||||
// See Core.Table.
|
||||
func (tx *TX) Table(table string) *Model {
|
||||
table = tx.db.handleTableName(table)
|
||||
return &Model{
|
||||
@ -403,7 +403,7 @@ func (m *Model) Or(where interface{}, args ...interface{}) *Model {
|
||||
// Group sets the "GROUP BY" statement for the model.
|
||||
func (m *Model) Group(groupBy string) *Model {
|
||||
model := m.getModel()
|
||||
model.groupBy = m.db.quoteString(groupBy)
|
||||
model.groupBy = m.db.QuoteString(groupBy)
|
||||
return model
|
||||
}
|
||||
|
||||
@ -417,7 +417,7 @@ func (m *Model) GroupBy(groupBy string) *Model {
|
||||
// Order sets the "ORDER BY" statement for the model.
|
||||
func (m *Model) Order(orderBy string) *Model {
|
||||
model := m.getModel()
|
||||
model.orderBy = m.db.quoteString(orderBy)
|
||||
model.orderBy = m.db.QuoteString(orderBy)
|
||||
return model
|
||||
}
|
||||
|
||||
@ -586,7 +586,7 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql.
|
||||
if m.batch > 0 {
|
||||
batch = m.batch
|
||||
}
|
||||
return m.db.doBatchInsert(
|
||||
return m.db.DoBatchInsert(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(list),
|
||||
@ -595,7 +595,7 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql.
|
||||
)
|
||||
} else if data, ok := m.data.(Map); ok {
|
||||
// Single insert.
|
||||
return m.db.doInsert(
|
||||
return m.db.DoInsert(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(data),
|
||||
@ -626,7 +626,7 @@ func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
|
||||
if m.batch > 0 {
|
||||
batch = m.batch
|
||||
}
|
||||
return m.db.doBatchInsert(
|
||||
return m.db.DoBatchInsert(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(list),
|
||||
@ -635,7 +635,7 @@ func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
|
||||
)
|
||||
} else if data, ok := m.data.(Map); ok {
|
||||
// Single insert.
|
||||
return m.db.doInsert(
|
||||
return m.db.DoInsert(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(data),
|
||||
@ -669,7 +669,7 @@ func (m *Model) Save(data ...interface{}) (result sql.Result, err error) {
|
||||
if m.batch > 0 {
|
||||
batch = m.batch
|
||||
}
|
||||
return m.db.doBatchInsert(
|
||||
return m.db.DoBatchInsert(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(list),
|
||||
@ -678,7 +678,7 @@ func (m *Model) Save(data ...interface{}) (result sql.Result, err error) {
|
||||
)
|
||||
} else if data, ok := m.data.(Map); ok {
|
||||
// Single save.
|
||||
return m.db.doInsert(
|
||||
return m.db.DoInsert(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(data),
|
||||
@ -712,7 +712,7 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro
|
||||
return nil, errors.New("updating table with empty data")
|
||||
}
|
||||
condition, conditionArgs := m.formatCondition(false)
|
||||
return m.db.doUpdate(
|
||||
return m.db.DoUpdate(
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(m.data),
|
||||
@ -734,7 +734,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) {
|
||||
}
|
||||
}()
|
||||
condition, conditionArgs := m.formatCondition(false)
|
||||
return m.db.doDelete(m.getLink(true), m.tables, condition, conditionArgs...)
|
||||
return m.db.DoDelete(m.getLink(true), m.tables, condition, conditionArgs...)
|
||||
}
|
||||
|
||||
// Select is alias of Model.All.
|
||||
@ -1059,10 +1059,16 @@ func (m *Model) getLink(master bool) dbLink {
|
||||
}
|
||||
switch linkType {
|
||||
case gLINK_TYPE_MASTER:
|
||||
link, _ := m.db.getMaster(m.schema)
|
||||
link, err := m.db.GetMaster(m.schema)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return link
|
||||
case gLINK_TYPE_SLAVE:
|
||||
link, _ := m.db.getSlave(m.schema)
|
||||
link, err := m.db.GetSlave(m.schema)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return link
|
||||
}
|
||||
return nil
|
||||
@ -1077,17 +1083,17 @@ func (m *Model) getAll(query string, args ...interface{}) (result Result, err er
|
||||
if len(cacheKey) == 0 {
|
||||
cacheKey = query + "/" + gconv.String(args)
|
||||
}
|
||||
if v := m.db.getCache().Get(cacheKey); v != nil {
|
||||
if v := m.db.GetCache().Get(cacheKey); v != nil {
|
||||
return v.(Result), nil
|
||||
}
|
||||
}
|
||||
result, err = m.db.doGetAll(m.getLink(false), query, args...)
|
||||
result, err = m.db.DoGetAll(m.getLink(false), query, args...)
|
||||
// Cache the result.
|
||||
if len(cacheKey) > 0 && err == nil {
|
||||
if m.cacheDuration < 0 {
|
||||
m.db.getCache().Remove(cacheKey)
|
||||
m.db.GetCache().Remove(cacheKey)
|
||||
} else {
|
||||
m.db.getCache().Set(cacheKey, result, m.cacheDuration)
|
||||
m.db.GetCache().Set(cacheKey, result, m.cacheDuration)
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
@ -1113,7 +1119,7 @@ func (m *Model) getPrimaryKey() string {
|
||||
// checkAndRemoveCache checks and remove the cache if necessary.
|
||||
func (m *Model) checkAndRemoveCache() {
|
||||
if m.cacheEnabled && m.cacheDuration < 0 && len(m.cacheName) > 0 {
|
||||
m.db.getCache().Remove(m.cacheName)
|
||||
m.db.GetCache().Remove(m.cacheName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,9 +14,9 @@ type Schema struct {
|
||||
}
|
||||
|
||||
// Schema creates and returns a schema.
|
||||
func (bs *dbBase) Schema(schema string) *Schema {
|
||||
func (c *Core) Schema(schema string) *Schema {
|
||||
return &Schema{
|
||||
db: bs.db,
|
||||
db: c.DB,
|
||||
schema: schema,
|
||||
}
|
||||
}
|
||||
@ -44,8 +44,8 @@ func (s *Schema) Table(table string) *Model {
|
||||
return m
|
||||
}
|
||||
|
||||
// Model is alias of dbBase.Table.
|
||||
// See dbBase.Table.
|
||||
// Model is alias of Core.Table.
|
||||
// See Core.Table.
|
||||
func (s *Schema) Model(table string) *Model {
|
||||
return s.Table(table)
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ import (
|
||||
|
||||
// convertValue automatically checks and converts field value from database type
|
||||
// to golang variable type.
|
||||
func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{} {
|
||||
func (c *Core) convertValue(fieldValue []byte, fieldType string) interface{} {
|
||||
t, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
|
||||
t = strings.ToLower(t)
|
||||
switch t {
|
||||
@ -106,10 +106,10 @@ func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
}
|
||||
|
||||
// filterFields removes all key-value pairs which are not the field of given table.
|
||||
func (bs *dbBase) filterFields(schema, table string, data map[string]interface{}) map[string]interface{} {
|
||||
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 := bs.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
|
||||
|
||||
@ -32,15 +32,15 @@ func (tx *TX) Rollback() error {
|
||||
}
|
||||
|
||||
// Query does query operation on transaction.
|
||||
// See dbBase.Query.
|
||||
// See Core.Query.
|
||||
func (tx *TX) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
return tx.db.doQuery(tx.tx, query, args...)
|
||||
return tx.db.DoQuery(tx.tx, query, args...)
|
||||
}
|
||||
|
||||
// Exec does none query operation on transaction.
|
||||
// See dbBase.Exec.
|
||||
// See Core.Exec.
|
||||
func (tx *TX) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
return tx.db.doExec(tx.tx, query, args...)
|
||||
return tx.db.DoExec(tx.tx, query, args...)
|
||||
}
|
||||
|
||||
// Prepare creates a prepared statement for later queries or executions.
|
||||
@ -49,7 +49,7 @@ func (tx *TX) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
// The caller must call the statement's Close method
|
||||
// when the statement is no longer needed.
|
||||
func (tx *TX) Prepare(query string) (*sql.Stmt, error) {
|
||||
return tx.db.doPrepare(tx.tx, query)
|
||||
return tx.db.DoPrepare(tx.tx, query)
|
||||
}
|
||||
|
||||
// GetAll queries and returns data records from database.
|
||||
@ -154,7 +154,7 @@ func (tx *TX) GetCount(query string, args ...interface{}) (int, error) {
|
||||
//
|
||||
// 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) {
|
||||
return tx.db.doInsert(tx.tx, table, data, gINSERT_OPTION_DEFAULT, batch...)
|
||||
return tx.db.DoInsert(tx.tx, table, data, gINSERT_OPTION_DEFAULT, batch...)
|
||||
}
|
||||
|
||||
// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
|
||||
@ -167,7 +167,7 @@ func (tx *TX) Insert(table string, data interface{}, batch ...int) (sql.Result,
|
||||
//
|
||||
// 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) {
|
||||
return tx.db.doInsert(tx.tx, table, data, gINSERT_OPTION_IGNORE, batch...)
|
||||
return tx.db.DoInsert(tx.tx, table, data, gINSERT_OPTION_IGNORE, batch...)
|
||||
}
|
||||
|
||||
// Replace does "REPLACE INTO ..." statement for the table.
|
||||
@ -183,7 +183,7 @@ func (tx *TX) InsertIgnore(table string, data interface{}, batch ...int) (sql.Re
|
||||
// If given data is type of slice, it then does batch replacing, and the optional parameter
|
||||
// <batch> specifies the batch operation count.
|
||||
func (tx *TX) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return tx.db.doInsert(tx.tx, table, data, gINSERT_OPTION_REPLACE, batch...)
|
||||
return tx.db.DoInsert(tx.tx, table, data, gINSERT_OPTION_REPLACE, batch...)
|
||||
}
|
||||
|
||||
// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table.
|
||||
@ -198,31 +198,31 @@ func (tx *TX) Replace(table string, data interface{}, batch ...int) (sql.Result,
|
||||
// If given data is type of slice, it then does batch saving, and the optional parameter
|
||||
// <batch> specifies the batch operation count.
|
||||
func (tx *TX) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return tx.db.doInsert(tx.tx, table, data, gINSERT_OPTION_SAVE, batch...)
|
||||
return tx.db.DoInsert(tx.tx, table, data, gINSERT_OPTION_SAVE, batch...)
|
||||
}
|
||||
|
||||
// BatchInsert batch inserts data.
|
||||
// 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) {
|
||||
return tx.db.doBatchInsert(tx.tx, table, list, gINSERT_OPTION_DEFAULT, batch...)
|
||||
return tx.db.DoBatchInsert(tx.tx, table, list, gINSERT_OPTION_DEFAULT, batch...)
|
||||
}
|
||||
|
||||
// BatchInsert batch inserts data with ignore option.
|
||||
// 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) {
|
||||
return tx.db.doBatchInsert(tx.tx, table, list, gINSERT_OPTION_IGNORE, batch...)
|
||||
return tx.db.DoBatchInsert(tx.tx, table, list, gINSERT_OPTION_IGNORE, batch...)
|
||||
}
|
||||
|
||||
// BatchReplace batch replaces data.
|
||||
// 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) {
|
||||
return tx.db.doBatchInsert(tx.tx, table, list, gINSERT_OPTION_REPLACE, batch...)
|
||||
return tx.db.DoBatchInsert(tx.tx, table, list, gINSERT_OPTION_REPLACE, batch...)
|
||||
}
|
||||
|
||||
// BatchSave batch replaces data.
|
||||
// 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) {
|
||||
return tx.db.doBatchInsert(tx.tx, table, list, gINSERT_OPTION_SAVE, batch...)
|
||||
return tx.db.DoBatchInsert(tx.tx, table, list, gINSERT_OPTION_SAVE, batch...)
|
||||
}
|
||||
|
||||
// Update does "UPDATE ... " statement for the table.
|
||||
@ -244,7 +244,7 @@ func (tx *TX) Update(table string, data interface{}, condition interface{}, args
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return tx.db.doUpdate(tx.tx, table, data, newWhere, newArgs...)
|
||||
return tx.db.DoUpdate(tx.tx, table, data, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM ... " statement for the table.
|
||||
@ -263,5 +263,5 @@ func (tx *TX) Delete(table string, condition interface{}, args ...interface{}) (
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return tx.db.doDelete(tx.tx, table, newWhere, newArgs...)
|
||||
return tx.db.DoDelete(tx.tx, table, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ type PoolStats struct {
|
||||
}
|
||||
|
||||
const (
|
||||
gDEFAULT_POOL_IDLE_TIMEOUT = 60 * time.Second
|
||||
gDEFAULT_POOL_IDLE_TIMEOUT = 30 * time.Second
|
||||
gDEFAULT_POOL_CONN_TIMEOUT = 10 * time.Second
|
||||
gDEFAULT_POOL_MAX_LIFE_TIME = 60 * time.Second
|
||||
gDEFAULT_POOL_MAX_LIFE_TIME = 30 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
@ -80,6 +80,7 @@ func New(config Config) *Redis {
|
||||
config: config,
|
||||
pool: pools.GetOrSetFuncLock(fmt.Sprintf("%v", config), func() interface{} {
|
||||
return &redis.Pool{
|
||||
Wait: true,
|
||||
IdleTimeout: config.IdleTimeout,
|
||||
MaxActive: config.MaxActive,
|
||||
MaxIdle: config.MaxIdle,
|
||||
|
||||
3
go.mod
3
go.mod
@ -7,8 +7,8 @@ require (
|
||||
github.com/clbanning/mxj v1.8.4
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gf-third/mysql v1.4.2
|
||||
github.com/gf-third/yaml v1.0.1
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
@ -17,5 +17,4 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.1
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user