mirror of
https://github.com/astaxie/beego.git
synced 2024-11-24 14:30:54 +00:00
refactor orm
This commit is contained in:
parent
d9c016ed98
commit
32da446eb1
@ -111,6 +111,9 @@ type DB struct {
|
|||||||
stmtDecorators *lru.Cache
|
stmtDecorators *lru.Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ dbQuerier = new(DB)
|
||||||
|
var _ txer = new(DB)
|
||||||
|
|
||||||
func (d *DB) Begin() (*sql.Tx, error) {
|
func (d *DB) Begin() (*sql.Tx, error) {
|
||||||
return d.DB.Begin()
|
return d.DB.Begin()
|
||||||
}
|
}
|
||||||
@ -220,6 +223,56 @@ func (d *DB) QueryRowContext(ctx context.Context, query string, args ...interfac
|
|||||||
return stmt.QueryRowContext(ctx, args)
|
return stmt.QueryRowContext(ctx, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TxDB struct {
|
||||||
|
tx *sql.Tx
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ dbQuerier = new(TxDB)
|
||||||
|
var _ txEnder = new(TxDB)
|
||||||
|
|
||||||
|
func (t *TxDB) Commit() error {
|
||||||
|
return t.tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) Rollback() error {
|
||||||
|
return t.tx.Rollback()
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ dbQuerier = new(TxDB)
|
||||||
|
var _ txEnder = new(TxDB)
|
||||||
|
|
||||||
|
func (t *TxDB) Prepare(query string) (*sql.Stmt, error) {
|
||||||
|
return t.PrepareContext(context.Background(),query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
|
||||||
|
return t.tx.PrepareContext(ctx, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return t.ExecContext(context.Background(), query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return t.tx.ExecContext(ctx, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||||
|
return t.QueryContext(context.Background(),query,args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
||||||
|
return t.tx.QueryContext(ctx, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) QueryRow(query string, args ...interface{}) *sql.Row {
|
||||||
|
return t.QueryRowContext(context.Background(),query,args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
|
||||||
|
return t.tx.QueryRowContext(ctx, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
type alias struct {
|
type alias struct {
|
||||||
Name string
|
Name string
|
||||||
Driver DriverType
|
Driver DriverType
|
||||||
|
307
pkg/orm/orm.go
307
pkg/orm/orm.go
@ -62,6 +62,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DebugQueries define the debug
|
// DebugQueries define the debug
|
||||||
@ -76,8 +78,7 @@ var (
|
|||||||
DefaultRowsLimit = -1
|
DefaultRowsLimit = -1
|
||||||
DefaultRelsDepth = 2
|
DefaultRelsDepth = 2
|
||||||
DefaultTimeLoc = time.Local
|
DefaultTimeLoc = time.Local
|
||||||
ErrTxHasBegan = errors.New("<Ormer.Begin> transaction already begin")
|
ErrTxDone = errors.New("<TxOrmer.Commit/Rollback> transaction already done")
|
||||||
ErrTxDone = errors.New("<Ormer.Commit/Rollback> transaction not begin")
|
|
||||||
ErrMultiRows = errors.New("<QuerySeter> return multi rows")
|
ErrMultiRows = errors.New("<QuerySeter> return multi rows")
|
||||||
ErrNoRows = errors.New("<QuerySeter> no row found")
|
ErrNoRows = errors.New("<QuerySeter> no row found")
|
||||||
ErrStmtClosed = errors.New("<QuerySeter> stmt already closed")
|
ErrStmtClosed = errors.New("<QuerySeter> stmt already closed")
|
||||||
@ -91,16 +92,16 @@ type Params map[string]interface{}
|
|||||||
// ParamsList stores paramslist
|
// ParamsList stores paramslist
|
||||||
type ParamsList []interface{}
|
type ParamsList []interface{}
|
||||||
|
|
||||||
type orm struct {
|
type ormBase struct {
|
||||||
alias *alias
|
alias *alias
|
||||||
db dbQuerier
|
db dbQuerier
|
||||||
isTx bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Ormer = new(orm)
|
var _ DQL = new(ormBase)
|
||||||
|
var _ DML = new(ormBase)
|
||||||
|
|
||||||
// get model info and model reflect value
|
// get model info and model reflect value
|
||||||
func (o *orm) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect.Value) {
|
func (o *ormBase) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect.Value) {
|
||||||
val := reflect.ValueOf(md)
|
val := reflect.ValueOf(md)
|
||||||
ind = reflect.Indirect(val)
|
ind = reflect.Indirect(val)
|
||||||
typ := ind.Type()
|
typ := ind.Type()
|
||||||
@ -115,7 +116,7 @@ func (o *orm) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get field info from model info by given field name
|
// get field info from model info by given field name
|
||||||
func (o *orm) getFieldInfo(mi *modelInfo, name string) *fieldInfo {
|
func (o *ormBase) getFieldInfo(mi *modelInfo, name string) *fieldInfo {
|
||||||
fi, ok := mi.fields.GetByAny(name)
|
fi, ok := mi.fields.GetByAny(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Errorf("<Ormer> cannot find field `%s` for model `%s`", name, mi.fullName))
|
panic(fmt.Errorf("<Ormer> cannot find field `%s` for model `%s`", name, mi.fullName))
|
||||||
@ -124,33 +125,42 @@ func (o *orm) getFieldInfo(mi *modelInfo, name string) *fieldInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read data to model
|
// read data to model
|
||||||
func (o *orm) Read(md interface{}, cols ...string) error {
|
func (o *ormBase) Read(md interface{}, cols ...string) error {
|
||||||
|
return o.ReadWithCtx(context.Background(), md, cols...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) ReadWithCtx(ctx context.Context, md interface{}, cols ...string) error {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
return o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, false)
|
return o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// read data to model, like Read(), but use "SELECT FOR UPDATE" form
|
// read data to model, like Read(), but use "SELECT FOR UPDATE" form
|
||||||
func (o *orm) ReadForUpdate(md interface{}, cols ...string) error {
|
func (o *ormBase) ReadForUpdate(md interface{}, cols ...string) error {
|
||||||
|
return o.ReadForUpdateWithCtx(context.Background(), md, cols...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols ...string) error {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
return o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, true)
|
return o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to read a row from the database, or insert one if it doesn't exist
|
// Try to read a row from the database, or insert one if it doesn't exist
|
||||||
func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) {
|
func (o *ormBase) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) {
|
||||||
|
return o.ReadOrCreateWithCtx(context.Background(), md, col1, cols...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error) {
|
||||||
cols = append([]string{col1}, cols...)
|
cols = append([]string{col1}, cols...)
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, false)
|
err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, false)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
// Create
|
// Create
|
||||||
id, err := o.Insert(md)
|
id, err := o.InsertWithCtx(ctx, md)
|
||||||
return (err == nil), id, err
|
return err == nil, id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, vid := int64(0), ind.FieldByIndex(mi.fields.pk.fieldIndex)
|
id, vid := int64(0), ind.FieldByIndex(mi.fields.pk.fieldIndex)
|
||||||
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
||||||
id = int64(vid.Uint())
|
id = int64(vid.Uint())
|
||||||
} else if mi.fields.pk.rel {
|
} else if mi.fields.pk.rel {
|
||||||
return o.ReadOrCreate(vid.Interface(), mi.fields.pk.relModelInfo.fields.pk.name)
|
return o.ReadOrCreateWithCtx(ctx, vid.Interface(), mi.fields.pk.relModelInfo.fields.pk.name)
|
||||||
} else {
|
} else {
|
||||||
id = vid.Int()
|
id = vid.Int()
|
||||||
}
|
}
|
||||||
@ -159,7 +169,10 @@ func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert model data to database
|
// insert model data to database
|
||||||
func (o *orm) Insert(md interface{}) (int64, error) {
|
func (o *ormBase) Insert(md interface{}) (int64, error) {
|
||||||
|
return o.InsertWithCtx(context.Background(), md)
|
||||||
|
}
|
||||||
|
func (o *ormBase) InsertWithCtx(ctx context.Context, md interface{}) (int64, error) {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
id, err := o.alias.DbBaser.Insert(o.db, mi, ind, o.alias.TZ)
|
id, err := o.alias.DbBaser.Insert(o.db, mi, ind, o.alias.TZ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -172,7 +185,7 @@ func (o *orm) Insert(md interface{}) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set auto pk field
|
// set auto pk field
|
||||||
func (o *orm) setPk(mi *modelInfo, ind reflect.Value, id int64) {
|
func (o *ormBase) setPk(mi *modelInfo, ind reflect.Value, id int64) {
|
||||||
if mi.fields.pk.auto {
|
if mi.fields.pk.auto {
|
||||||
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
||||||
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(uint64(id))
|
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(uint64(id))
|
||||||
@ -183,7 +196,10 @@ func (o *orm) setPk(mi *modelInfo, ind reflect.Value, id int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert some models to database
|
// insert some models to database
|
||||||
func (o *orm) InsertMulti(bulk int, mds interface{}) (int64, error) {
|
func (o *ormBase) InsertMulti(bulk int, mds interface{}) (int64, error) {
|
||||||
|
return o.InsertMultiWithCtx(context.Background(), bulk, mds)
|
||||||
|
}
|
||||||
|
func (o *ormBase) InsertMultiWithCtx(ctx context.Context, bulk int, mds interface{}) (int64, error) {
|
||||||
var cnt int64
|
var cnt int64
|
||||||
|
|
||||||
sind := reflect.Indirect(reflect.ValueOf(mds))
|
sind := reflect.Indirect(reflect.ValueOf(mds))
|
||||||
@ -218,7 +234,10 @@ func (o *orm) InsertMulti(bulk int, mds interface{}) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertOrUpdate data to database
|
// InsertOrUpdate data to database
|
||||||
func (o *orm) InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error) {
|
func (o *ormBase) InsertOrUpdate(md interface{}, colConflictAndArgs ...string) (int64, error) {
|
||||||
|
return o.InsertOrUpdateWithCtx(context.Background(), md, colConflictAndArgs...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error) {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
id, err := o.alias.DbBaser.InsertOrUpdate(o.db, mi, ind, o.alias, colConflitAndArgs...)
|
id, err := o.alias.DbBaser.InsertOrUpdate(o.db, mi, ind, o.alias, colConflitAndArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -232,14 +251,20 @@ func (o *orm) InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64
|
|||||||
|
|
||||||
// update model to database.
|
// update model to database.
|
||||||
// cols set the columns those want to update.
|
// cols set the columns those want to update.
|
||||||
func (o *orm) Update(md interface{}, cols ...string) (int64, error) {
|
func (o *ormBase) Update(md interface{}, cols ...string) (int64, error) {
|
||||||
|
return o.UpdateWithCtx(context.Background(), md, cols...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) UpdateWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
return o.alias.DbBaser.Update(o.db, mi, ind, o.alias.TZ, cols)
|
return o.alias.DbBaser.Update(o.db, mi, ind, o.alias.TZ, cols)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete model in database
|
// delete model in database
|
||||||
// cols shows the delete conditions values read from. default is pk
|
// cols shows the delete conditions values read from. default is pk
|
||||||
func (o *orm) Delete(md interface{}, cols ...string) (int64, error) {
|
func (o *ormBase) Delete(md interface{}, cols ...string) (int64, error) {
|
||||||
|
return o.DeleteWithCtx(context.Background(), md, cols...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) DeleteWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
num, err := o.alias.DbBaser.Delete(o.db, mi, ind, o.alias.TZ, cols)
|
num, err := o.alias.DbBaser.Delete(o.db, mi, ind, o.alias.TZ, cols)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -252,7 +277,10 @@ func (o *orm) Delete(md interface{}, cols ...string) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create a models to models queryer
|
// create a models to models queryer
|
||||||
func (o *orm) QueryM2M(md interface{}, name string) QueryM2Mer {
|
func (o *ormBase) QueryM2M(md interface{}, name string) QueryM2Mer {
|
||||||
|
return o.QueryM2MWithCtx(context.Background(), md, name)
|
||||||
|
}
|
||||||
|
func (o *ormBase) QueryM2MWithCtx(ctx context.Context, md interface{}, name string) QueryM2Mer {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
fi := o.getFieldInfo(mi, name)
|
fi := o.getFieldInfo(mi, name)
|
||||||
|
|
||||||
@ -274,7 +302,10 @@ func (o *orm) QueryM2M(md interface{}, name string) QueryM2Mer {
|
|||||||
// for _,tag := range post.Tags{...}
|
// for _,tag := range post.Tags{...}
|
||||||
//
|
//
|
||||||
// make sure the relation is defined in model struct tags.
|
// make sure the relation is defined in model struct tags.
|
||||||
func (o *orm) LoadRelated(md interface{}, name string, args ...interface{}) (int64, error) {
|
func (o *ormBase) LoadRelated(md interface{}, name string, args ...interface{}) (int64, error) {
|
||||||
|
return o.LoadRelatedWithCtx(context.Background(), md, name, args...)
|
||||||
|
}
|
||||||
|
func (o *ormBase) LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...interface{}) (int64, error) {
|
||||||
_, fi, ind, qseter := o.queryRelated(md, name)
|
_, fi, ind, qseter := o.queryRelated(md, name)
|
||||||
|
|
||||||
qs := qseter.(*querySet)
|
qs := qseter.(*querySet)
|
||||||
@ -341,14 +372,17 @@ func (o *orm) LoadRelated(md interface{}, name string, args ...interface{}) (int
|
|||||||
// qs := orm.QueryRelated(post,"Tag")
|
// qs := orm.QueryRelated(post,"Tag")
|
||||||
// qs.All(&[]*Tag{})
|
// qs.All(&[]*Tag{})
|
||||||
//
|
//
|
||||||
func (o *orm) QueryRelated(md interface{}, name string) QuerySeter {
|
func (o *ormBase) QueryRelated(md interface{}, name string) QuerySeter {
|
||||||
|
return o.QueryRelatedWithCtx(context.Background(), md, name)
|
||||||
|
}
|
||||||
|
func (o *ormBase) QueryRelatedWithCtx(ctx context.Context, md interface{}, name string) QuerySeter {
|
||||||
// is this api needed ?
|
// is this api needed ?
|
||||||
_, _, _, qs := o.queryRelated(md, name)
|
_, _, _, qs := o.queryRelated(md, name)
|
||||||
return qs
|
return qs
|
||||||
}
|
}
|
||||||
|
|
||||||
// get QuerySeter for related models to md model
|
// get QuerySeter for related models to md model
|
||||||
func (o *orm) queryRelated(md interface{}, name string) (*modelInfo, *fieldInfo, reflect.Value, QuerySeter) {
|
func (o *ormBase) queryRelated(md interface{}, name string) (*modelInfo, *fieldInfo, reflect.Value, QuerySeter) {
|
||||||
mi, ind := o.getMiInd(md, true)
|
mi, ind := o.getMiInd(md, true)
|
||||||
fi := o.getFieldInfo(mi, name)
|
fi := o.getFieldInfo(mi, name)
|
||||||
|
|
||||||
@ -380,7 +414,7 @@ func (o *orm) queryRelated(md interface{}, name string) (*modelInfo, *fieldInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get reverse relation QuerySeter
|
// get reverse relation QuerySeter
|
||||||
func (o *orm) getReverseQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
func (o *ormBase) getReverseQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
||||||
switch fi.fieldType {
|
switch fi.fieldType {
|
||||||
case RelReverseOne, RelReverseMany:
|
case RelReverseOne, RelReverseMany:
|
||||||
default:
|
default:
|
||||||
@ -401,7 +435,7 @@ func (o *orm) getReverseQs(md interface{}, mi *modelInfo, fi *fieldInfo) *queryS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get relation QuerySeter
|
// get relation QuerySeter
|
||||||
func (o *orm) getRelQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
func (o *ormBase) getRelQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
||||||
switch fi.fieldType {
|
switch fi.fieldType {
|
||||||
case RelOneToOne, RelForeignKey, RelManyToMany:
|
case RelOneToOne, RelForeignKey, RelManyToMany:
|
||||||
default:
|
default:
|
||||||
@ -423,7 +457,10 @@ func (o *orm) getRelQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
|||||||
// return a QuerySeter for table operations.
|
// return a QuerySeter for table operations.
|
||||||
// table name can be string or struct.
|
// table name can be string or struct.
|
||||||
// e.g. QueryTable("user"), QueryTable(&user{}) or QueryTable((*User)(nil)),
|
// e.g. QueryTable("user"), QueryTable(&user{}) or QueryTable((*User)(nil)),
|
||||||
func (o *orm) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) {
|
func (o *ormBase) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) {
|
||||||
|
return o.QueryTableWithCtx(context.Background(), ptrStructOrTableName)
|
||||||
|
}
|
||||||
|
func (o *ormBase) QueryTableWithCtx(ctx context.Context, ptrStructOrTableName interface{}) (qs QuerySeter) {
|
||||||
var name string
|
var name string
|
||||||
if table, ok := ptrStructOrTableName.(string); ok {
|
if table, ok := ptrStructOrTableName.(string); ok {
|
||||||
name = nameStrategyMap[defaultNameStrategy](table)
|
name = nameStrategyMap[defaultNameStrategy](table)
|
||||||
@ -442,11 +479,136 @@ func (o *orm) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch to another registered database driver by given name.
|
// return a raw query seter for raw sql string.
|
||||||
func (o *orm) Using(name string) error {
|
func (o *ormBase) Raw(query string, args ...interface{}) RawSeter {
|
||||||
if o.isTx {
|
return o.RawWithCtx(context.Background(), query, args...)
|
||||||
panic(fmt.Errorf("<Ormer.Using> transaction has been start, cannot change db"))
|
}
|
||||||
|
func (o *ormBase) RawWithCtx(ctx context.Context, query string, args ...interface{}) RawSeter {
|
||||||
|
return newRawSet(o, query, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return current using database Driver
|
||||||
|
func (o *ormBase) Driver() Driver {
|
||||||
|
return driver(o.alias.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return sql.DBStats for current database
|
||||||
|
func (o *ormBase) DBStats() *sql.DBStats {
|
||||||
|
if o.alias != nil && o.alias.DB != nil {
|
||||||
|
stats := o.alias.DB.DB.Stats()
|
||||||
|
return &stats
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type orm struct {
|
||||||
|
ormBase
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Ormer = new(orm)
|
||||||
|
|
||||||
|
func (o *orm) Begin() (TxOrmer, error) {
|
||||||
|
return o.BeginWithCtx(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) BeginWithCtx(ctx context.Context) (TxOrmer, error) {
|
||||||
|
return o.BeginWithCtxAndOpts(ctx, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) BeginWithOpts(opts *sql.TxOptions) (TxOrmer, error) {
|
||||||
|
return o.BeginWithCtxAndOpts(context.Background(), opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) BeginWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions) (TxOrmer, error) {
|
||||||
|
tx, err := o.db.(txer).BeginTx(ctx, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_txOrm := &txOrm{
|
||||||
|
ormBase: ormBase{
|
||||||
|
alias: o.alias,
|
||||||
|
db: &TxDB{tx: tx},
|
||||||
|
},
|
||||||
|
isClosed: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
var taskTxOrm TxOrmer = _txOrm
|
||||||
|
return taskTxOrm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) DoTx(task func(txOrm TxOrmer) error) error {
|
||||||
|
return o.DoTxWithCtx(context.Background(), task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) DoTxWithCtx(ctx context.Context, task func(txOrm TxOrmer) error) error {
|
||||||
|
return o.DoTxWithCtxAndOpts(ctx, nil, task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) DoTxWithOpts(opts *sql.TxOptions, task func(txOrm TxOrmer) error) error {
|
||||||
|
return o.DoTxWithCtxAndOpts(context.Background(), opts, task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) DoTxWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions, task func(txOrm TxOrmer) error) error {
|
||||||
|
_txOrm, err := o.BeginWithCtxAndOpts(ctx, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
panicked := true
|
||||||
|
defer func() {
|
||||||
|
if panicked || err != nil {
|
||||||
|
e := _txOrm.Rollback()
|
||||||
|
logs.Error("rollback transaction failed: %v", e)
|
||||||
|
} else {
|
||||||
|
e := _txOrm.Commit()
|
||||||
|
logs.Error("commit transaction failed: %v", e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var taskTxOrm = _txOrm
|
||||||
|
err = task(taskTxOrm)
|
||||||
|
panicked = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type txOrm struct {
|
||||||
|
ormBase
|
||||||
|
isClosed bool
|
||||||
|
closeMutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ TxOrmer = new(txOrm)
|
||||||
|
|
||||||
|
func (t *txOrm) Commit() error {
|
||||||
|
t.closeMutex.Lock()
|
||||||
|
defer t.closeMutex.Unlock()
|
||||||
|
|
||||||
|
if t.isClosed {
|
||||||
|
return ErrTxDone
|
||||||
|
}
|
||||||
|
t.isClosed = true
|
||||||
|
|
||||||
|
return t.db.(txEnder).Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *txOrm) Rollback() error {
|
||||||
|
t.closeMutex.Lock()
|
||||||
|
defer t.closeMutex.Unlock()
|
||||||
|
|
||||||
|
if t.isClosed {
|
||||||
|
return ErrTxDone
|
||||||
|
}
|
||||||
|
t.isClosed = true
|
||||||
|
|
||||||
|
return t.db.(txEnder).Rollback()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOrm create new orm
|
||||||
|
func NewOrm() Ormer {
|
||||||
|
BootStrap() // execute only once
|
||||||
|
|
||||||
|
o := new(orm)
|
||||||
|
name := `default`
|
||||||
if al, ok := dataBaseCache.get(name); ok {
|
if al, ok := dataBaseCache.get(name); ok {
|
||||||
o.alias = al
|
o.alias = al
|
||||||
if Debug {
|
if Debug {
|
||||||
@ -455,92 +617,9 @@ func (o *orm) Using(name string) error {
|
|||||||
o.db = al.DB
|
o.db = al.DB
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("<Ormer.Using> unknown db alias name `%s`", name)
|
panic(fmt.Errorf("<Ormer.Using> unknown db alias name `%s`", name))
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// begin transaction
|
|
||||||
func (o *orm) Begin() error {
|
|
||||||
return o.BeginTx(context.Background(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *orm) BeginTx(ctx context.Context, opts *sql.TxOptions) error {
|
|
||||||
if o.isTx {
|
|
||||||
return ErrTxHasBegan
|
|
||||||
}
|
|
||||||
var tx *sql.Tx
|
|
||||||
tx, err := o.db.(txer).BeginTx(ctx, opts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
o.isTx = true
|
|
||||||
if Debug {
|
|
||||||
o.db.(*dbQueryLog).SetDB(tx)
|
|
||||||
} else {
|
|
||||||
o.db = tx
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// commit transaction
|
|
||||||
func (o *orm) Commit() error {
|
|
||||||
if !o.isTx {
|
|
||||||
return ErrTxDone
|
|
||||||
}
|
|
||||||
err := o.db.(txEnder).Commit()
|
|
||||||
if err == nil {
|
|
||||||
o.isTx = false
|
|
||||||
o.Using(o.alias.Name)
|
|
||||||
} else if err == sql.ErrTxDone {
|
|
||||||
return ErrTxDone
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// rollback transaction
|
|
||||||
func (o *orm) Rollback() error {
|
|
||||||
if !o.isTx {
|
|
||||||
return ErrTxDone
|
|
||||||
}
|
|
||||||
err := o.db.(txEnder).Rollback()
|
|
||||||
if err == nil {
|
|
||||||
o.isTx = false
|
|
||||||
o.Using(o.alias.Name)
|
|
||||||
} else if err == sql.ErrTxDone {
|
|
||||||
return ErrTxDone
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a raw query seter for raw sql string.
|
|
||||||
func (o *orm) Raw(query string, args ...interface{}) RawSeter {
|
|
||||||
return newRawSet(o, query, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// return current using database Driver
|
|
||||||
func (o *orm) Driver() Driver {
|
|
||||||
return driver(o.alias.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// return sql.DBStats for current database
|
|
||||||
func (o *orm) DBStats() *sql.DBStats {
|
|
||||||
if o.alias != nil && o.alias.DB != nil {
|
|
||||||
stats := o.alias.DB.DB.Stats()
|
|
||||||
return &stats
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewOrm create new orm
|
|
||||||
func NewOrm() Ormer {
|
|
||||||
BootStrap() // execute only once
|
|
||||||
|
|
||||||
o := new(orm)
|
|
||||||
err := o.Using("default")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
// an insert queryer struct
|
// an insert queryer struct
|
||||||
type insertSet struct {
|
type insertSet struct {
|
||||||
mi *modelInfo
|
mi *modelInfo
|
||||||
orm *orm
|
orm *ormBase
|
||||||
stmt stmtQuerier
|
stmt stmtQuerier
|
||||||
closed bool
|
closed bool
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ func (o *insertSet) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create new insert queryer.
|
// create new insert queryer.
|
||||||
func newInsertSet(orm *orm, mi *modelInfo) (Inserter, error) {
|
func newInsertSet(orm *ormBase, mi *modelInfo) (Inserter, error) {
|
||||||
bi := new(insertSet)
|
bi := new(insertSet)
|
||||||
bi.orm = orm
|
bi.orm = orm
|
||||||
bi.mi = mi
|
bi.mi = mi
|
||||||
|
@ -129,7 +129,7 @@ func (o *queryM2M) Count() (int64, error) {
|
|||||||
var _ QueryM2Mer = new(queryM2M)
|
var _ QueryM2Mer = new(queryM2M)
|
||||||
|
|
||||||
// create new M2M queryer.
|
// create new M2M queryer.
|
||||||
func newQueryM2M(md interface{}, o *orm, mi *modelInfo, fi *fieldInfo, ind reflect.Value) QueryM2Mer {
|
func newQueryM2M(md interface{}, o *ormBase, mi *modelInfo, fi *fieldInfo, ind reflect.Value) QueryM2Mer {
|
||||||
qm2m := new(queryM2M)
|
qm2m := new(queryM2M)
|
||||||
qm2m.md = md
|
qm2m.md = md
|
||||||
qm2m.mi = mi
|
qm2m.mi = mi
|
||||||
|
@ -72,7 +72,7 @@ type querySet struct {
|
|||||||
orders []string
|
orders []string
|
||||||
distinct bool
|
distinct bool
|
||||||
forupdate bool
|
forupdate bool
|
||||||
orm *orm
|
orm *ormBase
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
forContext bool
|
forContext bool
|
||||||
}
|
}
|
||||||
@ -292,7 +292,7 @@ func (o querySet) WithContext(ctx context.Context) QuerySeter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create new QuerySeter.
|
// create new QuerySeter.
|
||||||
func newQuerySet(orm *orm, mi *modelInfo) QuerySeter {
|
func newQuerySet(orm *ormBase, mi *modelInfo) QuerySeter {
|
||||||
o := new(querySet)
|
o := new(querySet)
|
||||||
o.mi = mi
|
o.mi = mi
|
||||||
o.orm = orm
|
o.orm = orm
|
||||||
|
@ -63,7 +63,7 @@ func newRawPreparer(rs *rawSet) (RawPreparer, error) {
|
|||||||
type rawSet struct {
|
type rawSet struct {
|
||||||
query string
|
query string
|
||||||
args []interface{}
|
args []interface{}
|
||||||
orm *orm
|
orm *ormBase
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ RawSeter = new(rawSet)
|
var _ RawSeter = new(rawSet)
|
||||||
@ -858,7 +858,7 @@ func (o *rawSet) Prepare() (RawPreparer, error) {
|
|||||||
return newRawPreparer(o)
|
return newRawPreparer(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRawSet(orm *orm, query string, args []interface{}) RawSeter {
|
func newRawSet(orm *ormBase, query string, args []interface{}) RawSeter {
|
||||||
o := new(rawSet)
|
o := new(rawSet)
|
||||||
o.query = query
|
o.query = query
|
||||||
o.args = args
|
o.args = args
|
||||||
|
@ -2026,24 +2026,24 @@ func TestTransaction(t *testing.T) {
|
|||||||
// this test worked when database support transaction
|
// this test worked when database support transaction
|
||||||
|
|
||||||
o := NewOrm()
|
o := NewOrm()
|
||||||
err := o.Begin()
|
to, err := o.Begin()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
var names = []string{"1", "2", "3"}
|
var names = []string{"1", "2", "3"}
|
||||||
|
|
||||||
var tag Tag
|
var tag Tag
|
||||||
tag.Name = names[0]
|
tag.Name = names[0]
|
||||||
id, err := o.Insert(&tag)
|
id, err := to.Insert(&tag)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(id > 0, true))
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
|
|
||||||
num, err := o.QueryTable("tag").Filter("name", "golang").Update(Params{"name": names[1]})
|
num, err := to.QueryTable("tag").Filter("name", "golang").Update(Params{"name": names[1]})
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(num, 1))
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case IsMysql || IsSqlite:
|
case IsMysql || IsSqlite:
|
||||||
res, err := o.Raw("INSERT INTO tag (name) VALUES (?)", names[2]).Exec()
|
res, err := to.Raw("INSERT INTO tag (name) VALUES (?)", names[2]).Exec()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
id, err = res.LastInsertId()
|
id, err = res.LastInsertId()
|
||||||
@ -2052,22 +2052,22 @@ func TestTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = o.Rollback()
|
err = to.Rollback()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
num, err = o.QueryTable("tag").Filter("name__in", names).Count()
|
num, err = o.QueryTable("tag").Filter("name__in", names).Count()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(num, 0))
|
throwFail(t, AssertIs(num, 0))
|
||||||
|
|
||||||
err = o.Begin()
|
to, err = o.Begin()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
tag.Name = "commit"
|
tag.Name = "commit"
|
||||||
id, err = o.Insert(&tag)
|
id, err = to.Insert(&tag)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(id > 0, true))
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
|
|
||||||
o.Commit()
|
to.Commit()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
num, err = o.QueryTable("tag").Filter("name", "commit").Delete()
|
num, err = o.QueryTable("tag").Filter("name", "commit").Delete()
|
||||||
@ -2086,15 +2086,15 @@ func TestTransactionIsolationLevel(t *testing.T) {
|
|||||||
o2 := NewOrm()
|
o2 := NewOrm()
|
||||||
|
|
||||||
// start two transaction with isolation level repeatable read
|
// start two transaction with isolation level repeatable read
|
||||||
err := o1.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
to1, err := o1.BeginWithCtxAndOpts(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
err = o2.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
to2, err := o2.BeginWithCtxAndOpts(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
// o1 insert tag
|
// o1 insert tag
|
||||||
var tag Tag
|
var tag Tag
|
||||||
tag.Name = "test-transaction"
|
tag.Name = "test-transaction"
|
||||||
id, err := o1.Insert(&tag)
|
id, err := to1.Insert(&tag)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(id > 0, true))
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
|
|
||||||
@ -2104,15 +2104,15 @@ func TestTransactionIsolationLevel(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(num, 0))
|
throwFail(t, AssertIs(num, 0))
|
||||||
|
|
||||||
// o1 commit
|
// o1 commit
|
||||||
o1.Commit()
|
to1.Commit()
|
||||||
|
|
||||||
// o2 query tag table, still no result
|
// o2 query tag table, still no result
|
||||||
num, err = o2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
num, err = to2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(num, 0))
|
throwFail(t, AssertIs(num, 0))
|
||||||
|
|
||||||
// o2 commit and query tag table, get the result
|
// o2 commit and query tag table, get the result
|
||||||
o2.Commit()
|
to2.Commit()
|
||||||
num, err = o2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
num, err = o2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(num, 1))
|
throwFail(t, AssertIs(num, 1))
|
||||||
@ -2125,14 +2125,14 @@ func TestTransactionIsolationLevel(t *testing.T) {
|
|||||||
func TestBeginTxWithContextCanceled(t *testing.T) {
|
func TestBeginTxWithContextCanceled(t *testing.T) {
|
||||||
o := NewOrm()
|
o := NewOrm()
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
o.BeginTx(ctx, nil)
|
to, _ := o.BeginWithCtx(ctx)
|
||||||
id, err := o.Insert(&Tag{Name: "test-context"})
|
id, err := to.Insert(&Tag{Name: "test-context"})
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(id > 0, true))
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
|
|
||||||
// cancel the context before commit to make it error
|
// cancel the context before commit to make it error
|
||||||
cancel()
|
cancel()
|
||||||
err = o.Commit()
|
err = to.Commit()
|
||||||
throwFail(t, AssertIs(err, context.Canceled))
|
throwFail(t, AssertIs(err, context.Canceled))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
162
pkg/orm/types.go
162
pkg/orm/types.go
@ -35,35 +35,43 @@ type Fielder interface {
|
|||||||
RawValue() interface{}
|
RawValue() interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ormer define the orm interface
|
type TxBeginner interface {
|
||||||
type Ormer interface {
|
//self control transaction
|
||||||
// read data to model
|
Begin() (TxOrmer, error)
|
||||||
// for example:
|
BeginWithCtx(ctx context.Context) (TxOrmer, error)
|
||||||
// this will find User by Id field
|
BeginWithOpts(opts *sql.TxOptions) (TxOrmer, error)
|
||||||
// u = &User{Id: user.Id}
|
BeginWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions) (TxOrmer, error)
|
||||||
// err = Ormer.Read(u)
|
|
||||||
// this will find User by UserName field
|
//closure control transaction
|
||||||
// u = &User{UserName: "astaxie", Password: "pass"}
|
DoTx(task func(txOrm TxOrmer) error) error
|
||||||
// err = Ormer.Read(u, "UserName")
|
DoTxWithCtx(ctx context.Context, task func(txOrm TxOrmer) error) error
|
||||||
Read(md interface{}, cols ...string) error
|
DoTxWithOpts(opts *sql.TxOptions, task func(txOrm TxOrmer) error) error
|
||||||
// Like Read(), but with "FOR UPDATE" clause, useful in transaction.
|
DoTxWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions, task func(txOrm TxOrmer) error) error
|
||||||
// Some databases are not support this feature.
|
}
|
||||||
ReadForUpdate(md interface{}, cols ...string) error
|
|
||||||
// Try to read a row from the database, or insert one if it doesn't exist
|
type TxCommitter interface {
|
||||||
ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error)
|
Commit() error
|
||||||
|
Rollback() error
|
||||||
|
}
|
||||||
|
|
||||||
|
//Data Manipulation Language
|
||||||
|
type DML interface {
|
||||||
// insert model data to database
|
// insert model data to database
|
||||||
// for example:
|
// for example:
|
||||||
// user := new(User)
|
// user := new(User)
|
||||||
// id, err = Ormer.Insert(user)
|
// id, err = Ormer.Insert(user)
|
||||||
// user must be a pointer and Insert will set user's pk field
|
// user must be a pointer and Insert will set user's pk field
|
||||||
Insert(interface{}) (int64, error)
|
Insert(md interface{}) (int64, error)
|
||||||
|
InsertWithCtx(ctx context.Context, md interface{}) (int64, error)
|
||||||
// mysql:InsertOrUpdate(model) or InsertOrUpdate(model,"colu=colu+value")
|
// mysql:InsertOrUpdate(model) or InsertOrUpdate(model,"colu=colu+value")
|
||||||
// if colu type is integer : can use(+-*/), string : convert(colu,"value")
|
// if colu type is integer : can use(+-*/), string : convert(colu,"value")
|
||||||
// postgres: InsertOrUpdate(model,"conflictColumnName") or InsertOrUpdate(model,"conflictColumnName","colu=colu+value")
|
// postgres: InsertOrUpdate(model,"conflictColumnName") or InsertOrUpdate(model,"conflictColumnName","colu=colu+value")
|
||||||
// if colu type is integer : can use(+-*/), string : colu || "value"
|
// if colu type is integer : can use(+-*/), string : colu || "value"
|
||||||
InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error)
|
InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error)
|
||||||
|
InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error)
|
||||||
// insert some models to database
|
// insert some models to database
|
||||||
InsertMulti(bulk int, mds interface{}) (int64, error)
|
InsertMulti(bulk int, mds interface{}) (int64, error)
|
||||||
|
InsertMultiWithCtx(ctx context.Context, bulk int, mds interface{}) (int64, error)
|
||||||
// update model to database.
|
// update model to database.
|
||||||
// cols set the columns those want to update.
|
// cols set the columns those want to update.
|
||||||
// find model by Id(pk) field and update columns specified by fields, if cols is null then update all columns
|
// find model by Id(pk) field and update columns specified by fields, if cols is null then update all columns
|
||||||
@ -74,63 +82,93 @@ type Ormer interface {
|
|||||||
// user.Extra.Data = "orm"
|
// user.Extra.Data = "orm"
|
||||||
// num, err = Ormer.Update(&user, "Langs", "Extra")
|
// num, err = Ormer.Update(&user, "Langs", "Extra")
|
||||||
Update(md interface{}, cols ...string) (int64, error)
|
Update(md interface{}, cols ...string) (int64, error)
|
||||||
|
UpdateWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error)
|
||||||
// delete model in database
|
// delete model in database
|
||||||
Delete(md interface{}, cols ...string) (int64, error)
|
Delete(md interface{}, cols ...string) (int64, error)
|
||||||
|
DeleteWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error)
|
||||||
|
|
||||||
|
// return a raw query seter for raw sql string.
|
||||||
|
// for example:
|
||||||
|
// ormer.Raw("UPDATE `user` SET `user_name` = ? WHERE `user_name` = ?", "slene", "testing").Exec()
|
||||||
|
// // update user testing's name to slene
|
||||||
|
Raw(query string, args ...interface{}) RawSeter
|
||||||
|
RawWithCtx(ctx context.Context, query string, args ...interface{}) RawSeter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data Query Language
|
||||||
|
type DQL interface {
|
||||||
|
// read data to model
|
||||||
|
// for example:
|
||||||
|
// this will find User by Id field
|
||||||
|
// u = &User{Id: user.Id}
|
||||||
|
// err = Ormer.Read(u)
|
||||||
|
// this will find User by UserName field
|
||||||
|
// u = &User{UserName: "astaxie", Password: "pass"}
|
||||||
|
// err = Ormer.Read(u, "UserName")
|
||||||
|
Read(md interface{}, cols ...string) error
|
||||||
|
ReadWithCtx(ctx context.Context, md interface{}, cols ...string) error
|
||||||
|
|
||||||
|
// Like Read(), but with "FOR UPDATE" clause, useful in transaction.
|
||||||
|
// Some databases are not support this feature.
|
||||||
|
ReadForUpdate( md interface{}, cols ...string) error
|
||||||
|
ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols ...string) error
|
||||||
|
|
||||||
|
// Try to read a row from the database, or insert one if it doesn't exist
|
||||||
|
ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error)
|
||||||
|
ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error)
|
||||||
|
|
||||||
// load related models to md model.
|
// load related models to md model.
|
||||||
// args are limit, offset int and order string.
|
// args are limit, offset int and order string.
|
||||||
//
|
//
|
||||||
// example:
|
// example:
|
||||||
// Ormer.LoadRelated(post,"Tags")
|
// Ormer.LoadRelated(post,"Tags")
|
||||||
// for _,tag := range post.Tags{...}
|
// for _,tag := range post.Tags{...}
|
||||||
//args[0] bool true useDefaultRelsDepth ; false depth 0
|
// args[0] bool true useDefaultRelsDepth ; false depth 0
|
||||||
//args[0] int loadRelationDepth
|
// args[0] int loadRelationDepth
|
||||||
//args[1] int limit default limit 1000
|
// args[1] int limit default limit 1000
|
||||||
//args[2] int offset default offset 0
|
// args[2] int offset default offset 0
|
||||||
//args[3] string order for example : "-Id"
|
// args[3] string order for example : "-Id"
|
||||||
// make sure the relation is defined in model struct tags.
|
// make sure the relation is defined in model struct tags.
|
||||||
LoadRelated(md interface{}, name string, args ...interface{}) (int64, error)
|
LoadRelated( md interface{}, name string, args ...interface{}) (int64, error)
|
||||||
|
LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...interface{}) (int64, error)
|
||||||
|
|
||||||
// create a models to models queryer
|
// create a models to models queryer
|
||||||
// for example:
|
// for example:
|
||||||
// post := Post{Id: 4}
|
// post := Post{Id: 4}
|
||||||
// m2m := Ormer.QueryM2M(&post, "Tags")
|
// m2m := Ormer.QueryM2M(&post, "Tags")
|
||||||
QueryM2M(md interface{}, name string) QueryM2Mer
|
QueryM2M( md interface{}, name string) QueryM2Mer
|
||||||
|
QueryM2MWithCtx(ctx context.Context, md interface{}, name string) QueryM2Mer
|
||||||
|
|
||||||
// return a QuerySeter for table operations.
|
// return a QuerySeter for table operations.
|
||||||
// table name can be string or struct.
|
// table name can be string or struct.
|
||||||
// e.g. QueryTable("user"), QueryTable(&user{}) or QueryTable((*User)(nil)),
|
// e.g. QueryTable("user"), QueryTable(&user{}) or QueryTable((*User)(nil)),
|
||||||
QueryTable(ptrStructOrTableName interface{}) QuerySeter
|
QueryTable(ptrStructOrTableName interface{}) QuerySeter
|
||||||
|
QueryTableWithCtx(ctx context.Context, ptrStructOrTableName interface{}) QuerySeter
|
||||||
|
|
||||||
// switch to another registered database driver by given name.
|
// switch to another registered database driver by given name.
|
||||||
Using(name string) error
|
// Using(name string) error
|
||||||
// begin transaction
|
|
||||||
// for example:
|
|
||||||
// o := NewOrm()
|
|
||||||
// err := o.Begin()
|
|
||||||
// ...
|
|
||||||
// err = o.Rollback()
|
|
||||||
Begin() error
|
|
||||||
// begin transaction with provided context and option
|
|
||||||
// the provided context is used until the transaction is committed or rolled back.
|
|
||||||
// if the context is canceled, the transaction will be rolled back.
|
|
||||||
// the provided TxOptions is optional and may be nil if defaults should be used.
|
|
||||||
// if a non-default isolation level is used that the driver doesn't support, an error will be returned.
|
|
||||||
// for example:
|
|
||||||
// o := NewOrm()
|
|
||||||
// err := o.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
|
||||||
// ...
|
|
||||||
// err = o.Rollback()
|
|
||||||
BeginTx(ctx context.Context, opts *sql.TxOptions) error
|
|
||||||
// commit transaction
|
|
||||||
Commit() error
|
|
||||||
// rollback transaction
|
|
||||||
Rollback() error
|
|
||||||
// return a raw query seter for raw sql string.
|
|
||||||
// for example:
|
|
||||||
// ormer.Raw("UPDATE `user` SET `user_name` = ? WHERE `user_name` = ?", "slene", "testing").Exec()
|
|
||||||
// // update user testing's name to slene
|
|
||||||
Raw(query string, args ...interface{}) RawSeter
|
|
||||||
Driver() Driver
|
|
||||||
DBStats() *sql.DBStats
|
DBStats() *sql.DBStats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DriverGetter interface {
|
||||||
|
Driver() Driver
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ormer interface {
|
||||||
|
DQL
|
||||||
|
DML
|
||||||
|
DriverGetter
|
||||||
|
TxBeginner
|
||||||
|
}
|
||||||
|
|
||||||
|
type TxOrmer interface {
|
||||||
|
DQL
|
||||||
|
DML
|
||||||
|
DriverGetter
|
||||||
|
TxCommitter
|
||||||
|
}
|
||||||
|
|
||||||
// Inserter insert prepared statement
|
// Inserter insert prepared statement
|
||||||
type Inserter interface {
|
type Inserter interface {
|
||||||
Insert(interface{}) (int64, error)
|
Insert(interface{}) (int64, error)
|
||||||
@ -229,7 +267,7 @@ type QuerySeter interface {
|
|||||||
// }) // user slene's name will change to slene2
|
// }) // user slene's name will change to slene2
|
||||||
Update(values Params) (int64, error)
|
Update(values Params) (int64, error)
|
||||||
// delete from table
|
// delete from table
|
||||||
//for example:
|
// for example:
|
||||||
// num ,err = qs.Filter("user_name__in", "testing1", "testing2").Delete()
|
// num ,err = qs.Filter("user_name__in", "testing1", "testing2").Delete()
|
||||||
// //delete two user who's name is testing1 or testing2
|
// //delete two user who's name is testing1 or testing2
|
||||||
Delete() (int64, error)
|
Delete() (int64, error)
|
||||||
@ -314,8 +352,8 @@ type QueryM2Mer interface {
|
|||||||
// remove models following the origin model relationship
|
// remove models following the origin model relationship
|
||||||
// only delete rows from m2m table
|
// only delete rows from m2m table
|
||||||
// for example:
|
// for example:
|
||||||
//tag3 := &Tag{Id:5,Name: "TestTag3"}
|
// tag3 := &Tag{Id:5,Name: "TestTag3"}
|
||||||
//num, err = m2m.Remove(tag3)
|
// num, err = m2m.Remove(tag3)
|
||||||
Remove(...interface{}) (int64, error)
|
Remove(...interface{}) (int64, error)
|
||||||
// check model is existed in relationship of origin model
|
// check model is existed in relationship of origin model
|
||||||
Exist(interface{}) bool
|
Exist(interface{}) bool
|
||||||
@ -337,10 +375,10 @@ type RawPreparer interface {
|
|||||||
// sql := fmt.Sprintf("SELECT %sid%s,%sname%s FROM %suser%s WHERE id = ?",Q,Q,Q,Q,Q,Q)
|
// sql := fmt.Sprintf("SELECT %sid%s,%sname%s FROM %suser%s WHERE id = ?",Q,Q,Q,Q,Q,Q)
|
||||||
// rs := Ormer.Raw(sql, 1)
|
// rs := Ormer.Raw(sql, 1)
|
||||||
type RawSeter interface {
|
type RawSeter interface {
|
||||||
//execute sql and get result
|
// execute sql and get result
|
||||||
Exec() (sql.Result, error)
|
Exec() (sql.Result, error)
|
||||||
//query data and map to container
|
// query data and map to container
|
||||||
//for example:
|
// for example:
|
||||||
// var name string
|
// var name string
|
||||||
// var id int
|
// var id int
|
||||||
// rs.QueryRow(&id,&name) // id==2 name=="slene"
|
// rs.QueryRow(&id,&name) // id==2 name=="slene"
|
||||||
@ -396,11 +434,11 @@ type RawSeter interface {
|
|||||||
type stmtQuerier interface {
|
type stmtQuerier interface {
|
||||||
Close() error
|
Close() error
|
||||||
Exec(args ...interface{}) (sql.Result, error)
|
Exec(args ...interface{}) (sql.Result, error)
|
||||||
//ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error)
|
// ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error)
|
||||||
Query(args ...interface{}) (*sql.Rows, error)
|
Query(args ...interface{}) (*sql.Rows, error)
|
||||||
//QueryContext(args ...interface{}) (*sql.Rows, error)
|
// QueryContext(args ...interface{}) (*sql.Rows, error)
|
||||||
QueryRow(args ...interface{}) *sql.Row
|
QueryRow(args ...interface{}) *sql.Row
|
||||||
//QueryRowContext(ctx context.Context, args ...interface{}) *sql.Row
|
// QueryRowContext(ctx context.Context, args ...interface{}) *sql.Row
|
||||||
}
|
}
|
||||||
|
|
||||||
// db querier
|
// db querier
|
||||||
|
Loading…
Reference in New Issue
Block a user