Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
张磊
/
FileStorageBeego
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
d043ebcd
authored
2013-10-14 22:31:35 +0800
by
slene
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
orm support complete m2m operation api / auto load related api
1 parent
e11c40ee
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
756 additions
and
140 deletions
orm/cmd_utils.go
orm/db.go
orm/db_tables.go
orm/models_boot.go
orm/models_info_f.go
orm/models_info_m.go
orm/models_test.go
orm/orm.go
orm/orm_querym2m.go
orm/orm_test.go
orm/types.go
orm/cmd_utils.go
View file @
d043ebc
...
...
@@ -151,7 +151,11 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex
}
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
))
for
_
,
name
:=
range
names
{
if
fi
,
ok
:=
mi
.
fields
.
GetByAny
(
name
);
ok
&&
fi
.
dbcol
{
...
...
orm/db.go
View file @
d043ebc
...
...
@@ -52,7 +52,6 @@ type dbBase struct {
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
)
{
_
,
pkValue
,
_
:=
getExistPk
(
mi
,
ind
)
for
_
,
column
:=
range
cols
{
var
fi
*
fieldInfo
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
{
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
{}
if
fi
.
pk
{
value
=
pkValue
_
,
value
,
_
=
getExistPk
(
mi
,
ind
)
}
else
{
field
:=
ind
.
Field
(
fi
.
fieldIndex
)
if
fi
.
isFielder
{
...
...
@@ -111,7 +121,7 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string,
}
}
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
)
values
=
append
(
values
,
value
)
}
return
return
value
,
nil
}
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
d
.
InsertValue
(
q
,
mi
,
names
,
values
)
}
func
(
d
*
dbBase
)
InsertValue
(
q
dbQuerier
,
mi
*
modelInfo
,
names
[]
string
,
values
[]
interface
{})
(
int64
,
error
)
{
Q
:=
d
.
ins
.
TableQuote
()
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
)
:
]
for
_
,
tbl
:=
range
tables
.
tables
{
// loop selected tables
if
tbl
.
sel
{
last
:=
mind
names
:=
""
mmi
:=
mi
// loop cascade models
for
_
,
name
:=
range
tbl
.
names
{
names
+=
name
if
val
,
ok
:=
cacheV
[
names
];
ok
{
...
...
@@ -665,8 +678,10 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
}
else
{
fi
:=
mmi
.
fields
.
GetByName
(
name
)
lastm
:=
mmi
mmi
:=
fi
.
relModelInfo
field
:=
reflect
.
Indirect
(
last
.
Field
(
fi
.
fieldIndex
))
mmi
=
fi
.
relModelInfo
field
:=
last
if
last
.
Kind
()
!=
reflect
.
Invalid
{
field
=
reflect
.
Indirect
(
last
.
Field
(
fi
.
fieldIndex
))
if
field
.
IsValid
()
{
d
.
setColsValues
(
mmi
,
&
field
,
mmi
.
fields
.
dbcols
,
trefs
[
:
len
(
mmi
.
fields
.
dbcols
)],
tz
)
for
_
,
fi
:=
range
mmi
.
fields
.
fieldsReverse
{
...
...
@@ -679,14 +694,15 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
}
}
}
cacheV
[
names
]
=
&
field
cacheM
[
names
]
=
mmi
last
=
field
}
trefs
=
trefs
[
len
(
mmi
.
fields
.
dbcols
)
:
]
}
cacheV
[
names
]
=
&
field
cacheM
[
names
]
=
mmi
}
}
trefs
=
trefs
[
len
(
mmi
.
fields
.
dbcols
)
:
]
}
}
if
one
{
...
...
orm/db_tables.go
View file @
d043ebc
...
...
@@ -100,22 +100,29 @@ func (t *dbTables) parseRelated(rels []string, depth int) {
exs
=
strings
.
Split
(
s
,
ExprSep
)
names
=
make
([]
string
,
0
,
len
(
exs
))
mmi
=
t
.
mi
can
s
el
=
true
can
c
el
=
true
jtl
*
dbTable
)
inner
:=
true
for
_
,
ex
:=
range
exs
{
if
fi
,
ok
:=
mmi
.
fields
.
GetByAny
(
ex
);
ok
&&
fi
.
rel
&&
fi
.
fieldType
!=
RelManyToMany
{
names
=
append
(
names
,
fi
.
name
)
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
if
fi
.
reverse
{
can
s
el
=
false
can
c
el
=
false
}
if
can
s
el
{
if
can
c
el
{
jt
.
sel
=
depth
>
0
if
i
<
relsNum
{
...
...
@@ -178,9 +185,8 @@ func (t *dbTables) getJoinSql() (join string) {
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
(
ffi
*
fieldInfo
jtl
*
dbTable
mmi
=
mi
)
...
...
@@ -188,15 +194,16 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
num
:=
len
(
exprs
)
-
1
names
:=
make
([]
string
,
0
)
inner
:=
true
for
i
,
ex
:=
range
exprs
{
exist
:=
false
check
:
fi
,
ok
:=
mmi
.
fields
.
GetByAny
(
ex
)
if
ok
{
if
num
!=
i
{
isRel
:=
fi
.
rel
||
fi
.
reverse
names
=
append
(
names
,
fi
.
name
)
switch
{
...
...
@@ -207,54 +214,47 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
}
case
fi
.
reverse
:
mmi
=
fi
.
reverseFieldInfo
.
mi
if
fi
.
reverseFieldInfo
.
fieldType
==
RelManyToMany
{
mmi
=
fi
.
reverseFieldInfo
.
relThroughModelInfo
}
default
:
return
if
isRel
&&
(
fi
.
mi
.
isThrough
==
false
||
num
!=
i
)
{
if
fi
.
null
{
inner
=
false
}
jt
,
_
:=
d
.
add
(
names
,
mmi
,
fi
,
fi
.
null
==
false
)
jt
,
_
:=
t
.
add
(
names
,
mmi
,
fi
,
inner
)
jt
.
jtl
=
jtl
jtl
=
jt
if
fi
.
rel
&&
fi
.
fieldType
==
RelManyToMany
{
ex
=
fi
.
relModelInfo
.
name
goto
check
}
if
fi
.
reverse
&&
fi
.
reverseFieldInfo
.
fieldType
==
RelManyToMany
{
ex
=
fi
.
reverseFieldInfo
.
mi
.
name
goto
check
}
exist
=
true
}
else
{
if
ffi
==
nil
{
if
num
==
i
{
if
i
==
0
||
jtl
==
nil
{
index
=
"T0"
}
else
{
index
=
jtl
.
index
}
info
=
fi
if
jtl
!=
nil
{
name
=
jtl
.
name
+
ExprSep
+
fi
.
name
}
else
{
if
jtl
==
nil
{
name
=
fi
.
name
}
else
{
name
=
jtl
.
name
+
ExprSep
+
fi
.
name
}
switch
fi
.
fieldType
{
case
RelManyToMany
,
RelReverseMany
:
default
:
exist
=
true
switch
{
case
fi
.
rel
:
case
fi
.
reverse
:
switch
fi
.
reverseFieldInfo
.
fieldType
{
case
RelOneToOne
,
RelForeignKey
:
index
=
jtl
.
index
info
=
fi
.
reverseFieldInfo
.
mi
.
fields
.
pk
name
=
info
.
name
}
}
ffi
=
fi
}
if
exist
==
fa
lse
{
}
e
lse
{
index
=
""
name
=
""
info
=
nil
...
...
@@ -267,16 +267,15 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
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
()
{
return
}
Q
:=
d
.
base
.
TableQuote
()
Q
:=
t
.
base
.
TableQuote
()
mi
:=
d
.
mi
mi
:=
t
.
mi
// outFor:
for
i
,
p
:=
range
cond
.
params
{
if
i
>
0
{
if
p
.
isOr
{
...
...
@@ -289,7 +288,7 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
where
+=
"NOT "
}
if
p
.
isCond
{
w
,
ps
:=
d
.
getCondSql
(
p
.
cond
,
true
,
tz
)
w
,
ps
:=
t
.
getCondSql
(
p
.
cond
,
true
,
tz
)
if
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
]
}
index
,
_
,
fi
,
suc
:=
d
.
parseExprs
(
mi
,
exprs
)
index
,
_
,
fi
,
suc
:=
t
.
parseExprs
(
mi
,
exprs
)
if
suc
==
false
{
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"
}
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
)
d
.
base
.
GenerateOperatorLeftCol
(
fi
,
operator
,
&
leftCol
)
t
.
base
.
GenerateOperatorLeftCol
(
fi
,
operator
,
&
leftCol
)
where
+=
fmt
.
Sprintf
(
"%s %s "
,
leftCol
,
operSql
)
params
=
append
(
params
,
args
...
)
...
...
@@ -332,12 +331,12 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
return
}
func
(
d
*
dbTables
)
getOrderSql
(
orders
[]
string
)
(
orderSql
string
)
{
func
(
t
*
dbTables
)
getOrderSql
(
orders
[]
string
)
(
orderSql
string
)
{
if
len
(
orders
)
==
0
{
return
}
Q
:=
d
.
base
.
TableQuote
()
Q
:=
t
.
base
.
TableQuote
()
orderSqls
:=
make
([]
string
,
0
,
len
(
orders
))
for
_
,
order
:=
range
orders
{
...
...
@@ -348,7 +347,7 @@ func (d *dbTables) getOrderSql(orders []string) (orderSql string) {
}
exprs
:=
strings
.
Split
(
order
,
ExprSep
)
index
,
_
,
fi
,
suc
:=
d
.
parseExprs
(
d
.
mi
,
exprs
)
index
,
_
,
fi
,
suc
:=
t
.
parseExprs
(
t
.
mi
,
exprs
)
if
suc
==
false
{
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
}
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
{
limit
=
int64
(
DefaultRowsLimit
)
}
if
limit
<
0
{
// no limit
if
offset
>
0
{
maxLimit
:=
d
.
base
.
MaxLimit
()
maxLimit
:=
t
.
base
.
MaxLimit
()
if
maxLimit
==
0
{
limits
=
fmt
.
Sprintf
(
"OFFSET %d"
,
offset
)
}
else
{
...
...
orm/models_boot.go
View file @
d043ebc
...
...
@@ -121,7 +121,6 @@ func bootStrap() {
err
=
errors
.
New
(
msg
)
goto
end
}
err
=
nil
}
else
{
i
:=
newM2MModelInfo
(
mi
,
mii
)
if
fi
.
relTable
!=
""
{
...
...
@@ -135,6 +134,8 @@ func bootStrap() {
fi
.
relTable
=
i
.
table
fi
.
relThroughModelInfo
=
i
}
fi
.
relThroughModelInfo
.
isThrough
=
true
}
}
}
...
...
@@ -152,6 +153,7 @@ func bootStrap() {
break
}
}
if
inModel
==
false
{
rmi
:=
fi
.
relModelInfo
ffi
:=
new
(
fieldInfo
)
...
...
@@ -185,9 +187,34 @@ func bootStrap() {
}
}
models
=
modelCache
.
all
()
for
_
,
mi
:=
range
models
{
if
fields
,
ok
:=
mi
.
fields
.
fieldsByType
[
RelReverseOne
];
ok
{
for
_
,
fi
:=
range
fields
{
for
_
,
fi
:=
range
mi
.
fields
.
fieldsRel
{
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
mForA
:
for
_
,
ffi
:=
range
fi
.
relModelInfo
.
fields
.
fieldsByType
[
RelOneToOne
]
{
...
...
@@ -195,6 +222,9 @@ func bootStrap() {
found
=
true
fi
.
reverseField
=
ffi
.
name
fi
.
reverseFieldInfo
=
ffi
ffi
.
reverseField
=
fi
.
name
ffi
.
reverseFieldInfo
=
fi
break
mForA
}
}
...
...
@@ -202,10 +232,7 @@ func bootStrap() {
err
=
fmt
.
Errorf
(
"reverse field `%s` not found in model `%s`"
,
fi
.
fullName
,
fi
.
relModelInfo
.
fullName
)
goto
end
}
}
}
if
fields
,
ok
:=
mi
.
fields
.
fieldsByType
[
RelReverseMany
];
ok
{
for
_
,
fi
:=
range
fields
{
case
RelReverseMany
:
found
:=
false
mForB
:
for
_
,
ffi
:=
range
fi
.
relModelInfo
.
fields
.
fieldsByType
[
RelForeignKey
]
{
...
...
@@ -213,6 +240,10 @@ func bootStrap() {
found
=
true
fi
.
reverseField
=
ffi
.
name
fi
.
reverseFieldInfo
=
ffi
ffi
.
reverseField
=
fi
.
name
ffi
.
reverseFieldInfo
=
fi
break
mForB
}
}
...
...
@@ -221,14 +252,20 @@ func bootStrap() {
for
_
,
ffi
:=
range
fi
.
relModelInfo
.
fields
.
fieldsByType
[
RelManyToMany
]
{
if
ffi
.
relModelInfo
==
mi
{
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
}
}
}
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
}
}
...
...
orm/models_info_f.go
View file @
d043ebc
...
...
@@ -103,6 +103,8 @@ type fieldInfo struct {
reverse
bool
reverseField
string
reverseFieldInfo
*
fieldInfo
reverseFieldInfoTwo
*
fieldInfo
reverseFieldInfoM2M
*
fieldInfo
relTable
string
relThrough
string
relThroughModelInfo
*
modelInfo
...
...
orm/models_info_m.go
View file @
d043ebc
...
...
@@ -16,6 +16,8 @@ type modelInfo struct {
fields
*
fields
manual
bool
addrField
reflect
.
Value
uniques
[]
string
isThrough
bool
}
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
(
f2
)
info
.
fields
.
pk
=
fa
info
.
uniques
=
[]
string
{
f1
.
column
,
f2
.
column
}
return
}
...
...
orm/models_test.go
View file @
d043ebc
...
...
@@ -103,6 +103,7 @@ type Profile struct {
Age
int16
Money
float64
User
*
User
`orm:"reverse(one)" json:"-"`
BestPost
*
Post
`orm:"rel(one);null"`
}
func
(
u
*
Profile
)
TableName
()
string
{
...
...
@@ -138,6 +139,7 @@ func NewPost() *Post {
type
Tag
struct
{
Id
int
Name
string
`orm:"size(30)"`
BestPost
*
Post
`orm:"rel(one);null"`
Posts
[]
*
Post
`orm:"reverse(many)" json:"-"`
}
...
...
orm/orm.go
View file @
d043ebc
...
...
@@ -18,7 +18,7 @@ var (
Debug
=
false
DebugLog
=
NewLog
(
os
.
Stderr
)
DefaultRowsLimit
=
1000
DefaultRelsDepth
=
5
DefaultRelsDepth
=
2
DefaultTimeLoc
=
time
.
Local
ErrTxHasBegan
=
errors
.
New
(
"<Ormer.Begin> transaction already 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
))
}
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
{
mi
,
ind
:=
o
.
getMiInd
(
md
)
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
}
func
(
o
*
orm
)
M2mAdd
(
md
interface
{},
name
string
,
mds
...
interface
{})
(
int64
,
error
)
{
// TODO
panic
(
ErrNotImplement
)
return
0
,
nil
func
(
o
*
orm
)
QueryM2M
(
md
interface
{},
name
string
)
QueryM2Mer
{
mi
,
ind
:=
o
.
getMiInd
(
md
)
fi
:=
o
.
getFieldInfo
(
mi
,
name
)
if
fi
.
fieldType
!=
RelManyToMany
{
panic
(
fmt
.
Errorf
(
"<Ormer.QueryM2M> name `%s` for model `%s` is not a m2m field"
,
fi
.
name
,
mi
.
fullName
))
}
return
newQueryM2M
(
md
,
o
,
mi
,
fi
,
ind
)
}
func
(
o
*
orm
)
LoadRelated
(
md
interface
{},
name
string
,
args
...
interface
{})
(
int64
,
error
)
{
_
,
fi
,
ind
,
qseter
:=
o
.
queryRelated
(
md
,
name
)
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
)
M2mDel
(
md
interface
{},
name
string
,
mds
...
interface
{})
(
int64
,
error
)
{
// TODO
panic
(
ErrNotImplement
)
return
0
,
nil
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
)
LoadRel
(
md
interface
{},
name
string
)
(
int64
,
error
)
{
// TODO
panic
(
ErrNotImplement
)
return
0
,
nil
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
)
{
...
...
orm/orm_querym2m.go
0 → 100644
View file @
d043ebc
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
}
orm/orm_test.go
View file @
d043ebc
...
...
@@ -48,9 +48,9 @@ func ValuesCompare(is bool, a interface{}, args ...interface{}) (err error, ok b
ok
=
is
&&
ok
||
!
is
&&
!
ok
if
!
ok
{
if
is
{
err
=
fmt
.
Errorf
(
"expected:
a ==
`%v`, get `%v`"
,
b
,
a
)
err
=
fmt
.
Errorf
(
"expected: `%v`, get `%v`"
,
b
,
a
)
}
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
))
tags
:=
[]
*
Tag
{
&
Tag
{
Name
:
"golang"
},
&
Tag
{
Name
:
"golang"
,
BestPost
:
&
Post
{
Id
:
2
}
},
&
Tag
{
Name
:
"example"
},
&
Tag
{
Name
:
"format"
},
&
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
)
throwFail
(
t
,
err
)
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
{
...
...
@@ -590,6 +596,68 @@ func TestOperators(t *testing.T) {
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
)
{
var
users
[]
*
User
qs
:=
dORM
.
QueryTable
(
"user"
)
...
...
@@ -758,66 +826,292 @@ func TestRelatedSel(t *testing.T) {
throwFailNow
(
t
,
AssertIs
(
posts
[
3
]
.
User
.
UserName
,
"nobody"
))
}
func
TestSetCond
(
t
*
testing
.
T
)
{
cond
:=
NewCondition
()
cond1
:=
cond
.
And
(
"profile__isnull"
,
false
)
.
AndNot
(
"status__in"
,
1
)
.
Or
(
"profile__age__gt"
,
2000
)
func
TestReverseQuery
(
t
*
testing
.
T
)
{
var
profile
Profile
err
:=
dORM
.
QueryTable
(
"user_profile"
)
.
Filter
(
"User"
,
3
)
.
One
(
&
profile
)
throwFailNow
(
t
,
err
)
throwFailNow
(
t
,
AssertIs
(
profile
.
Age
,
30
))
qs
:=
dORM
.
QueryTable
(
"user"
)
num
,
err
:=
qs
.
SetCond
(
cond1
)
.
Count
(
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
1
))
profile
=
Profile
{}
err
=
dORM
.
QueryTable
(
"user_profile"
)
.
Filter
(
"User__UserName"
,
"astaxie"
)
.
One
(
&
profile
)
throwFail
Now
(
t
,
err
)
throwFail
Now
(
t
,
AssertIs
(
profile
.
Age
,
30
))
cond2
:=
cond
.
AndCond
(
cond1
)
.
OrCond
(
cond
.
And
(
"user_name"
,
"slene"
))
num
,
err
=
qs
.
SetCond
(
cond2
)
.
Count
()
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
2
))
}
var
user
User
err
=
dORM
.
QueryTable
(
"user"
)
.
Filter
(
"Posts__Title"
,
"Examples"
)
.
One
(
&
user
)
throwFailNow
(
t
,
err
)
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
qs
:=
dORM
.
QueryTable
(
"post"
)
num
,
err
:=
qs
.
Limit
(
1
)
.
All
(
&
posts
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
1
))
num
,
err
:=
dORM
.
QueryTable
(
"post"
)
.
Filter
(
"Tags__Tag__Name"
,
"golang"
)
.
All
(
&
posts
)
throwFailNow
(
t
,
err
)
throwFail
Now
(
t
,
AssertIs
(
num
,
3
)
)
throwFail
Now
(
t
,
AssertIs
(
posts
[
0
]
.
Title
,
"Introduction"
))
num
,
err
=
qs
.
Limit
(
-
1
)
.
All
(
&
posts
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
4
))
posts
=
[]
*
Post
{}
num
,
err
=
dORM
.
QueryTable
(
"post"
)
.
Filter
(
"Tags__Tag__Name"
,
"golang"
)
.
Filter
(
"User__UserName"
,
"slene"
)
.
All
(
&
posts
)
throwFailNow
(
t
,
err
)
throwFailNow
(
t
,
AssertIs
(
num
,
1
))
throwFailNow
(
t
,
AssertIs
(
posts
[
0
]
.
Title
,
"Introduction"
))
num
,
err
=
qs
.
Limit
(
-
1
,
2
)
.
All
(
&
posts
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
2
))
posts
=
[]
*
Post
{}
num
,
err
=
dORM
.
QueryTable
(
"post"
)
.
Filter
(
"Tags__Tag__Name"
,
"golang"
)
.
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
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
2
))
var
tags
[]
*
Tag
num
,
err
=
dORM
.
QueryTable
(
"tag"
)
.
Filter
(
"Posts__Post__Title"
,
"Introduction"
)
.
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"
)
.
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
)
{
var
posts
[]
*
Post
qs
:=
dORM
.
QueryTable
(
"post"
)
num
,
err
:=
qs
.
Limit
(
1
)
.
Offset
(
2
)
.
All
(
&
posts
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
1
))
func
TestLoadRelated
(
t
*
testing
.
T
)
{
// load reverse foreign key
user
:=
User
{
Id
:
3
}
num
,
err
=
qs
.
Offset
(
2
)
.
All
(
&
posts
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
2
))
err
:=
dORM
.
Read
(
&
user
)
throwFailNow
(
t
,
err
)
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
)
{
qs
:=
dORM
.
QueryTable
(
"user"
)
num
,
err
:=
qs
.
OrderBy
(
"-status"
)
.
Filter
(
"user_name"
,
"nobody"
)
.
Count
()
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
1
))
func
TestQueryM2M
(
t
*
testing
.
T
)
{
post
:=
Post
{
Id
:
4
}
m2m
:=
dORM
.
QueryM2M
(
&
post
,
"Tags"
)
num
,
err
=
qs
.
OrderBy
(
"status"
)
.
Filter
(
"user_name"
,
"slene"
)
.
Count
()
t
hrowFail
(
t
,
err
)
t
hrowFail
(
t
,
AssertIs
(
num
,
1
))
tag1
:=
[]
*
Tag
{
&
Tag
{
Name
:
"TestTag1"
},
&
Tag
{
Name
:
"TestTag2"
}}
t
ag2
:=
&
Tag
{
Name
:
"TestTag3"
}
t
ag3
:=
[]
interface
{}{
&
Tag
{
Name
:
"TestTag4"
}}
num
,
err
=
qs
.
OrderBy
(
"-profile__age"
)
.
Filter
(
"user_name"
,
"astaxie"
)
.
Count
()
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
1
))
tags
:=
[]
interface
{}{
tag1
[
0
],
tag1
[
1
],
tag2
,
tag3
[
0
]}
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
)
{
...
...
orm/types.go
View file @
d043ebc
...
...
@@ -24,9 +24,8 @@ type Ormer interface {
Insert
(
interface
{})
(
int64
,
error
)
Update
(
interface
{},
...
string
)
(
int64
,
error
)
Delete
(
interface
{})
(
int64
,
error
)
M2mAdd
(
interface
{},
string
,
...
interface
{})
(
int64
,
error
)
M2mDel
(
interface
{},
string
,
...
interface
{})
(
int64
,
error
)
LoadRel
(
interface
{},
string
)
(
int64
,
error
)
LoadRelated
(
interface
{},
string
,
...
interface
{})
(
int64
,
error
)
QueryM2M
(
interface
{},
string
)
QueryM2Mer
QueryTable
(
interface
{})
QuerySeter
Using
(
string
)
error
Begin
()
error
...
...
@@ -61,6 +60,14 @@ type QuerySeter interface {
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
{
Exec
(
...
interface
{})
(
sql
.
Result
,
error
)
Close
()
error
...
...
@@ -114,6 +121,7 @@ type txEnder interface {
type
dbBaser
interface
{
Read
(
dbQuerier
,
*
modelInfo
,
reflect
.
Value
,
*
time
.
Location
,
[]
string
)
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
)
Update
(
dbQuerier
,
*
modelInfo
,
reflect
.
Value
,
*
time
.
Location
,
[]
string
)
(
int64
,
error
)
Delete
(
dbQuerier
,
*
modelInfo
,
reflect
.
Value
,
*
time
.
Location
)
(
int64
,
error
)
...
...
@@ -139,4 +147,5 @@ type dbBaser interface {
ShowTablesQuery
()
string
ShowColumnsQuery
(
string
)
string
IndexExists
(
dbQuerier
,
string
,
string
)
bool
collectFieldValue
(
*
modelInfo
,
*
fieldInfo
,
reflect
.
Value
,
bool
,
*
time
.
Location
)
(
interface
{},
error
)
}
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment