mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 14:40:57 +00:00
orm support complete m2m operation api / auto load related api
This commit is contained in:
parent
e11c40eee4
commit
d043ebcdd3
@ -151,7 +151,11 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mi.model != nil {
|
if mi.model != nil {
|
||||||
for _, names := range getTableUnique(mi.addrField) {
|
allnames := getTableUnique(mi.addrField)
|
||||||
|
if !mi.manual && len(mi.uniques) > 0 {
|
||||||
|
allnames = append(allnames, mi.uniques)
|
||||||
|
}
|
||||||
|
for _, names := range allnames {
|
||||||
cols := make([]string, 0, len(names))
|
cols := make([]string, 0, len(names))
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if fi, ok := mi.fields.GetByAny(name); ok && fi.dbcol {
|
if fi, ok := mi.fields.GetByAny(name); ok && fi.dbcol {
|
||||||
|
42
orm/db.go
42
orm/db.go
@ -52,7 +52,6 @@ type dbBase struct {
|
|||||||
var _ dbBaser = new(dbBase)
|
var _ dbBaser = new(dbBase)
|
||||||
|
|
||||||
func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, tz *time.Location) (columns []string, values []interface{}, err error) {
|
func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, tz *time.Location) (columns []string, values []interface{}, err error) {
|
||||||
_, pkValue, _ := getExistPk(mi, ind)
|
|
||||||
for _, column := range cols {
|
for _, column := range cols {
|
||||||
var fi *fieldInfo
|
var fi *fieldInfo
|
||||||
if fi, _ = mi.fields.GetByAny(column); fi != nil {
|
if fi, _ = mi.fields.GetByAny(column); fi != nil {
|
||||||
@ -63,9 +62,20 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string,
|
|||||||
if fi.dbcol == false || fi.auto && skipAuto {
|
if fi.dbcol == false || fi.auto && skipAuto {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
value, err := d.collectFieldValue(mi, fi, ind, insert, tz)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
columns = append(columns, column)
|
||||||
|
values = append(values, value)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Value, insert bool, tz *time.Location) (interface{}, error) {
|
||||||
var value interface{}
|
var value interface{}
|
||||||
if fi.pk {
|
if fi.pk {
|
||||||
value = pkValue
|
_, value, _ = getExistPk(mi, ind)
|
||||||
} else {
|
} else {
|
||||||
field := ind.Field(fi.fieldIndex)
|
field := ind.Field(fi.fieldIndex)
|
||||||
if fi.isFielder {
|
if fi.isFielder {
|
||||||
@ -111,7 +121,7 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fi.null == false && value == nil {
|
if fi.null == false && value == nil {
|
||||||
return nil, nil, errors.New(fmt.Sprintf("field `%s` cannot be NULL", fi.fullName))
|
return nil, errors.New(fmt.Sprintf("field `%s` cannot be NULL", fi.fullName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,10 +145,7 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
columns = append(columns, column)
|
return value, nil
|
||||||
values = append(values, value)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string, error) {
|
func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string, error) {
|
||||||
@ -250,6 +257,10 @@ func (d *dbBase) Insert(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return d.InsertValue(q, mi, names, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dbBase) InsertValue(q dbQuerier, mi *modelInfo, names []string, values []interface{}) (int64, error) {
|
||||||
Q := d.ins.TableQuote()
|
Q := d.ins.TableQuote()
|
||||||
|
|
||||||
marks := make([]string, len(names))
|
marks := make([]string, len(names))
|
||||||
@ -653,10 +664,12 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
|||||||
trefs = refs[len(tCols):]
|
trefs = refs[len(tCols):]
|
||||||
|
|
||||||
for _, tbl := range tables.tables {
|
for _, tbl := range tables.tables {
|
||||||
|
// loop selected tables
|
||||||
if tbl.sel {
|
if tbl.sel {
|
||||||
last := mind
|
last := mind
|
||||||
names := ""
|
names := ""
|
||||||
mmi := mi
|
mmi := mi
|
||||||
|
// loop cascade models
|
||||||
for _, name := range tbl.names {
|
for _, name := range tbl.names {
|
||||||
names += name
|
names += name
|
||||||
if val, ok := cacheV[names]; ok {
|
if val, ok := cacheV[names]; ok {
|
||||||
@ -665,8 +678,10 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
|||||||
} else {
|
} else {
|
||||||
fi := mmi.fields.GetByName(name)
|
fi := mmi.fields.GetByName(name)
|
||||||
lastm := mmi
|
lastm := mmi
|
||||||
mmi := fi.relModelInfo
|
mmi = fi.relModelInfo
|
||||||
field := reflect.Indirect(last.Field(fi.fieldIndex))
|
field := last
|
||||||
|
if last.Kind() != reflect.Invalid {
|
||||||
|
field = reflect.Indirect(last.Field(fi.fieldIndex))
|
||||||
if field.IsValid() {
|
if field.IsValid() {
|
||||||
d.setColsValues(mmi, &field, mmi.fields.dbcols, trefs[:len(mmi.fields.dbcols)], tz)
|
d.setColsValues(mmi, &field, mmi.fields.dbcols, trefs[:len(mmi.fields.dbcols)], tz)
|
||||||
for _, fi := range mmi.fields.fieldsReverse {
|
for _, fi := range mmi.fields.fieldsReverse {
|
||||||
@ -679,15 +694,16 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cacheV[names] = &field
|
|
||||||
cacheM[names] = mmi
|
|
||||||
last = field
|
last = field
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
cacheV[names] = &field
|
||||||
|
cacheM[names] = mmi
|
||||||
|
}
|
||||||
|
}
|
||||||
trefs = trefs[len(mmi.fields.dbcols):]
|
trefs = trefs[len(mmi.fields.dbcols):]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if one {
|
if one {
|
||||||
ind.Set(mind)
|
ind.Set(mind)
|
||||||
|
107
orm/db_tables.go
107
orm/db_tables.go
@ -100,22 +100,29 @@ func (t *dbTables) parseRelated(rels []string, depth int) {
|
|||||||
exs = strings.Split(s, ExprSep)
|
exs = strings.Split(s, ExprSep)
|
||||||
names = make([]string, 0, len(exs))
|
names = make([]string, 0, len(exs))
|
||||||
mmi = t.mi
|
mmi = t.mi
|
||||||
cansel = true
|
cancel = true
|
||||||
jtl *dbTable
|
jtl *dbTable
|
||||||
)
|
)
|
||||||
|
|
||||||
|
inner := true
|
||||||
|
|
||||||
for _, ex := range exs {
|
for _, ex := range exs {
|
||||||
if fi, ok := mmi.fields.GetByAny(ex); ok && fi.rel && fi.fieldType != RelManyToMany {
|
if fi, ok := mmi.fields.GetByAny(ex); ok && fi.rel && fi.fieldType != RelManyToMany {
|
||||||
names = append(names, fi.name)
|
names = append(names, fi.name)
|
||||||
mmi = fi.relModelInfo
|
mmi = fi.relModelInfo
|
||||||
|
|
||||||
jt := t.set(names, mmi, fi, fi.null == false)
|
if fi.null {
|
||||||
|
inner = false
|
||||||
|
}
|
||||||
|
|
||||||
|
jt := t.set(names, mmi, fi, inner)
|
||||||
jt.jtl = jtl
|
jt.jtl = jtl
|
||||||
|
|
||||||
if fi.reverse {
|
if fi.reverse {
|
||||||
cansel = false
|
cancel = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if cansel {
|
if cancel {
|
||||||
jt.sel = depth > 0
|
jt.sel = depth > 0
|
||||||
|
|
||||||
if i < relsNum {
|
if i < relsNum {
|
||||||
@ -178,9 +185,8 @@ func (t *dbTables) getJoinSql() (join string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string, info *fieldInfo, success bool) {
|
func (t *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string, info *fieldInfo, success bool) {
|
||||||
var (
|
var (
|
||||||
ffi *fieldInfo
|
|
||||||
jtl *dbTable
|
jtl *dbTable
|
||||||
mmi = mi
|
mmi = mi
|
||||||
)
|
)
|
||||||
@ -188,15 +194,16 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
|
|||||||
num := len(exprs) - 1
|
num := len(exprs) - 1
|
||||||
names := make([]string, 0)
|
names := make([]string, 0)
|
||||||
|
|
||||||
for i, ex := range exprs {
|
inner := true
|
||||||
exist := false
|
|
||||||
|
for i, ex := range exprs {
|
||||||
|
|
||||||
check:
|
|
||||||
fi, ok := mmi.fields.GetByAny(ex)
|
fi, ok := mmi.fields.GetByAny(ex)
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
|
|
||||||
if num != i {
|
isRel := fi.rel || fi.reverse
|
||||||
|
|
||||||
names = append(names, fi.name)
|
names = append(names, fi.name)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -207,54 +214,47 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
|
|||||||
}
|
}
|
||||||
case fi.reverse:
|
case fi.reverse:
|
||||||
mmi = fi.reverseFieldInfo.mi
|
mmi = fi.reverseFieldInfo.mi
|
||||||
if fi.reverseFieldInfo.fieldType == RelManyToMany {
|
|
||||||
mmi = fi.reverseFieldInfo.relThroughModelInfo
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jt, _ := d.add(names, mmi, fi, fi.null == false)
|
if isRel && (fi.mi.isThrough == false || num != i) {
|
||||||
|
if fi.null {
|
||||||
|
inner = false
|
||||||
|
}
|
||||||
|
|
||||||
|
jt, _ := t.add(names, mmi, fi, inner)
|
||||||
jt.jtl = jtl
|
jt.jtl = jtl
|
||||||
jtl = jt
|
jtl = jt
|
||||||
|
|
||||||
if fi.rel && fi.fieldType == RelManyToMany {
|
|
||||||
ex = fi.relModelInfo.name
|
|
||||||
goto check
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi.reverse && fi.reverseFieldInfo.fieldType == RelManyToMany {
|
if num == i {
|
||||||
ex = fi.reverseFieldInfo.mi.name
|
if i == 0 || jtl == nil {
|
||||||
goto check
|
|
||||||
}
|
|
||||||
|
|
||||||
exist = true
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if ffi == nil {
|
|
||||||
index = "T0"
|
index = "T0"
|
||||||
} else {
|
} else {
|
||||||
index = jtl.index
|
index = jtl.index
|
||||||
}
|
}
|
||||||
|
|
||||||
info = fi
|
info = fi
|
||||||
if jtl != nil {
|
|
||||||
name = jtl.name + ExprSep + fi.name
|
if jtl == nil {
|
||||||
} else {
|
|
||||||
name = fi.name
|
name = fi.name
|
||||||
|
} else {
|
||||||
|
name = jtl.name + ExprSep + fi.name
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fi.fieldType {
|
switch {
|
||||||
case RelManyToMany, RelReverseMany:
|
case fi.rel:
|
||||||
default:
|
|
||||||
exist = true
|
case fi.reverse:
|
||||||
|
switch fi.reverseFieldInfo.fieldType {
|
||||||
|
case RelOneToOne, RelForeignKey:
|
||||||
|
index = jtl.index
|
||||||
|
info = fi.reverseFieldInfo.mi.fields.pk
|
||||||
|
name = info.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi = fi
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
if exist == false {
|
|
||||||
index = ""
|
index = ""
|
||||||
name = ""
|
name = ""
|
||||||
info = nil
|
info = nil
|
||||||
@ -267,16 +267,15 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (where string, params []interface{}) {
|
func (t *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (where string, params []interface{}) {
|
||||||
if cond == nil || cond.IsEmpty() {
|
if cond == nil || cond.IsEmpty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Q := d.base.TableQuote()
|
Q := t.base.TableQuote()
|
||||||
|
|
||||||
mi := d.mi
|
mi := t.mi
|
||||||
|
|
||||||
// outFor:
|
|
||||||
for i, p := range cond.params {
|
for i, p := range cond.params {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
if p.isOr {
|
if p.isOr {
|
||||||
@ -289,7 +288,7 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
|
|||||||
where += "NOT "
|
where += "NOT "
|
||||||
}
|
}
|
||||||
if p.isCond {
|
if p.isCond {
|
||||||
w, ps := d.getCondSql(p.cond, true, tz)
|
w, ps := t.getCondSql(p.cond, true, tz)
|
||||||
if w != "" {
|
if w != "" {
|
||||||
w = fmt.Sprintf("( %s) ", w)
|
w = fmt.Sprintf("( %s) ", w)
|
||||||
}
|
}
|
||||||
@ -305,7 +304,7 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
|
|||||||
exprs = exprs[:num]
|
exprs = exprs[:num]
|
||||||
}
|
}
|
||||||
|
|
||||||
index, _, fi, suc := d.parseExprs(mi, exprs)
|
index, _, fi, suc := t.parseExprs(mi, exprs)
|
||||||
if suc == false {
|
if suc == false {
|
||||||
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(p.exprs, ExprSep)))
|
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(p.exprs, ExprSep)))
|
||||||
}
|
}
|
||||||
@ -314,10 +313,10 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
|
|||||||
operator = "exact"
|
operator = "exact"
|
||||||
}
|
}
|
||||||
|
|
||||||
operSql, args := d.base.GenerateOperatorSql(mi, fi, operator, p.args, tz)
|
operSql, args := t.base.GenerateOperatorSql(mi, fi, operator, p.args, tz)
|
||||||
|
|
||||||
leftCol := fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q)
|
leftCol := fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q)
|
||||||
d.base.GenerateOperatorLeftCol(fi, operator, &leftCol)
|
t.base.GenerateOperatorLeftCol(fi, operator, &leftCol)
|
||||||
|
|
||||||
where += fmt.Sprintf("%s %s ", leftCol, operSql)
|
where += fmt.Sprintf("%s %s ", leftCol, operSql)
|
||||||
params = append(params, args...)
|
params = append(params, args...)
|
||||||
@ -332,12 +331,12 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbTables) getOrderSql(orders []string) (orderSql string) {
|
func (t *dbTables) getOrderSql(orders []string) (orderSql string) {
|
||||||
if len(orders) == 0 {
|
if len(orders) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Q := d.base.TableQuote()
|
Q := t.base.TableQuote()
|
||||||
|
|
||||||
orderSqls := make([]string, 0, len(orders))
|
orderSqls := make([]string, 0, len(orders))
|
||||||
for _, order := range orders {
|
for _, order := range orders {
|
||||||
@ -348,7 +347,7 @@ func (d *dbTables) getOrderSql(orders []string) (orderSql string) {
|
|||||||
}
|
}
|
||||||
exprs := strings.Split(order, ExprSep)
|
exprs := strings.Split(order, ExprSep)
|
||||||
|
|
||||||
index, _, fi, suc := d.parseExprs(d.mi, exprs)
|
index, _, fi, suc := t.parseExprs(t.mi, exprs)
|
||||||
if suc == false {
|
if suc == false {
|
||||||
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
|
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
|
||||||
}
|
}
|
||||||
@ -360,14 +359,14 @@ func (d *dbTables) getOrderSql(orders []string) (orderSql string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbTables) getLimitSql(mi *modelInfo, offset int64, limit int64) (limits string) {
|
func (t *dbTables) getLimitSql(mi *modelInfo, offset int64, limit int64) (limits string) {
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
limit = int64(DefaultRowsLimit)
|
limit = int64(DefaultRowsLimit)
|
||||||
}
|
}
|
||||||
if limit < 0 {
|
if limit < 0 {
|
||||||
// no limit
|
// no limit
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
maxLimit := d.base.MaxLimit()
|
maxLimit := t.base.MaxLimit()
|
||||||
if maxLimit == 0 {
|
if maxLimit == 0 {
|
||||||
limits = fmt.Sprintf("OFFSET %d", offset)
|
limits = fmt.Sprintf("OFFSET %d", offset)
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,7 +121,6 @@ func bootStrap() {
|
|||||||
err = errors.New(msg)
|
err = errors.New(msg)
|
||||||
goto end
|
goto end
|
||||||
}
|
}
|
||||||
err = nil
|
|
||||||
} else {
|
} else {
|
||||||
i := newM2MModelInfo(mi, mii)
|
i := newM2MModelInfo(mi, mii)
|
||||||
if fi.relTable != "" {
|
if fi.relTable != "" {
|
||||||
@ -135,6 +134,8 @@ func bootStrap() {
|
|||||||
fi.relTable = i.table
|
fi.relTable = i.table
|
||||||
fi.relThroughModelInfo = i
|
fi.relThroughModelInfo = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fi.relThroughModelInfo.isThrough = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,6 +153,7 @@ func bootStrap() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if inModel == false {
|
if inModel == false {
|
||||||
rmi := fi.relModelInfo
|
rmi := fi.relModelInfo
|
||||||
ffi := new(fieldInfo)
|
ffi := new(fieldInfo)
|
||||||
@ -185,9 +187,34 @@ func bootStrap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
models = modelCache.all()
|
||||||
for _, mi := range models {
|
for _, mi := range models {
|
||||||
if fields, ok := mi.fields.fieldsByType[RelReverseOne]; ok {
|
for _, fi := range mi.fields.fieldsRel {
|
||||||
for _, fi := range fields {
|
switch fi.fieldType {
|
||||||
|
case RelManyToMany:
|
||||||
|
for _, ffi := range fi.relThroughModelInfo.fields.fieldsRel {
|
||||||
|
switch ffi.fieldType {
|
||||||
|
case RelOneToOne, RelForeignKey:
|
||||||
|
if ffi.relModelInfo == fi.relModelInfo {
|
||||||
|
fi.reverseFieldInfoTwo = ffi
|
||||||
|
}
|
||||||
|
if ffi.relModelInfo == mi {
|
||||||
|
fi.reverseField = ffi.name
|
||||||
|
fi.reverseFieldInfo = ffi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.reverseFieldInfoTwo == nil {
|
||||||
|
err = fmt.Errorf("can not find m2m field for m2m model `%s`, ensure your m2m model defined correct",
|
||||||
|
fi.relThroughModelInfo.fullName)
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, fi := range mi.fields.fieldsReverse {
|
||||||
|
switch fi.fieldType {
|
||||||
|
case RelReverseOne:
|
||||||
found := false
|
found := false
|
||||||
mForA:
|
mForA:
|
||||||
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelOneToOne] {
|
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelOneToOne] {
|
||||||
@ -195,6 +222,9 @@ func bootStrap() {
|
|||||||
found = true
|
found = true
|
||||||
fi.reverseField = ffi.name
|
fi.reverseField = ffi.name
|
||||||
fi.reverseFieldInfo = ffi
|
fi.reverseFieldInfo = ffi
|
||||||
|
|
||||||
|
ffi.reverseField = fi.name
|
||||||
|
ffi.reverseFieldInfo = fi
|
||||||
break mForA
|
break mForA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,10 +232,7 @@ func bootStrap() {
|
|||||||
err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
|
err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
|
||||||
goto end
|
goto end
|
||||||
}
|
}
|
||||||
}
|
case RelReverseMany:
|
||||||
}
|
|
||||||
if fields, ok := mi.fields.fieldsByType[RelReverseMany]; ok {
|
|
||||||
for _, fi := range fields {
|
|
||||||
found := false
|
found := false
|
||||||
mForB:
|
mForB:
|
||||||
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelForeignKey] {
|
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelForeignKey] {
|
||||||
@ -213,6 +240,10 @@ func bootStrap() {
|
|||||||
found = true
|
found = true
|
||||||
fi.reverseField = ffi.name
|
fi.reverseField = ffi.name
|
||||||
fi.reverseFieldInfo = ffi
|
fi.reverseFieldInfo = ffi
|
||||||
|
|
||||||
|
ffi.reverseField = fi.name
|
||||||
|
ffi.reverseFieldInfo = fi
|
||||||
|
|
||||||
break mForB
|
break mForB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,14 +252,20 @@ func bootStrap() {
|
|||||||
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelManyToMany] {
|
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelManyToMany] {
|
||||||
if ffi.relModelInfo == mi {
|
if ffi.relModelInfo == mi {
|
||||||
found = true
|
found = true
|
||||||
fi.reverseField = ffi.name
|
|
||||||
fi.reverseFieldInfo = ffi
|
fi.reverseField = ffi.reverseFieldInfoTwo.name
|
||||||
|
fi.reverseFieldInfo = ffi.reverseFieldInfoTwo
|
||||||
|
fi.relThroughModelInfo = ffi.relThroughModelInfo
|
||||||
|
fi.reverseFieldInfoTwo = ffi.reverseFieldInfo
|
||||||
|
fi.reverseFieldInfoM2M = ffi
|
||||||
|
ffi.reverseFieldInfoM2M = fi
|
||||||
|
|
||||||
break mForC
|
break mForC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found == false {
|
if found == false {
|
||||||
err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
|
err = fmt.Errorf("reverse field for `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
|
||||||
goto end
|
goto end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,8 @@ type fieldInfo struct {
|
|||||||
reverse bool
|
reverse bool
|
||||||
reverseField string
|
reverseField string
|
||||||
reverseFieldInfo *fieldInfo
|
reverseFieldInfo *fieldInfo
|
||||||
|
reverseFieldInfoTwo *fieldInfo
|
||||||
|
reverseFieldInfoM2M *fieldInfo
|
||||||
relTable string
|
relTable string
|
||||||
relThrough string
|
relThrough string
|
||||||
relThroughModelInfo *modelInfo
|
relThroughModelInfo *modelInfo
|
||||||
|
@ -16,6 +16,8 @@ type modelInfo struct {
|
|||||||
fields *fields
|
fields *fields
|
||||||
manual bool
|
manual bool
|
||||||
addrField reflect.Value
|
addrField reflect.Value
|
||||||
|
uniques []string
|
||||||
|
isThrough bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newModelInfo(val reflect.Value) (info *modelInfo) {
|
func newModelInfo(val reflect.Value) (info *modelInfo) {
|
||||||
@ -118,5 +120,7 @@ func newM2MModelInfo(m1, m2 *modelInfo) (info *modelInfo) {
|
|||||||
info.fields.Add(f1)
|
info.fields.Add(f1)
|
||||||
info.fields.Add(f2)
|
info.fields.Add(f2)
|
||||||
info.fields.pk = fa
|
info.fields.pk = fa
|
||||||
|
|
||||||
|
info.uniques = []string{f1.column, f2.column}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ type Profile struct {
|
|||||||
Age int16
|
Age int16
|
||||||
Money float64
|
Money float64
|
||||||
User *User `orm:"reverse(one)" json:"-"`
|
User *User `orm:"reverse(one)" json:"-"`
|
||||||
|
BestPost *Post `orm:"rel(one);null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Profile) TableName() string {
|
func (u *Profile) TableName() string {
|
||||||
@ -138,6 +139,7 @@ func NewPost() *Post {
|
|||||||
type Tag struct {
|
type Tag struct {
|
||||||
Id int
|
Id int
|
||||||
Name string `orm:"size(30)"`
|
Name string `orm:"size(30)"`
|
||||||
|
BestPost *Post `orm:"rel(one);null"`
|
||||||
Posts []*Post `orm:"reverse(many)" json:"-"`
|
Posts []*Post `orm:"reverse(many)" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
164
orm/orm.go
164
orm/orm.go
@ -18,7 +18,7 @@ var (
|
|||||||
Debug = false
|
Debug = false
|
||||||
DebugLog = NewLog(os.Stderr)
|
DebugLog = NewLog(os.Stderr)
|
||||||
DefaultRowsLimit = 1000
|
DefaultRowsLimit = 1000
|
||||||
DefaultRelsDepth = 5
|
DefaultRelsDepth = 2
|
||||||
DefaultTimeLoc = time.Local
|
DefaultTimeLoc = time.Local
|
||||||
ErrTxHasBegan = errors.New("<Ormer.Begin> transaction already begin")
|
ErrTxHasBegan = errors.New("<Ormer.Begin> transaction already begin")
|
||||||
ErrTxDone = errors.New("<Ormer.Commit/Rollback> transaction not begin")
|
ErrTxDone = errors.New("<Ormer.Commit/Rollback> transaction not begin")
|
||||||
@ -53,6 +53,14 @@ func (o *orm) getMiInd(md interface{}) (mi *modelInfo, ind reflect.Value) {
|
|||||||
panic(fmt.Errorf("<Ormer> table: `%s` not found, maybe not RegisterModel", name))
|
panic(fmt.Errorf("<Ormer> table: `%s` not found, maybe not RegisterModel", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *orm) getFieldInfo(mi *modelInfo, name string) *fieldInfo {
|
||||||
|
fi, ok := mi.fields.GetByAny(name)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Errorf("<Ormer> cannot find field `%s` for model `%s`", name, mi.fullName))
|
||||||
|
}
|
||||||
|
return fi
|
||||||
|
}
|
||||||
|
|
||||||
func (o *orm) Read(md interface{}, cols ...string) error {
|
func (o *orm) Read(md interface{}, cols ...string) error {
|
||||||
mi, ind := o.getMiInd(md)
|
mi, ind := o.getMiInd(md)
|
||||||
err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols)
|
err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols)
|
||||||
@ -107,22 +115,152 @@ func (o *orm) Delete(md interface{}) (int64, error) {
|
|||||||
return num, nil
|
return num, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *orm) M2mAdd(md interface{}, name string, mds ...interface{}) (int64, error) {
|
func (o *orm) QueryM2M(md interface{}, name string) QueryM2Mer {
|
||||||
// TODO
|
mi, ind := o.getMiInd(md)
|
||||||
panic(ErrNotImplement)
|
fi := o.getFieldInfo(mi, name)
|
||||||
return 0, nil
|
|
||||||
|
if fi.fieldType != RelManyToMany {
|
||||||
|
panic(fmt.Errorf("<Ormer.QueryM2M> name `%s` for model `%s` is not a m2m field", fi.name, mi.fullName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *orm) M2mDel(md interface{}, name string, mds ...interface{}) (int64, error) {
|
return newQueryM2M(md, o, mi, fi, ind)
|
||||||
// TODO
|
|
||||||
panic(ErrNotImplement)
|
|
||||||
return 0, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *orm) LoadRel(md interface{}, name string) (int64, error) {
|
func (o *orm) LoadRelated(md interface{}, name string, args ...interface{}) (int64, error) {
|
||||||
// TODO
|
_, fi, ind, qseter := o.queryRelated(md, name)
|
||||||
panic(ErrNotImplement)
|
|
||||||
return 0, nil
|
qs := qseter.(*querySet)
|
||||||
|
|
||||||
|
var relDepth int
|
||||||
|
var limit, offset int64
|
||||||
|
var order string
|
||||||
|
for i, arg := range args {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
if v, ok := arg.(bool); ok {
|
||||||
|
if v {
|
||||||
|
relDepth = DefaultRelsDepth
|
||||||
|
}
|
||||||
|
} else if v, ok := arg.(int); ok {
|
||||||
|
relDepth = v
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
limit = ToInt64(arg)
|
||||||
|
case 2:
|
||||||
|
offset = ToInt64(arg)
|
||||||
|
case 3:
|
||||||
|
order, _ = arg.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fi.fieldType {
|
||||||
|
case RelOneToOne, RelForeignKey, RelReverseOne:
|
||||||
|
limit = 1
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
qs.limit = limit
|
||||||
|
qs.offset = offset
|
||||||
|
qs.relDepth = relDepth
|
||||||
|
|
||||||
|
if len(order) > 0 {
|
||||||
|
qs.orders = []string{order}
|
||||||
|
}
|
||||||
|
|
||||||
|
find := ind.Field(fi.fieldIndex)
|
||||||
|
|
||||||
|
var nums int64
|
||||||
|
var err error
|
||||||
|
switch fi.fieldType {
|
||||||
|
case RelOneToOne, RelForeignKey, RelReverseOne:
|
||||||
|
val := reflect.New(find.Type().Elem())
|
||||||
|
container := val.Interface()
|
||||||
|
err = qs.One(container)
|
||||||
|
if err == nil {
|
||||||
|
find.Set(val)
|
||||||
|
nums = 1
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
nums, err = qs.All(find.Addr().Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nums, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) QueryRelated(md interface{}, name string) QuerySeter {
|
||||||
|
// is this api needed ?
|
||||||
|
_, _, _, qs := o.queryRelated(md, name)
|
||||||
|
return qs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) queryRelated(md interface{}, name string) (*modelInfo, *fieldInfo, reflect.Value, QuerySeter) {
|
||||||
|
mi, ind := o.getMiInd(md)
|
||||||
|
fi := o.getFieldInfo(mi, name)
|
||||||
|
|
||||||
|
_, _, exist := getExistPk(mi, ind)
|
||||||
|
if exist == false {
|
||||||
|
panic(ErrMissPK)
|
||||||
|
}
|
||||||
|
|
||||||
|
var qs *querySet
|
||||||
|
|
||||||
|
switch fi.fieldType {
|
||||||
|
case RelOneToOne, RelForeignKey, RelManyToMany:
|
||||||
|
if !fi.inModel {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
qs = o.getRelQs(md, mi, fi)
|
||||||
|
case RelReverseOne, RelReverseMany:
|
||||||
|
if !fi.inModel {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
qs = o.getReverseQs(md, mi, fi)
|
||||||
|
}
|
||||||
|
|
||||||
|
if qs == nil {
|
||||||
|
panic(fmt.Errorf("<Ormer> name `%s` for model `%s` is not an available rel/reverse field"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return mi, fi, ind, qs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) getReverseQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
||||||
|
switch fi.fieldType {
|
||||||
|
case RelReverseOne, RelReverseMany:
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("<Ormer> name `%s` for model `%s` is not an available reverse field", fi.name, mi.fullName))
|
||||||
|
}
|
||||||
|
|
||||||
|
var q *querySet
|
||||||
|
|
||||||
|
if fi.fieldType == RelReverseMany && fi.reverseFieldInfo.mi.isThrough {
|
||||||
|
q = newQuerySet(o, fi.relModelInfo).(*querySet)
|
||||||
|
q.cond = NewCondition().And(fi.reverseFieldInfoM2M.column+ExprSep+fi.reverseFieldInfo.column, md)
|
||||||
|
} else {
|
||||||
|
q = newQuerySet(o, fi.reverseFieldInfo.mi).(*querySet)
|
||||||
|
q.cond = NewCondition().And(fi.reverseFieldInfo.column, md)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) getRelQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
|
||||||
|
switch fi.fieldType {
|
||||||
|
case RelOneToOne, RelForeignKey, RelManyToMany:
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("<Ormer> name `%s` for model `%s` is not an available rel field", fi.name, mi.fullName))
|
||||||
|
}
|
||||||
|
|
||||||
|
q := newQuerySet(o, fi.relModelInfo).(*querySet)
|
||||||
|
q.cond = NewCondition()
|
||||||
|
|
||||||
|
if fi.fieldType == RelManyToMany {
|
||||||
|
q.cond = q.cond.And(fi.reverseFieldInfoM2M.column+ExprSep+fi.reverseFieldInfo.column, md)
|
||||||
|
} else {
|
||||||
|
q.cond = q.cond.And(fi.reverseFieldInfo.column, md)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *orm) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) {
|
func (o *orm) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) {
|
||||||
|
111
orm/orm_querym2m.go
Normal file
111
orm/orm_querym2m.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package orm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type queryM2M struct {
|
||||||
|
md interface{}
|
||||||
|
mi *modelInfo
|
||||||
|
fi *fieldInfo
|
||||||
|
qs *querySet
|
||||||
|
ind reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *queryM2M) Add(mds ...interface{}) (int64, error) {
|
||||||
|
fi := o.fi
|
||||||
|
mi := fi.relThroughModelInfo
|
||||||
|
mfi := fi.reverseFieldInfo
|
||||||
|
rfi := fi.reverseFieldInfoTwo
|
||||||
|
|
||||||
|
orm := o.qs.orm
|
||||||
|
dbase := orm.alias.DbBaser
|
||||||
|
|
||||||
|
var models []interface{}
|
||||||
|
|
||||||
|
for _, md := range mds {
|
||||||
|
val := reflect.ValueOf(md)
|
||||||
|
if val.Kind() == reflect.Slice || val.Kind() == reflect.Array {
|
||||||
|
for i := 0; i < val.Len(); i++ {
|
||||||
|
v := val.Index(i)
|
||||||
|
if v.CanInterface() {
|
||||||
|
models = append(models, v.Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
models = append(models, md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, v1, exist := getExistPk(o.mi, o.ind)
|
||||||
|
if exist == false {
|
||||||
|
panic(ErrMissPK)
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []string{mfi.column, rfi.column}
|
||||||
|
|
||||||
|
var nums int64
|
||||||
|
for _, md := range models {
|
||||||
|
|
||||||
|
ind := reflect.Indirect(reflect.ValueOf(md))
|
||||||
|
|
||||||
|
var v2 interface{}
|
||||||
|
if ind.Kind() != reflect.Struct {
|
||||||
|
v2 = ind.Interface()
|
||||||
|
} else {
|
||||||
|
_, v2, exist = getExistPk(fi.relModelInfo, ind)
|
||||||
|
if exist == false {
|
||||||
|
panic(ErrMissPK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values := []interface{}{v1, v2}
|
||||||
|
_, err := dbase.InsertValue(orm.db, mi, names, values)
|
||||||
|
if err != nil {
|
||||||
|
return nums, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nums += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return nums, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *queryM2M) Remove(mds ...interface{}) (int64, error) {
|
||||||
|
fi := o.fi
|
||||||
|
qs := o.qs.Filter(fi.reverseFieldInfo.name, o.md)
|
||||||
|
|
||||||
|
nums, err := qs.Filter(fi.reverseFieldInfoTwo.name+ExprSep+"in", mds).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return nums, err
|
||||||
|
}
|
||||||
|
return nums, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *queryM2M) Exist(md interface{}) bool {
|
||||||
|
fi := o.fi
|
||||||
|
return o.qs.Filter(fi.reverseFieldInfo.name, o.md).
|
||||||
|
Filter(fi.reverseFieldInfoTwo.name, md).Exist()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *queryM2M) Clear() (int64, error) {
|
||||||
|
fi := o.fi
|
||||||
|
return o.qs.Filter(fi.reverseFieldInfo.name, o.md).Delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *queryM2M) Count() (int64, error) {
|
||||||
|
fi := o.fi
|
||||||
|
return o.qs.Filter(fi.reverseFieldInfo.name, o.md).Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ QueryM2Mer = new(queryM2M)
|
||||||
|
|
||||||
|
func newQueryM2M(md interface{}, o *orm, mi *modelInfo, fi *fieldInfo, ind reflect.Value) QueryM2Mer {
|
||||||
|
qm2m := new(queryM2M)
|
||||||
|
qm2m.md = md
|
||||||
|
qm2m.mi = mi
|
||||||
|
qm2m.fi = fi
|
||||||
|
qm2m.ind = ind
|
||||||
|
qm2m.qs = newQuerySet(o, fi.relThroughModelInfo).(*querySet)
|
||||||
|
return qm2m
|
||||||
|
}
|
394
orm/orm_test.go
394
orm/orm_test.go
@ -48,9 +48,9 @@ func ValuesCompare(is bool, a interface{}, args ...interface{}) (err error, ok b
|
|||||||
ok = is && ok || !is && !ok
|
ok = is && ok || !is && !ok
|
||||||
if !ok {
|
if !ok {
|
||||||
if is {
|
if is {
|
||||||
err = fmt.Errorf("expected: a == `%v`, get `%v`", b, a)
|
err = fmt.Errorf("expected: `%v`, get `%v`", b, a)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("expected: a != `%v`, get `%v`", b, a)
|
err = fmt.Errorf("expected: `%v`, get `%v`", b, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ func TestInsertTestData(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(id, 4))
|
throwFail(t, AssertIs(id, 4))
|
||||||
|
|
||||||
tags := []*Tag{
|
tags := []*Tag{
|
||||||
&Tag{Name: "golang"},
|
&Tag{Name: "golang", BestPost: &Post{Id: 2}},
|
||||||
&Tag{Name: "example"},
|
&Tag{Name: "example"},
|
||||||
&Tag{Name: "format"},
|
&Tag{Name: "format"},
|
||||||
&Tag{Name: "c++"},
|
&Tag{Name: "c++"},
|
||||||
@ -454,7 +454,13 @@ The program—and web server—godoc processes Go source files to extract docume
|
|||||||
id, err := dORM.Insert(post)
|
id, err := dORM.Insert(post)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(id > 0, true))
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
// dORM.M2mAdd(post, "tags", post.Tags)
|
|
||||||
|
num := len(post.Tags)
|
||||||
|
if num > 0 {
|
||||||
|
nums, err := dORM.QueryM2M(post, "tags").Add(post.Tags)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(nums, num))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
@ -590,6 +596,68 @@ func TestOperators(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(num, 2))
|
throwFail(t, AssertIs(num, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetCond(t *testing.T) {
|
||||||
|
cond := NewCondition()
|
||||||
|
cond1 := cond.And("profile__isnull", false).AndNot("status__in", 1).Or("profile__age__gt", 2000)
|
||||||
|
|
||||||
|
qs := dORM.QueryTable("user")
|
||||||
|
num, err := qs.SetCond(cond1).Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
cond2 := cond.AndCond(cond1).OrCond(cond.And("user_name", "slene"))
|
||||||
|
num, err = qs.SetCond(cond2).Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLimit(t *testing.T) {
|
||||||
|
var posts []*Post
|
||||||
|
qs := dORM.QueryTable("post")
|
||||||
|
num, err := qs.Limit(1).All(&posts)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = qs.Limit(-1).All(&posts)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 4))
|
||||||
|
|
||||||
|
num, err = qs.Limit(-1, 2).All(&posts)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 2))
|
||||||
|
|
||||||
|
num, err = qs.Limit(0, 2).All(&posts)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOffset(t *testing.T) {
|
||||||
|
var posts []*Post
|
||||||
|
qs := dORM.QueryTable("post")
|
||||||
|
num, err := qs.Limit(1).Offset(2).All(&posts)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = qs.Offset(2).All(&posts)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderBy(t *testing.T) {
|
||||||
|
qs := dORM.QueryTable("user")
|
||||||
|
num, err := qs.OrderBy("-status").Filter("user_name", "nobody").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = qs.OrderBy("status").Filter("user_name", "slene").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = qs.OrderBy("-profile__age").Filter("user_name", "astaxie").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
}
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
func TestAll(t *testing.T) {
|
||||||
var users []*User
|
var users []*User
|
||||||
qs := dORM.QueryTable("user")
|
qs := dORM.QueryTable("user")
|
||||||
@ -758,66 +826,292 @@ func TestRelatedSel(t *testing.T) {
|
|||||||
throwFailNow(t, AssertIs(posts[3].User.UserName, "nobody"))
|
throwFailNow(t, AssertIs(posts[3].User.UserName, "nobody"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetCond(t *testing.T) {
|
func TestReverseQuery(t *testing.T) {
|
||||||
cond := NewCondition()
|
var profile Profile
|
||||||
cond1 := cond.And("profile__isnull", false).AndNot("status__in", 1).Or("profile__age__gt", 2000)
|
err := dORM.QueryTable("user_profile").Filter("User", 3).One(&profile)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(profile.Age, 30))
|
||||||
|
|
||||||
qs := dORM.QueryTable("user")
|
profile = Profile{}
|
||||||
num, err := qs.SetCond(cond1).Count()
|
err = dORM.QueryTable("user_profile").Filter("User__UserName", "astaxie").One(&profile)
|
||||||
throwFail(t, err)
|
throwFailNow(t, err)
|
||||||
throwFail(t, AssertIs(num, 1))
|
throwFailNow(t, AssertIs(profile.Age, 30))
|
||||||
|
|
||||||
cond2 := cond.AndCond(cond1).OrCond(cond.And("user_name", "slene"))
|
var user User
|
||||||
num, err = qs.SetCond(cond2).Count()
|
err = dORM.QueryTable("user").Filter("Posts__Title", "Examples").One(&user)
|
||||||
throwFail(t, err)
|
throwFailNow(t, err)
|
||||||
throwFail(t, AssertIs(num, 2))
|
throwFailNow(t, AssertIs(user.UserName, "astaxie"))
|
||||||
}
|
|
||||||
|
user = User{}
|
||||||
|
err = dORM.QueryTable("user").Filter("Posts__User__UserName", "astaxie").Limit(1).One(&user)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(user.UserName, "astaxie"))
|
||||||
|
|
||||||
|
user = User{}
|
||||||
|
err = dORM.QueryTable("user").Filter("Posts__User__UserName", "astaxie").RelatedSel().Limit(1).One(&user)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(user.UserName, "astaxie"))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile.Age, 30))
|
||||||
|
|
||||||
func TestLimit(t *testing.T) {
|
|
||||||
var posts []*Post
|
var posts []*Post
|
||||||
qs := dORM.QueryTable("post")
|
num, err := dORM.QueryTable("post").Filter("Tags__Tag__Name", "golang").All(&posts)
|
||||||
num, err := qs.Limit(1).All(&posts)
|
throwFailNow(t, err)
|
||||||
throwFail(t, err)
|
throwFailNow(t, AssertIs(num, 3))
|
||||||
throwFail(t, AssertIs(num, 1))
|
throwFailNow(t, AssertIs(posts[0].Title, "Introduction"))
|
||||||
|
|
||||||
num, err = qs.Limit(-1).All(&posts)
|
posts = []*Post{}
|
||||||
throwFail(t, err)
|
num, err = dORM.QueryTable("post").Filter("Tags__Tag__Name", "golang").Filter("User__UserName", "slene").All(&posts)
|
||||||
throwFail(t, AssertIs(num, 4))
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(posts[0].Title, "Introduction"))
|
||||||
|
|
||||||
num, err = qs.Limit(-1, 2).All(&posts)
|
posts = []*Post{}
|
||||||
throwFail(t, err)
|
num, err = dORM.QueryTable("post").Filter("Tags__Tag__Name", "golang").
|
||||||
throwFail(t, AssertIs(num, 2))
|
Filter("User__UserName", "slene").RelatedSel().All(&posts)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(posts[0].User == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(posts[0].User.UserName, "slene"))
|
||||||
|
|
||||||
num, err = qs.Limit(0, 2).All(&posts)
|
var tags []*Tag
|
||||||
throwFail(t, err)
|
num, err = dORM.QueryTable("tag").Filter("Posts__Post__Title", "Introduction").All(&tags)
|
||||||
throwFail(t, AssertIs(num, 2))
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].Name, "golang"))
|
||||||
|
|
||||||
|
tags = []*Tag{}
|
||||||
|
num, err = dORM.QueryTable("tag").Filter("Posts__Post__Title", "Introduction").
|
||||||
|
Filter("BestPost__User__UserName", "astaxie").All(&tags)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].Name, "golang"))
|
||||||
|
|
||||||
|
tags = []*Tag{}
|
||||||
|
num, err = dORM.QueryTable("tag").Filter("Posts__Post__Title", "Introduction").
|
||||||
|
Filter("BestPost__User__UserName", "astaxie").RelatedSel().All(&tags)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].Name, "golang"))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].BestPost == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].BestPost.Title, "Examples"))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].BestPost.User == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(tags[0].BestPost.User.UserName, "astaxie"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOffset(t *testing.T) {
|
func TestLoadRelated(t *testing.T) {
|
||||||
var posts []*Post
|
// load reverse foreign key
|
||||||
qs := dORM.QueryTable("post")
|
user := User{Id: 3}
|
||||||
num, err := qs.Limit(1).Offset(2).All(&posts)
|
|
||||||
throwFail(t, err)
|
|
||||||
throwFail(t, AssertIs(num, 1))
|
|
||||||
|
|
||||||
num, err = qs.Offset(2).All(&posts)
|
err := dORM.Read(&user)
|
||||||
throwFail(t, err)
|
throwFailNow(t, err)
|
||||||
throwFail(t, AssertIs(num, 2))
|
|
||||||
|
num, err := dORM.LoadRelated(&user, "Posts")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 2))
|
||||||
|
throwFailNow(t, AssertIs(len(user.Posts), 2))
|
||||||
|
throwFailNow(t, AssertIs(user.Posts[0].User.Id, 3))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&user, "Posts", true)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(len(user.Posts), 2))
|
||||||
|
throwFailNow(t, AssertIs(user.Posts[0].User.UserName, "astaxie"))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&user, "Posts", true, 1)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(len(user.Posts), 1))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&user, "Posts", true, 0, 0, "-Id")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(len(user.Posts), 2))
|
||||||
|
throwFailNow(t, AssertIs(user.Posts[0].Title, "Formatting"))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&user, "Posts", true, 1, 1, "Id")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(len(user.Posts), 1))
|
||||||
|
throwFailNow(t, AssertIs(user.Posts[0].Title, "Formatting"))
|
||||||
|
|
||||||
|
// load reverse one to one
|
||||||
|
profile := Profile{Id: 3}
|
||||||
|
profile.BestPost = &Post{Id: 2}
|
||||||
|
num, err = dORM.Update(&profile, "BestPost")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
err = dORM.Read(&profile)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&profile, "User")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(profile.User == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(profile.User.UserName, "astaxie"))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&profile, "User", true)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(profile.User == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(profile.User.UserName, "astaxie"))
|
||||||
|
throwFailNow(t, AssertIs(profile.User.Profile.Age, profile.Age))
|
||||||
|
|
||||||
|
// load rel one to one
|
||||||
|
err = dORM.Read(&user)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&user, "Profile")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile.Age, 30))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&user, "Profile", true)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile.Age, 30))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile.BestPost == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(user.Profile.BestPost.Title, "Examples"))
|
||||||
|
|
||||||
|
post := Post{Id: 2}
|
||||||
|
|
||||||
|
// load rel foreign key
|
||||||
|
err = dORM.Read(&post)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&post, "User")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(post.User == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(post.User.UserName, "astaxie"))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&post, "User", true)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
throwFailNow(t, AssertIs(post.User == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(post.User.UserName, "astaxie"))
|
||||||
|
throwFailNow(t, AssertIs(post.User.Profile == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(post.User.Profile.Age, 30))
|
||||||
|
|
||||||
|
// load rel m2m
|
||||||
|
post = Post{Id: 2}
|
||||||
|
|
||||||
|
err = dORM.Read(&post)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&post, "Tags")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 2))
|
||||||
|
throwFailNow(t, AssertIs(len(post.Tags), 2))
|
||||||
|
throwFailNow(t, AssertIs(post.Tags[0].Name, "golang"))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&post, "Tags", true)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 2))
|
||||||
|
throwFailNow(t, AssertIs(len(post.Tags), 2))
|
||||||
|
throwFailNow(t, AssertIs(post.Tags[0].Name, "golang"))
|
||||||
|
throwFailNow(t, AssertIs(post.Tags[0].BestPost == nil, false))
|
||||||
|
throwFailNow(t, AssertIs(post.Tags[0].BestPost.User.UserName, "astaxie"))
|
||||||
|
|
||||||
|
// load reverse m2m
|
||||||
|
tag := Tag{Id: 1}
|
||||||
|
|
||||||
|
err = dORM.Read(&tag)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&tag, "Posts")
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 3))
|
||||||
|
throwFailNow(t, AssertIs(tag.Posts[0].Title, "Introduction"))
|
||||||
|
throwFailNow(t, AssertIs(tag.Posts[0].User.Id, 2))
|
||||||
|
throwFailNow(t, AssertIs(tag.Posts[0].User.Profile == nil, true))
|
||||||
|
|
||||||
|
num, err = dORM.LoadRelated(&tag, "Posts", true)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 3))
|
||||||
|
throwFailNow(t, AssertIs(tag.Posts[0].Title, "Introduction"))
|
||||||
|
throwFailNow(t, AssertIs(tag.Posts[0].User.Id, 2))
|
||||||
|
throwFailNow(t, AssertIs(tag.Posts[0].User.UserName, "slene"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOrderBy(t *testing.T) {
|
func TestQueryM2M(t *testing.T) {
|
||||||
qs := dORM.QueryTable("user")
|
post := Post{Id: 4}
|
||||||
num, err := qs.OrderBy("-status").Filter("user_name", "nobody").Count()
|
m2m := dORM.QueryM2M(&post, "Tags")
|
||||||
throwFail(t, err)
|
|
||||||
throwFail(t, AssertIs(num, 1))
|
|
||||||
|
|
||||||
num, err = qs.OrderBy("status").Filter("user_name", "slene").Count()
|
tag1 := []*Tag{&Tag{Name: "TestTag1"}, &Tag{Name: "TestTag2"}}
|
||||||
throwFail(t, err)
|
tag2 := &Tag{Name: "TestTag3"}
|
||||||
throwFail(t, AssertIs(num, 1))
|
tag3 := []interface{}{&Tag{Name: "TestTag4"}}
|
||||||
|
|
||||||
num, err = qs.OrderBy("-profile__age").Filter("user_name", "astaxie").Count()
|
tags := []interface{}{tag1[0], tag1[1], tag2, tag3[0]}
|
||||||
throwFail(t, err)
|
|
||||||
throwFail(t, AssertIs(num, 1))
|
for _, tag := range tags {
|
||||||
|
_, err := dORM.Insert(tag)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
num, err := m2m.Add(tag1)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 2))
|
||||||
|
|
||||||
|
num, err = m2m.Add(tag2)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = m2m.Add(tag3)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = m2m.Count()
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 5))
|
||||||
|
|
||||||
|
num, err = m2m.Remove(tag3)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = m2m.Count()
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 4))
|
||||||
|
|
||||||
|
exist := m2m.Exist(tag2)
|
||||||
|
throwFailNow(t, AssertIs(exist, true))
|
||||||
|
|
||||||
|
num, err = m2m.Remove(tag2)
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
exist = m2m.Exist(tag2)
|
||||||
|
throwFailNow(t, AssertIs(exist, false))
|
||||||
|
|
||||||
|
num, err = m2m.Count()
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 3))
|
||||||
|
|
||||||
|
num, err = m2m.Clear()
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 3))
|
||||||
|
|
||||||
|
num, err = m2m.Count()
|
||||||
|
throwFailNow(t, err)
|
||||||
|
throwFailNow(t, AssertIs(num, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryRelate(t *testing.T) {
|
||||||
|
// post := &Post{Id: 2}
|
||||||
|
|
||||||
|
// qs := dORM.QueryRelate(post, "Tags")
|
||||||
|
// num, err := qs.Count()
|
||||||
|
// throwFailNow(t, err)
|
||||||
|
// throwFailNow(t, AssertIs(num, 2))
|
||||||
|
|
||||||
|
// var tags []*Tag
|
||||||
|
// num, err = qs.All(&tags)
|
||||||
|
// throwFailNow(t, err)
|
||||||
|
// throwFailNow(t, AssertIs(num, 2))
|
||||||
|
// throwFailNow(t, AssertIs(tags[0].Name, "golang"))
|
||||||
|
|
||||||
|
// num, err = dORM.QueryTable("Tag").Filter("Posts__Post", 2).Count()
|
||||||
|
// throwFailNow(t, err)
|
||||||
|
// throwFailNow(t, AssertIs(num, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrepareInsert(t *testing.T) {
|
func TestPrepareInsert(t *testing.T) {
|
||||||
|
15
orm/types.go
15
orm/types.go
@ -24,9 +24,8 @@ type Ormer interface {
|
|||||||
Insert(interface{}) (int64, error)
|
Insert(interface{}) (int64, error)
|
||||||
Update(interface{}, ...string) (int64, error)
|
Update(interface{}, ...string) (int64, error)
|
||||||
Delete(interface{}) (int64, error)
|
Delete(interface{}) (int64, error)
|
||||||
M2mAdd(interface{}, string, ...interface{}) (int64, error)
|
LoadRelated(interface{}, string, ...interface{}) (int64, error)
|
||||||
M2mDel(interface{}, string, ...interface{}) (int64, error)
|
QueryM2M(interface{}, string) QueryM2Mer
|
||||||
LoadRel(interface{}, string) (int64, error)
|
|
||||||
QueryTable(interface{}) QuerySeter
|
QueryTable(interface{}) QuerySeter
|
||||||
Using(string) error
|
Using(string) error
|
||||||
Begin() error
|
Begin() error
|
||||||
@ -61,6 +60,14 @@ type QuerySeter interface {
|
|||||||
ValuesFlat(*ParamsList, string) (int64, error)
|
ValuesFlat(*ParamsList, string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryM2Mer interface {
|
||||||
|
Add(...interface{}) (int64, error)
|
||||||
|
Remove(...interface{}) (int64, error)
|
||||||
|
Exist(interface{}) bool
|
||||||
|
Clear() (int64, error)
|
||||||
|
Count() (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
type RawPreparer interface {
|
type RawPreparer interface {
|
||||||
Exec(...interface{}) (sql.Result, error)
|
Exec(...interface{}) (sql.Result, error)
|
||||||
Close() error
|
Close() error
|
||||||
@ -114,6 +121,7 @@ type txEnder interface {
|
|||||||
type dbBaser interface {
|
type dbBaser interface {
|
||||||
Read(dbQuerier, *modelInfo, reflect.Value, *time.Location, []string) error
|
Read(dbQuerier, *modelInfo, reflect.Value, *time.Location, []string) error
|
||||||
Insert(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
|
Insert(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
|
||||||
|
InsertValue(dbQuerier, *modelInfo, []string, []interface{}) (int64, error)
|
||||||
InsertStmt(stmtQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
|
InsertStmt(stmtQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
|
||||||
Update(dbQuerier, *modelInfo, reflect.Value, *time.Location, []string) (int64, error)
|
Update(dbQuerier, *modelInfo, reflect.Value, *time.Location, []string) (int64, error)
|
||||||
Delete(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
|
Delete(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
|
||||||
@ -139,4 +147,5 @@ type dbBaser interface {
|
|||||||
ShowTablesQuery() string
|
ShowTablesQuery() string
|
||||||
ShowColumnsQuery(string) string
|
ShowColumnsQuery(string) string
|
||||||
IndexExists(dbQuerier, string, string) bool
|
IndexExists(dbQuerier, string, string) bool
|
||||||
|
collectFieldValue(*modelInfo, *fieldInfo, reflect.Value, bool, *time.Location) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user