forked from mirror/gorm
Refactor builder
This commit is contained in:
parent
85bfd175c6
commit
9d5b9834d9
|
@ -1,5 +1,7 @@
|
|||
package gorm
|
||||
|
||||
import "github.com/jinzhu/gorm/clause"
|
||||
|
||||
// Model specify the model you would like to run db operations
|
||||
// // update all users's name to `hello`
|
||||
// db.Model(&User{}).Update("name", "hello")
|
||||
|
@ -11,6 +13,27 @@ func (db *DB) Model(value interface{}) (tx *DB) {
|
|||
return
|
||||
}
|
||||
|
||||
// Clauses Add clauses
|
||||
func (db *DB) Clauses(conds ...clause.Expression) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
var whereConds []interface{}
|
||||
|
||||
for _, cond := range conds {
|
||||
if c, ok := cond.(clause.Interface); ok {
|
||||
tx.Statement.AddClause(c)
|
||||
} else {
|
||||
whereConds = append(whereConds, cond)
|
||||
}
|
||||
}
|
||||
|
||||
if len(whereConds) > 0 {
|
||||
tx.Statement.AddClause(clause.Where{
|
||||
AndConditions: tx.Statement.BuildCondtion(whereConds[0], whereConds[1:]...),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Table specify the table you would like to run db operations
|
||||
func (db *DB) Table(name string) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
|
@ -32,18 +55,25 @@ func (db *DB) Omit(columns ...string) (tx *DB) {
|
|||
|
||||
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
tx.Statement.AddClause(clause.Where{AndConditions: tx.Statement.BuildCondtion(query, args...)})
|
||||
return
|
||||
}
|
||||
|
||||
// Not add NOT condition
|
||||
func (db *DB) Not(query interface{}, args ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
tx.Statement.AddClause(clause.Where{
|
||||
AndConditions: []clause.Expression{clause.NotConditions(tx.Statement.BuildCondtion(query, args...))},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Or add OR conditions
|
||||
func (db *DB) Or(query interface{}, args ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
tx.Statement.AddClause(clause.Where{
|
||||
ORConditions: []clause.ORConditions{tx.Statement.BuildCondtion(query, args...)},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -98,20 +128,13 @@ func (db *DB) Offset(offset int64) (tx *DB) {
|
|||
// }
|
||||
//
|
||||
// db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
|
||||
// Refer https://jinzhu.github.io/gorm/crud.html#scopes
|
||||
func (db *DB) Scopes(funcs ...func(*DB) *DB) (tx *DB) {
|
||||
func (db *DB) Scopes(funcs ...func(*DB) *DB) *DB {
|
||||
for _, f := range funcs {
|
||||
db = f(db)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
//Preloads only preloads relations, don`t touch out
|
||||
func (db *DB) Preloads(out interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
||||
// Preload preload associations with given conditions
|
||||
// db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
|
||||
func (db *DB) Preload(column string, conditions ...interface{}) (tx *DB) {
|
||||
|
|
128
clause/clause.go
128
clause/clause.go
|
@ -1,31 +1,131 @@
|
|||
package clause
|
||||
|
||||
// Builder builder interface
|
||||
type BuilderInterface interface {
|
||||
Write(sql ...string) error
|
||||
WriteQuoted(field interface{}) error
|
||||
AddVar(vars ...interface{}) string
|
||||
Quote(field interface{}) string
|
||||
// Clause
|
||||
type Clause struct {
|
||||
Name string // WHERE
|
||||
Priority float64
|
||||
BeforeExpressions []Expression
|
||||
AfterNameExpressions []Expression
|
||||
AfterExpressions []Expression
|
||||
Expression Expression
|
||||
Builder ClauseBuilder
|
||||
}
|
||||
|
||||
// ClauseBuilder clause builder, allows to custmize how to build clause
|
||||
type ClauseBuilder interface {
|
||||
Build(Clause, Builder)
|
||||
}
|
||||
|
||||
// Build build clause
|
||||
func (c Clause) Build(builder Builder) {
|
||||
if c.Builder != nil {
|
||||
c.Builder.Build(c, builder)
|
||||
} else {
|
||||
builders := c.BeforeExpressions
|
||||
if c.Name != "" {
|
||||
builders = append(builders, Expr{c.Name})
|
||||
}
|
||||
|
||||
builders = append(builders, c.AfterNameExpressions...)
|
||||
if c.Expression != nil {
|
||||
builders = append(builders, c.Expression)
|
||||
}
|
||||
|
||||
for idx, expr := range append(builders, c.AfterExpressions...) {
|
||||
if idx != 0 {
|
||||
builder.WriteByte(' ')
|
||||
}
|
||||
expr.Build(builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interface clause interface
|
||||
type Interface interface {
|
||||
Name() string
|
||||
Builder
|
||||
Build(Builder)
|
||||
MergeExpression(Expression)
|
||||
}
|
||||
|
||||
// Builder condition builder
|
||||
type Builder interface {
|
||||
Build(builder BuilderInterface)
|
||||
type OverrideNameInterface interface {
|
||||
OverrideName() string
|
||||
}
|
||||
|
||||
// NegationBuilder negation condition builder
|
||||
type NegationBuilder interface {
|
||||
NegationBuild(builder BuilderInterface)
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Predefined Clauses
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Where where clause
|
||||
type Where struct {
|
||||
AndConditions AddConditions
|
||||
ORConditions []ORConditions
|
||||
Builders []Expression
|
||||
}
|
||||
|
||||
func (where Where) Name() string {
|
||||
return "WHERE"
|
||||
}
|
||||
|
||||
func (where Where) Build(builder Builder) {
|
||||
var withConditions bool
|
||||
|
||||
if len(where.AndConditions) > 0 {
|
||||
withConditions = true
|
||||
where.AndConditions.Build(builder)
|
||||
}
|
||||
|
||||
if len(where.Builders) > 0 {
|
||||
for _, b := range where.Builders {
|
||||
if withConditions {
|
||||
builder.Write(" AND ")
|
||||
}
|
||||
withConditions = true
|
||||
b.Build(builder)
|
||||
}
|
||||
}
|
||||
|
||||
var singleOrConditions []ORConditions
|
||||
for _, or := range where.ORConditions {
|
||||
if len(or) == 1 {
|
||||
if withConditions {
|
||||
builder.Write(" OR ")
|
||||
or.Build(builder)
|
||||
} else {
|
||||
singleOrConditions = append(singleOrConditions, or)
|
||||
}
|
||||
} else {
|
||||
withConditions = true
|
||||
builder.Write(" AND (")
|
||||
or.Build(builder)
|
||||
builder.WriteByte(')')
|
||||
}
|
||||
}
|
||||
|
||||
for _, or := range singleOrConditions {
|
||||
if withConditions {
|
||||
builder.Write(" AND ")
|
||||
or.Build(builder)
|
||||
} else {
|
||||
withConditions = true
|
||||
or.Build(builder)
|
||||
}
|
||||
}
|
||||
|
||||
if !withConditions {
|
||||
builder.Write(" FALSE")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (where Where) MergeExpression(expr Expression) {
|
||||
if w, ok := expr.(Where); ok {
|
||||
where.AndConditions = append(where.AndConditions, w.AndConditions...)
|
||||
where.ORConditions = append(where.ORConditions, w.ORConditions...)
|
||||
where.Builders = append(where.Builders, w.Builders...)
|
||||
} else {
|
||||
where.Builders = append(where.Builders, expr)
|
||||
}
|
||||
}
|
||||
|
||||
// Select select attrs when querying, updating, creating
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
package clause
|
||||
|
||||
type ExprInterface interface {
|
||||
}
|
||||
|
||||
type Expr struct {
|
||||
}
|
||||
|
||||
type Average struct {
|
||||
}
|
||||
|
||||
type Minimum struct {
|
||||
}
|
||||
|
||||
type Maximum struct {
|
||||
}
|
||||
|
||||
type Sum struct {
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package clause
|
||||
|
||||
// Expression expression interface
|
||||
type Expression interface {
|
||||
Build(builder Builder)
|
||||
}
|
||||
|
||||
// NegationExpressionBuilder negation expression builder
|
||||
type NegationExpressionBuilder interface {
|
||||
NegationBuild(builder Builder)
|
||||
}
|
||||
|
||||
// Builder builder interface
|
||||
type Builder interface {
|
||||
WriteByte(byte) error
|
||||
Write(sql ...string) error
|
||||
WriteQuoted(field interface{}) error
|
||||
AddVar(vars ...interface{}) string
|
||||
Quote(field interface{}) string
|
||||
}
|
||||
|
||||
// Expr raw expression
|
||||
type Expr struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
// Build build raw expression
|
||||
func (expr Expr) Build(builder Builder) {
|
||||
builder.Write(expr.Value)
|
||||
}
|
|
@ -2,10 +2,13 @@ package clause
|
|||
|
||||
import "strings"
|
||||
|
||||
type Condition Builder
|
||||
type AddConditions []Condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Expressions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (cs AddConditions) Build(builder BuilderInterface) {
|
||||
type AddConditions []Expression
|
||||
|
||||
func (cs AddConditions) Build(builder Builder) {
|
||||
for idx, c := range cs {
|
||||
if idx > 0 {
|
||||
builder.Write(" AND ")
|
||||
|
@ -14,9 +17,9 @@ func (cs AddConditions) Build(builder BuilderInterface) {
|
|||
}
|
||||
}
|
||||
|
||||
type ORConditions []Condition
|
||||
type ORConditions []Expression
|
||||
|
||||
func (cs ORConditions) Build(builder BuilderInterface) {
|
||||
func (cs ORConditions) Build(builder Builder) {
|
||||
for idx, c := range cs {
|
||||
if idx > 0 {
|
||||
builder.Write(" OR ")
|
||||
|
@ -25,15 +28,15 @@ func (cs ORConditions) Build(builder BuilderInterface) {
|
|||
}
|
||||
}
|
||||
|
||||
type NotConditions []Condition
|
||||
type NotConditions []Expression
|
||||
|
||||
func (cs NotConditions) Build(builder BuilderInterface) {
|
||||
func (cs NotConditions) Build(builder Builder) {
|
||||
for idx, c := range cs {
|
||||
if idx > 0 {
|
||||
builder.Write(" AND ")
|
||||
}
|
||||
|
||||
if negationBuilder, ok := c.(NegationBuilder); ok {
|
||||
if negationBuilder, ok := c.(NegationExpressionBuilder); ok {
|
||||
negationBuilder.NegationBuild(builder)
|
||||
} else {
|
||||
builder.Write(" NOT ")
|
||||
|
@ -42,15 +45,15 @@ func (cs NotConditions) Build(builder BuilderInterface) {
|
|||
}
|
||||
}
|
||||
|
||||
// Raw raw sql for where
|
||||
type Raw struct {
|
||||
// String raw sql for where
|
||||
type String struct {
|
||||
SQL string
|
||||
Values []interface{}
|
||||
}
|
||||
|
||||
func (raw Raw) Build(builder BuilderInterface) {
|
||||
sql := raw.SQL
|
||||
for _, v := range raw.Values {
|
||||
func (str String) Build(builder Builder) {
|
||||
sql := str.SQL
|
||||
for _, v := range str.Values {
|
||||
sql = strings.Replace(sql, " ? ", " "+builder.AddVar(v)+" ", 1)
|
||||
}
|
||||
builder.Write(sql)
|
||||
|
@ -62,7 +65,7 @@ type IN struct {
|
|||
Values []interface{}
|
||||
}
|
||||
|
||||
func (in IN) Build(builder BuilderInterface) {
|
||||
func (in IN) Build(builder Builder) {
|
||||
builder.WriteQuoted(in.Column)
|
||||
|
||||
switch len(in.Values) {
|
||||
|
@ -75,7 +78,7 @@ func (in IN) Build(builder BuilderInterface) {
|
|||
}
|
||||
}
|
||||
|
||||
func (in IN) NegationBuild(builder BuilderInterface) {
|
||||
func (in IN) NegationBuild(builder Builder) {
|
||||
switch len(in.Values) {
|
||||
case 0:
|
||||
case 1:
|
||||
|
@ -91,7 +94,7 @@ type Eq struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (eq Eq) Build(builder BuilderInterface) {
|
||||
func (eq Eq) Build(builder Builder) {
|
||||
builder.WriteQuoted(eq.Column)
|
||||
|
||||
if eq.Value == nil {
|
||||
|
@ -101,7 +104,7 @@ func (eq Eq) Build(builder BuilderInterface) {
|
|||
}
|
||||
}
|
||||
|
||||
func (eq Eq) NegationBuild(builder BuilderInterface) {
|
||||
func (eq Eq) NegationBuild(builder Builder) {
|
||||
Neq{eq.Column, eq.Value}.Build(builder)
|
||||
}
|
||||
|
||||
|
@ -111,7 +114,7 @@ type Neq struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (neq Neq) Build(builder BuilderInterface) {
|
||||
func (neq Neq) Build(builder Builder) {
|
||||
builder.WriteQuoted(neq.Column)
|
||||
|
||||
if neq.Value == nil {
|
||||
|
@ -121,7 +124,7 @@ func (neq Neq) Build(builder BuilderInterface) {
|
|||
}
|
||||
}
|
||||
|
||||
func (neq Neq) NegationBuild(builder BuilderInterface) {
|
||||
func (neq Neq) NegationBuild(builder Builder) {
|
||||
Eq{neq.Column, neq.Value}.Build(builder)
|
||||
}
|
||||
|
||||
|
@ -131,12 +134,12 @@ type Gt struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (gt Gt) Build(builder BuilderInterface) {
|
||||
func (gt Gt) Build(builder Builder) {
|
||||
builder.WriteQuoted(gt.Column)
|
||||
builder.Write(" > ", builder.AddVar(gt.Value))
|
||||
}
|
||||
|
||||
func (gt Gt) NegationBuild(builder BuilderInterface) {
|
||||
func (gt Gt) NegationBuild(builder Builder) {
|
||||
Lte{gt.Column, gt.Value}.Build(builder)
|
||||
}
|
||||
|
||||
|
@ -146,12 +149,12 @@ type Gte struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (gte Gte) Build(builder BuilderInterface) {
|
||||
func (gte Gte) Build(builder Builder) {
|
||||
builder.WriteQuoted(gte.Column)
|
||||
builder.Write(" >= ", builder.AddVar(gte.Value))
|
||||
}
|
||||
|
||||
func (gte Gte) NegationBuild(builder BuilderInterface) {
|
||||
func (gte Gte) NegationBuild(builder Builder) {
|
||||
Lt{gte.Column, gte.Value}.Build(builder)
|
||||
}
|
||||
|
||||
|
@ -161,12 +164,12 @@ type Lt struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (lt Lt) Build(builder BuilderInterface) {
|
||||
func (lt Lt) Build(builder Builder) {
|
||||
builder.WriteQuoted(lt.Column)
|
||||
builder.Write(" < ", builder.AddVar(lt.Value))
|
||||
}
|
||||
|
||||
func (lt Lt) NegationBuild(builder BuilderInterface) {
|
||||
func (lt Lt) NegationBuild(builder Builder) {
|
||||
Gte{lt.Column, lt.Value}.Build(builder)
|
||||
}
|
||||
|
||||
|
@ -176,12 +179,12 @@ type Lte struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (lte Lte) Build(builder BuilderInterface) {
|
||||
func (lte Lte) Build(builder Builder) {
|
||||
builder.WriteQuoted(lte.Column)
|
||||
builder.Write(" <= ", builder.AddVar(lte.Value))
|
||||
}
|
||||
|
||||
func (lte Lte) NegationBuild(builder BuilderInterface) {
|
||||
func (lte Lte) NegationBuild(builder Builder) {
|
||||
Gt{lte.Column, lte.Value}.Build(builder)
|
||||
}
|
||||
|
||||
|
@ -191,12 +194,12 @@ type Like struct {
|
|||
Value interface{}
|
||||
}
|
||||
|
||||
func (like Like) Build(builder BuilderInterface) {
|
||||
func (like Like) Build(builder Builder) {
|
||||
builder.WriteQuoted(like.Column)
|
||||
builder.Write(" LIKE ", builder.AddVar(like.Value))
|
||||
}
|
||||
|
||||
func (like Like) NegationBuild(builder BuilderInterface) {
|
||||
func (like Like) NegationBuild(builder Builder) {
|
||||
builder.WriteQuoted(like.Column)
|
||||
builder.Write(" NOT LIKE ", builder.AddVar(like.Value))
|
||||
}
|
||||
|
@ -204,11 +207,11 @@ func (like Like) NegationBuild(builder BuilderInterface) {
|
|||
// Map
|
||||
type Map map[interface{}]interface{}
|
||||
|
||||
func (m Map) Build(builder BuilderInterface) {
|
||||
func (m Map) Build(builder Builder) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func (m Map) NegationBuild(builder BuilderInterface) {
|
||||
func (m Map) NegationBuild(builder Builder) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
@ -219,13 +222,13 @@ type Attrs struct {
|
|||
Omit []string
|
||||
}
|
||||
|
||||
func (attrs Attrs) Build(builder BuilderInterface) {
|
||||
func (attrs Attrs) Build(builder Builder) {
|
||||
// TODO
|
||||
// builder.WriteQuoted(like.Column)
|
||||
// builder.Write(" LIKE ", builder.AddVar(like.Value))
|
||||
}
|
||||
|
||||
func (attrs Attrs) NegationBuild(builder BuilderInterface) {
|
||||
func (attrs Attrs) NegationBuild(builder Builder) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
@ -234,7 +237,7 @@ type ID struct {
|
|||
Value []interface{}
|
||||
}
|
||||
|
||||
func (id ID) Build(builder BuilderInterface) {
|
||||
func (id ID) Build(builder Builder) {
|
||||
if len(id.Value) == 1 {
|
||||
}
|
||||
// TODO
|
||||
|
@ -242,6 +245,6 @@ func (id ID) Build(builder BuilderInterface) {
|
|||
// builder.Write(" LIKE ", builder.AddVar(like.Value))
|
||||
}
|
||||
|
||||
func (id ID) NegationBuild(builder BuilderInterface) {
|
||||
func (id ID) NegationBuild(builder Builder) {
|
||||
// TODO
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package gorm
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrRecordNotFound record not found error
|
||||
ErrRecordNotFound = errors.New("record not found")
|
||||
// ErrInvalidSQL invalid SQL error, happens when you passed invalid SQL
|
||||
ErrInvalidSQL = errors.New("invalid SQL")
|
||||
// ErrInvalidTransaction invalid transaction when you are trying to `Commit` or `Rollback`
|
||||
ErrInvalidTransaction = errors.New("no valid transaction")
|
||||
// ErrUnaddressable unaddressable value
|
||||
ErrUnaddressable = errors.New("using unaddressable value")
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e Error) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
|
@ -33,8 +33,6 @@ func (db *DB) Find(out interface{}, where ...interface{}) (tx *DB) {
|
|||
return
|
||||
}
|
||||
|
||||
// Scan scan value to a struct
|
||||
|
||||
func (db *DB) Row() *sql.Row {
|
||||
// TODO
|
||||
return nil
|
||||
|
@ -45,6 +43,7 @@ func (db *DB) Rows() (*sql.Rows, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Scan scan value to a struct
|
||||
func (db *DB) Scan(dest interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
|
@ -88,12 +87,12 @@ func (db *DB) UpdateColumns(values interface{}) (tx *DB) {
|
|||
return
|
||||
}
|
||||
|
||||
func (db *DB) FirstOrCreate(out interface{}, where ...interface{}) (tx *DB) {
|
||||
func (db *DB) FirstOrInit(out interface{}, where ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) FirstOrInit(out interface{}, where ...interface{}) (tx *DB) {
|
||||
func (db *DB) FirstOrCreate(out interface{}, where ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
@ -109,6 +108,16 @@ func (db *DB) Related(value interface{}, foreignKeys ...string) (tx *DB) {
|
|||
return
|
||||
}
|
||||
|
||||
//Preloads only preloads relations, don`t touch out
|
||||
func (db *DB) Preloads(out interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) Association(column string) *Association {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {
|
||||
panicked := true
|
||||
tx := db.Begin(opts...)
|
||||
|
@ -148,7 +157,3 @@ func (db *DB) Exec(sql string, values ...interface{}) (tx *DB) {
|
|||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) Association(column string) *Association {
|
||||
return nil
|
||||
}
|
||||
|
|
105
gorm.go
105
gorm.go
|
@ -25,44 +25,72 @@ type Config struct {
|
|||
NowFunc func() time.Time
|
||||
}
|
||||
|
||||
// Model a basic GoLang struct which includes the following fields: ID, CreatedAt, UpdatedAt, DeletedAt
|
||||
// It may be embeded into your model or you may build your own model without it
|
||||
// type User struct {
|
||||
// gorm.Model
|
||||
// }
|
||||
type Model struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time `gorm:"index"`
|
||||
}
|
||||
|
||||
// Dialector GORM database dialector
|
||||
type Dialector interface {
|
||||
Migrator() Migrator
|
||||
BindVar(stmt Statement, v interface{}) string
|
||||
}
|
||||
|
||||
// Result
|
||||
type Result struct {
|
||||
Error error
|
||||
RowsAffected int64
|
||||
Statement *Statement
|
||||
}
|
||||
|
||||
// DB GORM DB definition
|
||||
type DB struct {
|
||||
*Config
|
||||
Dialector
|
||||
Result
|
||||
Instance
|
||||
clone bool
|
||||
}
|
||||
|
||||
// Session session config when create new session
|
||||
type Session struct {
|
||||
Context context.Context
|
||||
Logger logger.Interface
|
||||
NowFunc func() time.Time
|
||||
}
|
||||
|
||||
// Open initialize db session based on dialector
|
||||
func Open(dialector Dialector, config *Config) (db *DB, err error) {
|
||||
return &DB{
|
||||
Config: config,
|
||||
Dialector: dialector,
|
||||
clone: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Session create new db session
|
||||
func (db *DB) Session(config *Session) *DB {
|
||||
var (
|
||||
tx = db.getInstance()
|
||||
txConfig = *tx.Config
|
||||
)
|
||||
|
||||
if config.Context != nil {
|
||||
tx.Context = config.Context
|
||||
}
|
||||
|
||||
if config.Logger != nil {
|
||||
txConfig.Logger = config.Logger
|
||||
}
|
||||
|
||||
if config.NowFunc != nil {
|
||||
txConfig.NowFunc = config.NowFunc
|
||||
}
|
||||
|
||||
tx.Config = &txConfig
|
||||
tx.clone = true
|
||||
return tx
|
||||
}
|
||||
|
||||
// WithContext change current instance db's context to ctx
|
||||
func (db *DB) WithContext(ctx context.Context) *DB {
|
||||
tx := db.getInstance()
|
||||
tx.Context = ctx
|
||||
return tx
|
||||
return db.Session(&Session{Context: ctx})
|
||||
}
|
||||
|
||||
// Debug start debug mode
|
||||
func (db *DB) Debug() (tx *DB) {
|
||||
return db.Session(&Session{Logger: db.Logger.LogMode(logger.Info)})
|
||||
}
|
||||
|
||||
func (db *DB) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set store value with key into current db instance's context
|
||||
|
@ -80,35 +108,22 @@ func (db *DB) Get(key string) (interface{}, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
func (db *DB) Close() *DB {
|
||||
// TODO
|
||||
return db
|
||||
}
|
||||
|
||||
func (db *DB) getInstance() *DB {
|
||||
// db.Result.Statement == nil means root DB
|
||||
if db.Result.Statement == nil {
|
||||
if db.clone {
|
||||
ctx := db.Instance.Context
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
return &DB{
|
||||
Config: db.Config,
|
||||
Dialector: db.Dialector,
|
||||
Context: context.Background(),
|
||||
Result: Result{
|
||||
Statement: &Statement{DB: db, Clauses: map[string][]clause.Condition{}},
|
||||
Instance: Instance{
|
||||
Context: ctx,
|
||||
Statement: &Statement{DB: db, Clauses: map[string]clause.Clause{}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// Debug start debug mode
|
||||
func (db *DB) Debug() (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
||||
// Session start session mode
|
||||
func (db *DB) Session() (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
package logger
|
||||
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
Info LogLevel = iota + 1
|
||||
Warn
|
||||
Error
|
||||
)
|
||||
|
||||
// Interface logger interface
|
||||
type Interface interface {
|
||||
LogMode(LogLevel) Interface
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package gorm
|
||||
|
||||
import "time"
|
||||
|
||||
// Model a basic GoLang struct which includes the following fields: ID, CreatedAt, UpdatedAt, DeletedAt
|
||||
// It may be embeded into your model or you may build your own model without it
|
||||
// type User struct {
|
||||
// gorm.Model
|
||||
// }
|
||||
type Model struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time `gorm:"index"`
|
||||
}
|
107
statement.go
107
statement.go
|
@ -1,7 +1,6 @@
|
|||
package gorm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
|
@ -13,25 +12,43 @@ import (
|
|||
"github.com/jinzhu/gorm/clause"
|
||||
)
|
||||
|
||||
// Statement statement
|
||||
type Statement struct {
|
||||
Model interface{}
|
||||
Dest interface{}
|
||||
Table string
|
||||
Clauses map[string][]clause.Condition
|
||||
Settings sync.Map
|
||||
Context context.Context
|
||||
DB *DB
|
||||
StatementBuilder
|
||||
// Instance db instance
|
||||
type Instance struct {
|
||||
Error error
|
||||
RowsAffected int64
|
||||
Context context.Context
|
||||
Statement *Statement
|
||||
}
|
||||
|
||||
// StatementBuilder statement builder
|
||||
type StatementBuilder struct {
|
||||
SQL bytes.Buffer
|
||||
// AddError add error to instance
|
||||
func (inst Instance) AddError(err error) {
|
||||
if inst.Error == nil {
|
||||
inst.Error = err
|
||||
} else {
|
||||
inst.Error = fmt.Errorf("%v; %w", inst.Error, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Statement statement
|
||||
type Statement struct {
|
||||
Table string
|
||||
Model interface{}
|
||||
Dest interface{}
|
||||
Clauses map[string]clause.Clause
|
||||
Settings sync.Map
|
||||
DB *DB
|
||||
|
||||
// SQL Builder
|
||||
SQL strings.Builder
|
||||
Vars []interface{}
|
||||
NamedVars []sql.NamedArg
|
||||
}
|
||||
|
||||
// StatementOptimizer statement optimizer interface
|
||||
type StatementOptimizer interface {
|
||||
OptimizeStatement(Statement)
|
||||
}
|
||||
|
||||
// Write write string
|
||||
func (stmt Statement) Write(sql ...string) (err error) {
|
||||
for _, s := range sql {
|
||||
|
@ -40,12 +57,23 @@ func (stmt Statement) Write(sql ...string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Write write string
|
||||
func (stmt Statement) WriteByte(c byte) (err error) {
|
||||
return stmt.SQL.WriteByte(c)
|
||||
}
|
||||
|
||||
// WriteQuoted write quoted field
|
||||
func (stmt Statement) WriteQuoted(field interface{}) (err error) {
|
||||
_, err = stmt.SQL.WriteString(stmt.Quote(field))
|
||||
return
|
||||
}
|
||||
|
||||
// Quote returns quoted value
|
||||
func (stmt Statement) Quote(field interface{}) (str string) {
|
||||
// FIXME
|
||||
return fmt.Sprint(field)
|
||||
}
|
||||
|
||||
// Write write string
|
||||
func (stmt Statement) AddVar(vars ...interface{}) string {
|
||||
var placeholders strings.Builder
|
||||
|
@ -73,23 +101,34 @@ func (stmt Statement) AddVar(vars ...interface{}) string {
|
|||
return placeholders.String()
|
||||
}
|
||||
|
||||
// Quote returns quoted value
|
||||
func (stmt Statement) Quote(field interface{}) (str string) {
|
||||
return fmt.Sprint(field)
|
||||
}
|
||||
|
||||
// AddClause add clause
|
||||
func (s Statement) AddClause(clause clause.Interface) {
|
||||
s.Clauses[clause.Name()] = append(s.Clauses[clause.Name()], clause)
|
||||
func (stmt Statement) AddClause(v clause.Interface) {
|
||||
if optimizer, ok := v.(StatementOptimizer); ok {
|
||||
optimizer.OptimizeStatement(stmt)
|
||||
}
|
||||
|
||||
c, _ := stmt.Clauses[v.Name()]
|
||||
if namer, ok := v.(clause.OverrideNameInterface); ok {
|
||||
c.Name = namer.OverrideName()
|
||||
} else {
|
||||
c.Name = v.Name()
|
||||
}
|
||||
|
||||
if c.Expression != nil {
|
||||
v.MergeExpression(c.Expression)
|
||||
}
|
||||
|
||||
c.Expression = v
|
||||
stmt.Clauses[v.Name()] = c
|
||||
}
|
||||
|
||||
// BuildCondtions build conditions
|
||||
func (s Statement) BuildCondtions(query interface{}, args ...interface{}) (conditions []clause.Condition) {
|
||||
// BuildCondtion build condition
|
||||
func (stmt Statement) BuildCondtion(query interface{}, args ...interface{}) (conditions []clause.Expression) {
|
||||
if sql, ok := query.(string); ok {
|
||||
if i, err := strconv.Atoi(sql); err != nil {
|
||||
query = i
|
||||
} else if len(args) == 0 || (len(args) > 0 && strings.Contains(sql, "?")) || strings.Contains(sql, "@") {
|
||||
return []clause.Condition{clause.Raw{SQL: sql, Values: args}}
|
||||
return []clause.Expression{clause.String{SQL: sql, Values: args}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,12 +139,12 @@ func (s Statement) BuildCondtions(query interface{}, args ...interface{}) (condi
|
|||
}
|
||||
|
||||
switch v := arg.(type) {
|
||||
case clause.Builder:
|
||||
case clause.Expression:
|
||||
conditions = append(conditions, v)
|
||||
case *DB:
|
||||
if v.Statement == nil {
|
||||
if cs, ok := v.Statement.Clauses["WHERE"]; ok {
|
||||
conditions = append(conditions, cs...)
|
||||
conditions = append(conditions, cs.Expression)
|
||||
}
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
|
@ -135,8 +174,22 @@ func (s Statement) BuildCondtions(query interface{}, args ...interface{}) (condi
|
|||
if len(conditions) == 0 {
|
||||
conditions = append(conditions, clause.ID{Value: args})
|
||||
}
|
||||
|
||||
return conditions
|
||||
}
|
||||
|
||||
func (s Statement) AddError(err error) {
|
||||
// Build build sql with clauses names
|
||||
func (stmt Statement) Build(clauses ...string) {
|
||||
var includeSpace bool
|
||||
|
||||
for _, name := range clauses {
|
||||
if c, ok := stmt.Clauses[name]; ok {
|
||||
if includeSpace {
|
||||
stmt.WriteByte(' ')
|
||||
}
|
||||
|
||||
includeSpace = true
|
||||
c.Build(stmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue