forked from mirror/gorm
Add clause, DB API, model definition
This commit is contained in:
parent
8eae7e4ab9
commit
b9cce2be6a
|
@ -1,4 +1,4 @@
|
||||||
TODO
|
TODO*
|
||||||
documents
|
documents
|
||||||
coverage.txt
|
coverage.txt
|
||||||
_book
|
_book
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package gorm
|
||||||
|
|
||||||
|
// Association Mode contains some helper methods to handle relationship things easily.
|
||||||
|
type Association struct {
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
package gorm
|
||||||
|
|
||||||
|
// Model specify the model you would like to run db operations
|
||||||
|
// // update all users's name to `hello`
|
||||||
|
// db.Model(&User{}).Update("name", "hello")
|
||||||
|
// // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello`
|
||||||
|
// db.Model(&user).Update("name", "hello")
|
||||||
|
func (db *DB) Model(value interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table specify the table you would like to run db operations
|
||||||
|
func (db *DB) Table(name string) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select specify fields that you want when querying, creating, updating
|
||||||
|
func (db *DB) Select(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Omit specify fields that you want to ignore when creating, updating and querying
|
||||||
|
func (db *DB) Omit(columns ...string) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not add NOT condition
|
||||||
|
func (db *DB) Not(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or add OR conditions
|
||||||
|
func (db *DB) Or(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Joins specify Joins conditions
|
||||||
|
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
||||||
|
func (db *DB) Joins(query string, args ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group specify the group method on the find
|
||||||
|
func (db *DB) Group(column string) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Having specify HAVING conditions for GROUP BY
|
||||||
|
func (db *DB) Having(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order specify order when retrieve records from database
|
||||||
|
// db.Order("name DESC")
|
||||||
|
// db.Order(gorm.Expr("name = ? DESC", "first")) // sql expression
|
||||||
|
func (db *DB) Order(value interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit specify the number of records to be retrieved
|
||||||
|
func (db *DB) Limit(limit int64) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset specify the number of records to skip before starting to return the records
|
||||||
|
func (db *DB) Offset(offset int64) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically
|
||||||
|
// func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
|
||||||
|
// return db.Where("amount > ?", 1000)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
|
||||||
|
// return func (db *gorm.DB) *gorm.DB {
|
||||||
|
// return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
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) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Assign(attrs ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Attrs(attrs ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Unscoped() (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Raw(sql string, values ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package clause
|
||||||
|
|
||||||
|
// Builder builder interface
|
||||||
|
type BuilderInterface interface {
|
||||||
|
Write(sql ...string) error
|
||||||
|
WriteQuoted(field interface{}) error
|
||||||
|
AddVar(vars ...interface{}) string
|
||||||
|
Quote(field interface{}) string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface clause interface
|
||||||
|
type Interface interface {
|
||||||
|
Name() string
|
||||||
|
Build(builder BuilderInterface)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NegationBuilder negation condition builder
|
||||||
|
type NegationBuilder interface {
|
||||||
|
NegationBuild(builder BuilderInterface)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where where clause
|
||||||
|
type Where struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select select attrs when querying, updating, creating
|
||||||
|
type Select struct {
|
||||||
|
Omit bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join join clause
|
||||||
|
type Join struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupBy group by clause
|
||||||
|
type GroupBy struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Having having clause
|
||||||
|
type Having struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order order clause
|
||||||
|
type Order struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit limit clause
|
||||||
|
type Limit struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset offset clause
|
||||||
|
type Offset struct {
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package clause
|
||||||
|
|
||||||
|
type ExprInterface interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Expr struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Average struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Minimum struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Maximum struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Sum struct {
|
||||||
|
}
|
|
@ -0,0 +1,195 @@
|
||||||
|
package clause
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type AddConditions []Interface
|
||||||
|
|
||||||
|
func (cs AddConditions) Build(builder BuilderInterface) {
|
||||||
|
for idx, c := range cs {
|
||||||
|
if idx > 0 {
|
||||||
|
builder.Write(" AND ")
|
||||||
|
}
|
||||||
|
c.Build(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ORConditions []Interface
|
||||||
|
|
||||||
|
func (cs ORConditions) Build(builder BuilderInterface) {
|
||||||
|
for idx, c := range cs {
|
||||||
|
if idx > 0 {
|
||||||
|
builder.Write(" OR ")
|
||||||
|
}
|
||||||
|
c.Build(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotConditions []Interface
|
||||||
|
|
||||||
|
func (cs NotConditions) Build(builder BuilderInterface) {
|
||||||
|
for idx, c := range cs {
|
||||||
|
if idx > 0 {
|
||||||
|
builder.Write(" AND ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if negationBuilder, ok := c.(NegationBuilder); ok {
|
||||||
|
negationBuilder.NegationBuild(builder)
|
||||||
|
} else {
|
||||||
|
builder.Write(" NOT ")
|
||||||
|
c.Build(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw raw sql for where
|
||||||
|
type Raw struct {
|
||||||
|
SQL string
|
||||||
|
Values []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (raw Raw) Build(builder BuilderInterface) {
|
||||||
|
sql := raw.SQL
|
||||||
|
for _, v := range raw.Values {
|
||||||
|
sql = strings.Replace(sql, " ? ", " "+builder.AddVar(v)+" ", 1)
|
||||||
|
}
|
||||||
|
builder.Write(sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IN Whether a value is within a set of values
|
||||||
|
type IN struct {
|
||||||
|
Column interface{}
|
||||||
|
Values []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (in IN) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(in.Column)
|
||||||
|
|
||||||
|
if len(in.Values) == 0 {
|
||||||
|
builder.Write(" IN (NULL)")
|
||||||
|
} else {
|
||||||
|
builder.Write(" IN (", builder.AddVar(in.Values...), ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (in IN) NegationBuild(builder BuilderInterface) {
|
||||||
|
if len(in.Values) != 0 {
|
||||||
|
builder.WriteQuoted(in.Column)
|
||||||
|
builder.Write(" NOT IN (", builder.AddVar(in.Values...), ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eq equal to for where
|
||||||
|
type Eq struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eq Eq) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(eq.Column)
|
||||||
|
|
||||||
|
if eq.Value == nil {
|
||||||
|
builder.Write(" IS NULL")
|
||||||
|
} else {
|
||||||
|
builder.Write(" = ", builder.AddVar(eq.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eq Eq) NegationBuild(builder BuilderInterface) {
|
||||||
|
Neq{eq.Column, eq.Value}.Build(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neq not equal to for where
|
||||||
|
type Neq struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (neq Neq) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(neq.Column)
|
||||||
|
|
||||||
|
if neq.Value == nil {
|
||||||
|
builder.Write(" IS NOT NULL")
|
||||||
|
} else {
|
||||||
|
builder.Write(" <> ", builder.AddVar(neq.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (neq Neq) NegationBuild(builder BuilderInterface) {
|
||||||
|
Eq{neq.Column, neq.Value}.Build(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gt greater than for where
|
||||||
|
type Gt struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gt Gt) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(gt.Column)
|
||||||
|
builder.Write(" > ", builder.AddVar(gt.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gt Gt) NegationBuild(builder BuilderInterface) {
|
||||||
|
Lte{gt.Column, gt.Value}.Build(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gte greater than or equal to for where
|
||||||
|
type Gte struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gte Gte) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(gte.Column)
|
||||||
|
builder.Write(" >= ", builder.AddVar(gte.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gte Gte) NegationBuild(builder BuilderInterface) {
|
||||||
|
Lt{gte.Column, gte.Value}.Build(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lt less than for where
|
||||||
|
type Lt struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lt Lt) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(lt.Column)
|
||||||
|
builder.Write(" < ", builder.AddVar(lt.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lt Lt) NegationBuild(builder BuilderInterface) {
|
||||||
|
Gte{lt.Column, lt.Value}.Build(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lte less than or equal to for where
|
||||||
|
type Lte struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lte Lte) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(lte.Column)
|
||||||
|
builder.Write(" <= ", builder.AddVar(lte.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lte Lte) NegationBuild(builder BuilderInterface) {
|
||||||
|
Gt{lte.Column, lte.Value}.Build(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like whether string matches regular expression
|
||||||
|
type Like struct {
|
||||||
|
Column interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (like Like) Build(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(like.Column)
|
||||||
|
builder.Write(" LIKE ", builder.AddVar(like.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (like Like) NegationBuild(builder BuilderInterface) {
|
||||||
|
builder.WriteQuoted(like.Column)
|
||||||
|
builder.Write(" NOT LIKE ", builder.AddVar(like.Value))
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
package gorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (db *DB) Count(sql string, values ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// First find first record that match given conditions, order by primary key
|
||||||
|
func (db *DB) First(out interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take return a record that match given conditions, the order will depend on the database implementation
|
||||||
|
func (db *DB) Take(out interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last find last record that match given conditions, order by primary key
|
||||||
|
func (db *DB) Last(out interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find find records that match given conditions
|
||||||
|
func (db *DB) Find(out interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan scan value to a struct
|
||||||
|
|
||||||
|
func (db *DB) Row() *sql.Row {
|
||||||
|
// TODO
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Rows() (*sql.Rows, error) {
|
||||||
|
// TODO
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Scan(dest interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) ScanRows(rows *sql.Rows, result interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create insert the value into database
|
||||||
|
func (db *DB) Create(value interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save update value in database, if the value doesn't have primary key, will insert it
|
||||||
|
func (db *DB) Save(value interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
|
||||||
|
func (db *DB) Update(column string, value interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
|
||||||
|
func (db *DB) Updates(values interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) UpdateColumn(attrs ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) UpdateColumns(values interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) FirstOrCreate(out interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) FirstOrInit(out interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
|
||||||
|
func (db *DB) Delete(value interface{}, where ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Related(value interface{}, foreignKeys ...string) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {
|
||||||
|
panicked := true
|
||||||
|
tx := db.Begin(opts...)
|
||||||
|
defer func() {
|
||||||
|
// Make sure to rollback when panic, Block error or Commit error
|
||||||
|
if panicked || err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = fc(tx)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
err = tx.Commit().Error
|
||||||
|
}
|
||||||
|
|
||||||
|
panicked = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Begin(opts ...*sql.TxOptions) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Commit() (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Rollback() (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Exec(sql string, values ...interface{}) (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Association(column string) *Association {
|
||||||
|
return nil
|
||||||
|
}
|
62
gorm.go
62
gorm.go
|
@ -1,8 +1,10 @@
|
||||||
package gorm
|
package gorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jinzhu/gorm/clause"
|
||||||
"github.com/jinzhu/gorm/logger"
|
"github.com/jinzhu/gorm/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,9 +40,69 @@ type Model struct {
|
||||||
// Dialector GORM database dialector
|
// Dialector GORM database dialector
|
||||||
type Dialector interface {
|
type Dialector interface {
|
||||||
Migrator() Migrator
|
Migrator() Migrator
|
||||||
|
BindVar(stmt Statement, v interface{}) string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result
|
||||||
|
type Result struct {
|
||||||
|
Error error
|
||||||
|
RowsAffected int64
|
||||||
|
Statement *Statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// DB GORM DB definition
|
// DB GORM DB definition
|
||||||
type DB struct {
|
type DB struct {
|
||||||
*Config
|
*Config
|
||||||
|
Dialector
|
||||||
|
Result
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set store value with key into current db instance's context
|
||||||
|
func (db *DB) Set(key string, value interface{}) *DB {
|
||||||
|
tx := db.getInstance()
|
||||||
|
tx.Statement.Settings.Store(key, value)
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get get value with key from current db instance's context
|
||||||
|
func (db *DB) Get(key string) (interface{}, bool) {
|
||||||
|
if db.Statement != nil {
|
||||||
|
return db.Statement.Settings.Load(key)
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
return &DB{
|
||||||
|
Config: db.Config,
|
||||||
|
Dialector: db.Dialector,
|
||||||
|
Context: context.Background(),
|
||||||
|
Result: Result{
|
||||||
|
Statement: &Statement{DB: db, Clauses: map[string][]clause.Interface{}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug start debug mode
|
||||||
|
func (db *DB) Debug() (tx *DB) {
|
||||||
|
tx = db.getInstance()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
ModelType reflect.Type
|
||||||
|
Table string
|
||||||
|
PrioritizedPrimaryField *Field
|
||||||
|
PrimaryFields []*Field
|
||||||
|
Fields []*Field
|
||||||
|
FieldsByName map[string]*Field
|
||||||
|
FieldsByDBName map[string]*Field
|
||||||
|
Relationships Relationships
|
||||||
|
}
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
Name string
|
||||||
|
DBName string
|
||||||
|
DataType reflect.Type
|
||||||
|
DBDataType string
|
||||||
|
Tag reflect.StructTag
|
||||||
|
TagSettings map[string]string
|
||||||
|
PrimaryKey bool
|
||||||
|
AutoIncrement bool
|
||||||
|
Creatable bool
|
||||||
|
Updatable bool
|
||||||
|
Nullable bool
|
||||||
|
Unique bool
|
||||||
|
Precision int
|
||||||
|
Size int
|
||||||
|
HasDefaultValue bool
|
||||||
|
DefaultValue string
|
||||||
|
StructField reflect.StructField
|
||||||
|
Model *Model
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
// RelationshipType relationship type
|
||||||
|
type RelationshipType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
HasOneRel RelationshipType = "has_one" // HasOneRel has one relationship
|
||||||
|
HasManyRel RelationshipType = "has_many" // HasManyRel has many relationship
|
||||||
|
BelongsToRel RelationshipType = "belongs_to" // BelongsToRel belongs to relationship
|
||||||
|
Many2ManyRel RelationshipType = "many_to_many" // Many2ManyRel many to many relationship
|
||||||
|
)
|
||||||
|
|
||||||
|
type Relationships struct {
|
||||||
|
HasOne map[string]*Relationship
|
||||||
|
BelongsTo map[string]*Relationship
|
||||||
|
HasMany map[string]*Relationship
|
||||||
|
Many2Many map[string]*Relationship
|
||||||
|
}
|
||||||
|
|
||||||
|
type Relationship struct {
|
||||||
|
Type RelationshipType
|
||||||
|
ForeignKeys []*RelationField // self
|
||||||
|
AssociationForeignKeys []*RelationField // association
|
||||||
|
JoinTable *JoinTable
|
||||||
|
}
|
||||||
|
|
||||||
|
type RelationField struct {
|
||||||
|
*Field
|
||||||
|
PolymorphicField *Field
|
||||||
|
PolymorphicValue string
|
||||||
|
}
|
||||||
|
|
||||||
|
type JoinTable struct {
|
||||||
|
Table string
|
||||||
|
ForeignKeys []*RelationField
|
||||||
|
AssociationForeignKeys []*RelationField
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package gorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/jinzhu/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Statement statement
|
||||||
|
type Statement struct {
|
||||||
|
Dest interface{}
|
||||||
|
Table interface{}
|
||||||
|
Clauses map[string][]clause.Interface
|
||||||
|
Settings sync.Map
|
||||||
|
Context context.Context
|
||||||
|
DB *DB
|
||||||
|
StatementBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatementBuilder statement builder
|
||||||
|
type StatementBuilder struct {
|
||||||
|
SQL bytes.Buffer
|
||||||
|
Vars []interface{}
|
||||||
|
NamedVars []sql.NamedArg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write write string
|
||||||
|
func (stmt Statement) Write(sql ...string) (err error) {
|
||||||
|
for _, s := range sql {
|
||||||
|
_, err = stmt.SQL.WriteString(s)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteQuoted write quoted field
|
||||||
|
func (stmt Statement) WriteQuoted(field interface{}) (err error) {
|
||||||
|
_, err = stmt.SQL.WriteString(stmt.Quote(field))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write write string
|
||||||
|
func (stmt Statement) AddVar(vars ...interface{}) string {
|
||||||
|
var placeholders []string
|
||||||
|
for _, v := range vars {
|
||||||
|
if namedArg, ok := v.(sql.NamedArg); ok && len(namedArg.Name) > 0 {
|
||||||
|
stmt.NamedVars = append(stmt.NamedVars, namedArg)
|
||||||
|
placeholders = append(placeholders, "@"+namedArg.Name)
|
||||||
|
} else {
|
||||||
|
placeholders = append(placeholders, stmt.DB.Dialector.BindVar(stmt, v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(placeholders, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
Loading…
Reference in New Issue