2020-01-28 18:01:35 +03:00
|
|
|
package gorm
|
|
|
|
|
|
|
|
import (
|
2020-01-29 14:22:44 +03:00
|
|
|
"context"
|
2020-03-09 15:37:01 +03:00
|
|
|
"fmt"
|
2020-02-02 09:40:44 +03:00
|
|
|
"sync"
|
2020-01-28 18:01:35 +03:00
|
|
|
"time"
|
|
|
|
|
2020-01-29 14:22:44 +03:00
|
|
|
"github.com/jinzhu/gorm/clause"
|
2020-01-28 18:01:35 +03:00
|
|
|
"github.com/jinzhu/gorm/logger"
|
2020-01-31 09:17:02 +03:00
|
|
|
"github.com/jinzhu/gorm/schema"
|
2020-01-28 18:01:35 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// Config GORM config
|
|
|
|
type Config struct {
|
|
|
|
// GORM perform single create, update, delete operations in transactions by default to ensure database data integrity
|
2020-02-02 09:40:44 +03:00
|
|
|
// You can disable it by setting `SkipDefaultTransaction` to true
|
|
|
|
SkipDefaultTransaction bool
|
2020-01-31 09:17:02 +03:00
|
|
|
// NamingStrategy tables, columns naming strategy
|
|
|
|
NamingStrategy schema.Namer
|
2020-01-28 18:01:35 +03:00
|
|
|
// Logger
|
|
|
|
Logger logger.Interface
|
|
|
|
// NowFunc the function to be used when creating a new timestamp
|
|
|
|
NowFunc func() time.Time
|
|
|
|
|
2020-03-09 08:10:48 +03:00
|
|
|
// ClauseBuilders clause builder
|
|
|
|
ClauseBuilders map[string]clause.ClauseBuilder
|
|
|
|
// ConnPool db conn pool
|
|
|
|
ConnPool ConnPool
|
|
|
|
// Dialector database dialector
|
|
|
|
Dialector
|
|
|
|
|
2020-05-31 06:34:59 +03:00
|
|
|
callbacks *callbacks
|
|
|
|
cacheStore *sync.Map
|
2020-02-05 06:14:58 +03:00
|
|
|
}
|
|
|
|
|
2020-01-28 18:01:35 +03:00
|
|
|
// DB GORM DB definition
|
|
|
|
type DB struct {
|
|
|
|
*Config
|
2020-03-09 08:10:48 +03:00
|
|
|
Error error
|
|
|
|
RowsAffected int64
|
|
|
|
Statement *Statement
|
|
|
|
clone bool
|
2020-01-30 10:14:48 +03:00
|
|
|
}
|
|
|
|
|
2020-02-02 09:40:44 +03:00
|
|
|
// Session session config when create session with Session() method
|
2020-01-30 10:14:48 +03:00
|
|
|
type Session struct {
|
2020-01-29 14:22:44 +03:00
|
|
|
Context context.Context
|
2020-01-30 10:14:48 +03:00
|
|
|
Logger logger.Interface
|
|
|
|
NowFunc func() time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open initialize db session based on dialector
|
2020-03-09 15:37:01 +03:00
|
|
|
func Open(dialector Dialector, config *Config) (db *DB, err error) {
|
2020-02-02 03:35:01 +03:00
|
|
|
if config == nil {
|
|
|
|
config = &Config{}
|
|
|
|
}
|
|
|
|
|
2020-01-31 09:17:02 +03:00
|
|
|
if config.NamingStrategy == nil {
|
|
|
|
config.NamingStrategy = schema.NamingStrategy{}
|
|
|
|
}
|
|
|
|
|
2020-02-02 03:35:01 +03:00
|
|
|
if config.Logger == nil {
|
|
|
|
config.Logger = logger.Default
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.NowFunc == nil {
|
2020-05-31 03:58:08 +03:00
|
|
|
config.NowFunc = func() time.Time { return time.Now().Local() }
|
2020-02-02 03:35:01 +03:00
|
|
|
}
|
|
|
|
|
2020-03-09 08:10:48 +03:00
|
|
|
if dialector != nil {
|
|
|
|
config.Dialector = dialector
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.cacheStore == nil {
|
|
|
|
config.cacheStore = &sync.Map{}
|
|
|
|
}
|
|
|
|
|
2020-03-09 15:37:01 +03:00
|
|
|
db = &DB{
|
2020-03-09 08:10:48 +03:00
|
|
|
Config: config,
|
|
|
|
clone: true,
|
2020-02-02 03:35:01 +03:00
|
|
|
}
|
|
|
|
|
2020-03-09 15:37:01 +03:00
|
|
|
db.callbacks = initializeCallbacks(db)
|
2020-02-02 14:32:27 +03:00
|
|
|
|
2020-05-29 17:34:35 +03:00
|
|
|
if config.ClauseBuilders == nil {
|
|
|
|
config.ClauseBuilders = map[string]clause.ClauseBuilder{}
|
|
|
|
}
|
|
|
|
|
2020-02-02 03:35:01 +03:00
|
|
|
if dialector != nil {
|
2020-03-09 15:37:01 +03:00
|
|
|
err = dialector.Initialize(db)
|
2020-02-02 03:35:01 +03:00
|
|
|
}
|
|
|
|
return
|
2020-01-30 10:14:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Session create new db session
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) Session(config *Session) *DB {
|
2020-01-30 10:14:48 +03:00
|
|
|
var (
|
|
|
|
tx = db.getInstance()
|
2020-05-24 12:24:23 +03:00
|
|
|
stmt = tx.Statement.clone()
|
2020-01-30 10:14:48 +03:00
|
|
|
txConfig = *tx.Config
|
|
|
|
)
|
|
|
|
|
|
|
|
if config.Context != nil {
|
2020-05-24 12:24:23 +03:00
|
|
|
stmt.Context = config.Context
|
2020-01-30 10:14:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if config.Logger != nil {
|
|
|
|
txConfig.Logger = config.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.NowFunc != nil {
|
|
|
|
txConfig.NowFunc = config.NowFunc
|
|
|
|
}
|
|
|
|
|
2020-05-24 12:24:23 +03:00
|
|
|
return &DB{
|
|
|
|
Config: &txConfig,
|
|
|
|
Statement: stmt,
|
|
|
|
clone: true,
|
|
|
|
}
|
2020-01-29 14:22:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// WithContext change current instance db's context to ctx
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) WithContext(ctx context.Context) *DB {
|
2020-01-30 10:14:48 +03:00
|
|
|
return db.Session(&Session{Context: ctx})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debug start debug mode
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) Debug() (tx *DB) {
|
2020-01-30 10:14:48 +03:00
|
|
|
return db.Session(&Session{Logger: db.Logger.LogMode(logger.Info)})
|
|
|
|
}
|
|
|
|
|
2020-01-29 14:22:44 +03:00
|
|
|
// Set store value with key into current db instance's context
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) Set(key string, value interface{}) *DB {
|
2020-01-29 14:22:44 +03:00
|
|
|
tx := db.getInstance()
|
|
|
|
tx.Statement.Settings.Store(key, value)
|
|
|
|
return tx
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get get value with key from current db instance's context
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) Get(key string) (interface{}, bool) {
|
2020-01-29 14:22:44 +03:00
|
|
|
if db.Statement != nil {
|
|
|
|
return db.Statement.Settings.Load(key)
|
|
|
|
}
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
2020-02-02 03:35:01 +03:00
|
|
|
// Callback returns callback manager
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) Callback() *callbacks {
|
2020-02-02 03:35:01 +03:00
|
|
|
return db.callbacks
|
|
|
|
}
|
|
|
|
|
2020-02-22 14:41:01 +03:00
|
|
|
// AutoMigrate run auto migration for given models
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) AutoMigrate(dst ...interface{}) error {
|
2020-02-22 14:41:01 +03:00
|
|
|
return db.Migrator().AutoMigrate(dst...)
|
|
|
|
}
|
|
|
|
|
2020-03-09 08:10:48 +03:00
|
|
|
// AddError add error to db
|
2020-04-19 18:11:56 +03:00
|
|
|
func (db *DB) AddError(err error) error {
|
2020-03-09 15:37:01 +03:00
|
|
|
if db.Error == nil {
|
|
|
|
db.Error = err
|
|
|
|
} else if err != nil {
|
|
|
|
db.Error = fmt.Errorf("%v; %w", db.Error, err)
|
|
|
|
}
|
2020-04-19 18:11:56 +03:00
|
|
|
return db.Error
|
2020-03-09 08:10:48 +03:00
|
|
|
}
|
|
|
|
|
2020-03-09 15:37:01 +03:00
|
|
|
func (db *DB) getInstance() *DB {
|
2020-01-30 10:14:48 +03:00
|
|
|
if db.clone {
|
2020-05-31 06:34:59 +03:00
|
|
|
stmt := &Statement{
|
|
|
|
DB: db,
|
|
|
|
ConnPool: db.ConnPool,
|
|
|
|
Clauses: map[string]clause.Clause{},
|
|
|
|
Context: context.Background(),
|
|
|
|
}
|
|
|
|
|
2020-03-09 08:10:48 +03:00
|
|
|
if db.Statement != nil {
|
2020-03-09 10:32:55 +03:00
|
|
|
stmt.Context = db.Statement.Context
|
2020-01-30 10:14:48 +03:00
|
|
|
}
|
|
|
|
|
2020-03-09 15:37:01 +03:00
|
|
|
return &DB{Config: db.Config, Statement: stmt}
|
2020-01-29 14:22:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return db
|
|
|
|
}
|
2020-05-30 11:47:16 +03:00
|
|
|
|
|
|
|
func Expr(expr string, args ...interface{}) clause.Expr {
|
|
|
|
return clause.Expr{SQL: expr, Vars: args}
|
|
|
|
}
|