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)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										130
									
								
								pkg/orm/types.go
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								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,8 +82,41 @@ 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. | ||||||
| 	// | 	// | ||||||
| @ -89,48 +130,45 @@ type Ormer interface { | |||||||
| 	// 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) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user