Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
f6ad2cf8
Commit
f6ad2cf8
authored
Apr 12, 2016
by
astaxie
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1875 from miraclesu/feature/orm_json
orm: add json & jsonb type support
parents
7906b18d
99f1e6c8
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
168 additions
and
28 deletions
+168
-28
cmd_utils.go
orm/cmd_utils.go
+14
-0
db.go
orm/db.go
+11
-3
db_postgres.go
orm/db_postgres.go
+2
-0
models_fields.go
orm/models_fields.go
+94
-2
models_info_f.go
orm/models_info_f.go
+10
-3
models_test.go
orm/models_test.go
+14
-10
orm_test.go
orm/orm_test.go
+23
-10
No files found.
orm/cmd_utils.go
View file @
f6ad2cf8
...
...
@@ -90,6 +90,18 @@ checkColumn:
}
else
{
col
=
fmt
.
Sprintf
(
s
,
fi
.
digits
,
fi
.
decimals
)
}
case
TypeJSONField
:
if
al
.
Driver
!=
DRPostgres
{
fieldType
=
TypeCharField
goto
checkColumn
}
col
=
T
[
"json"
]
case
TypeJsonbField
:
if
al
.
Driver
!=
DRPostgres
{
fieldType
=
TypeCharField
goto
checkColumn
}
col
=
T
[
"jsonb"
]
case
RelForeignKey
,
RelOneToOne
:
fieldType
=
fi
.
relModelInfo
.
fields
.
pk
.
fieldType
fieldSize
=
fi
.
relModelInfo
.
fields
.
pk
.
size
...
...
@@ -278,6 +290,8 @@ func getColumnDefault(fi *fieldInfo) string {
case
TypeBooleanField
:
t
=
" DEFAULT %s "
d
=
"FALSE"
case
TypeJSONField
,
TypeJsonbField
:
d
=
"{}"
}
if
fi
.
colDefault
{
...
...
orm/db.go
View file @
f6ad2cf8
...
...
@@ -141,7 +141,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
}
else
{
value
=
field
.
Bool
()
}
case
TypeCharField
,
TypeTextField
:
case
TypeCharField
,
TypeTextField
,
TypeJSONField
,
TypeJsonbField
:
if
ns
,
ok
:=
field
.
Interface
()
.
(
sql
.
NullString
);
ok
{
value
=
nil
if
ns
.
Valid
{
...
...
@@ -247,6 +247,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
field
.
Set
(
reflect
.
ValueOf
(
tnow
.
In
(
DefaultTimeLoc
)))
}
}
case
TypeJSONField
,
TypeJsonbField
:
if
s
,
ok
:=
value
.
(
string
);
(
ok
&&
len
(
s
)
==
0
)
||
value
==
nil
{
if
fi
.
colDefault
&&
fi
.
initial
.
Exist
()
{
value
=
fi
.
initial
.
String
()
}
else
{
value
=
nil
}
}
}
}
return
value
,
nil
...
...
@@ -1093,7 +1101,7 @@ setValue:
}
value
=
b
}
case
fieldType
==
TypeCharField
||
fieldType
==
TypeTextField
:
case
fieldType
==
TypeCharField
||
fieldType
==
TypeTextField
||
fieldType
==
TypeJSONField
||
fieldType
==
TypeJsonbField
:
if
str
==
nil
{
value
=
ToStr
(
val
)
}
else
{
...
...
@@ -1239,7 +1247,7 @@ setValue:
field
.
SetBool
(
value
.
(
bool
))
}
}
case
fieldType
==
TypeCharField
||
fieldType
==
TypeTextField
:
case
fieldType
==
TypeCharField
||
fieldType
==
TypeTextField
||
fieldType
==
TypeJSONField
||
fieldType
==
TypeJsonbField
:
if
isNative
{
if
ns
,
ok
:=
field
.
Interface
()
.
(
sql
.
NullString
);
ok
{
if
value
==
nil
{
...
...
orm/db_postgres.go
View file @
f6ad2cf8
...
...
@@ -56,6 +56,8 @@ var postgresTypes = map[string]string{
"uint64"
:
`bigint CHECK("%COL%" >= 0)`
,
"float64"
:
"double precision"
,
"float64-decimal"
:
"numeric(%d, %d)"
,
"json"
:
"json"
,
"jsonb"
:
"jsonb"
,
}
// postgresql dbBaser.
...
...
orm/models_fields.go
View file @
f6ad2cf8
...
...
@@ -38,6 +38,8 @@ const (
TypePositiveBigIntegerField
TypeFloatField
TypeDecimalField
TypeJSONField
TypeJsonbField
RelForeignKey
RelOneToOne
RelManyToMany
...
...
@@ -49,7 +51,7 @@ const (
const
(
IsIntegerField
=
^-
TypePositiveBigIntegerField
>>
5
<<
6
IsPositiveIntegerField
=
^-
TypePositiveBigIntegerField
>>
9
<<
10
IsRelField
=
^-
RelReverseMany
>>
1
5
<<
16
IsRelField
=
^-
RelReverseMany
>>
1
7
<<
18
IsFieldType
=
^-
RelReverseMany
<<
1
+
1
)
...
...
@@ -146,7 +148,7 @@ func (e *CharField) RawValue() interface{} {
// verify CharField implement Fielder
var
_
Fielder
=
new
(
CharField
)
// A time, represented in go by a time.Time instance.
//
TimeField
A time, represented in go by a time.Time instance.
// only time values like 10:00:00
// Has a few extra, optional attr tag:
//
...
...
@@ -161,22 +163,27 @@ var _ Fielder = new(CharField)
// eg: `orm:"auto_now"` or `orm:"auto_now_add"`
type
TimeField
time
.
Time
// Value return the time.Time
func
(
e
TimeField
)
Value
()
time
.
Time
{
return
time
.
Time
(
e
)
}
// Set set the TimeField's value
func
(
e
*
TimeField
)
Set
(
d
time
.
Time
)
{
*
e
=
TimeField
(
d
)
}
// String convert time to string
func
(
e
*
TimeField
)
String
()
string
{
return
e
.
Value
()
.
String
()
}
// FieldType return enum type Date
func
(
e
*
TimeField
)
FieldType
()
int
{
return
TypeDateField
}
// SetRaw convert the interface to time.Time. Allow string and time.Time
func
(
e
*
TimeField
)
SetRaw
(
value
interface
{})
error
{
switch
d
:=
value
.
(
type
)
{
case
time
.
Time
:
...
...
@@ -193,6 +200,7 @@ func (e *TimeField) SetRaw(value interface{}) error {
return
nil
}
// RawValue return time value
func
(
e
*
TimeField
)
RawValue
()
interface
{}
{
return
e
.
Value
()
}
...
...
@@ -681,3 +689,87 @@ func (e *TextField) RawValue() interface{} {
// verify TextField implement Fielder
var
_
Fielder
=
new
(
TextField
)
// JSONField postgres json field.
type
JSONField
string
// Value return JSONField value
func
(
j
JSONField
)
Value
()
string
{
return
string
(
j
)
}
// Set the JSONField value
func
(
j
*
JSONField
)
Set
(
d
string
)
{
*
j
=
JSONField
(
d
)
}
// String convert JSONField to string
func
(
j
*
JSONField
)
String
()
string
{
return
j
.
Value
()
}
// FieldType return enum type
func
(
j
*
JSONField
)
FieldType
()
int
{
return
TypeJSONField
}
// SetRaw convert interface string to string
func
(
j
*
JSONField
)
SetRaw
(
value
interface
{})
error
{
switch
d
:=
value
.
(
type
)
{
case
string
:
j
.
Set
(
d
)
default
:
return
fmt
.
Errorf
(
"<JSONField.SetRaw> unknown value `%s`"
,
value
)
}
return
nil
}
// RawValue return JSONField value
func
(
j
*
JSONField
)
RawValue
()
interface
{}
{
return
j
.
Value
()
}
// verify JSONField implement Fielder
var
_
Fielder
=
new
(
JSONField
)
// JsonbField postgres json field.
type
JsonbField
string
// Value return JsonbField value
func
(
j
JsonbField
)
Value
()
string
{
return
string
(
j
)
}
// Set the JsonbField value
func
(
j
*
JsonbField
)
Set
(
d
string
)
{
*
j
=
JsonbField
(
d
)
}
// String convert JsonbField to string
func
(
j
*
JsonbField
)
String
()
string
{
return
j
.
Value
()
}
// FieldType return enum type
func
(
j
*
JsonbField
)
FieldType
()
int
{
return
TypeJsonbField
}
// SetRaw convert interface string to string
func
(
j
*
JsonbField
)
SetRaw
(
value
interface
{})
error
{
switch
d
:=
value
.
(
type
)
{
case
string
:
j
.
Set
(
d
)
default
:
return
fmt
.
Errorf
(
"<JsonbField.SetRaw> unknown value `%s`"
,
value
)
}
return
nil
}
// RawValue return JsonbField value
func
(
j
*
JsonbField
)
RawValue
()
interface
{}
{
return
j
.
Value
()
}
// verify JsonbField implement Fielder
var
_
Fielder
=
new
(
JsonbField
)
orm/models_info_f.go
View file @
f6ad2cf8
...
...
@@ -239,8 +239,15 @@ checkType:
if
err
!=
nil
{
goto
end
}
if
fieldType
==
TypeCharField
&&
tags
[
"type"
]
==
"text"
{
fieldType
=
TypeTextField
if
fieldType
==
TypeCharField
{
switch
tags
[
"type"
]
{
case
"text"
:
fieldType
=
TypeTextField
case
"json"
:
fieldType
=
TypeJSONField
case
"jsonb"
:
fieldType
=
TypeJsonbField
}
}
if
fieldType
==
TypeFloatField
&&
(
digits
!=
""
||
decimals
!=
""
)
{
fieldType
=
TypeDecimalField
...
...
@@ -342,7 +349,7 @@ checkType:
switch
fieldType
{
case
TypeBooleanField
:
case
TypeCharField
:
case
TypeCharField
,
TypeJSONField
,
TypeJsonbField
:
if
size
!=
""
{
v
,
e
:=
StrTo
(
size
)
.
Int32
()
if
e
!=
nil
{
...
...
orm/models_test.go
View file @
f6ad2cf8
...
...
@@ -78,40 +78,42 @@ func (e *SliceStringField) RawValue() interface{} {
var
_
Fielder
=
new
(
SliceStringField
)
// A json field.
type
JSONField
struct
{
type
JSONField
Test
struct
{
Name
string
Data
string
}
func
(
e
*
JSONField
)
String
()
string
{
func
(
e
*
JSONField
Test
)
String
()
string
{
data
,
_
:=
json
.
Marshal
(
e
)
return
string
(
data
)
}
func
(
e
*
JSONField
)
FieldType
()
int
{
func
(
e
*
JSONField
Test
)
FieldType
()
int
{
return
TypeTextField
}
func
(
e
*
JSONField
)
SetRaw
(
value
interface
{})
error
{
func
(
e
*
JSONField
Test
)
SetRaw
(
value
interface
{})
error
{
switch
d
:=
value
.
(
type
)
{
case
string
:
return
json
.
Unmarshal
([]
byte
(
d
),
e
)
default
:
return
fmt
.
Errorf
(
"<J
son
Field.SetRaw> unknown value `%v`"
,
value
)
return
fmt
.
Errorf
(
"<J
SON
Field.SetRaw> unknown value `%v`"
,
value
)
}
}
func
(
e
*
JSONField
)
RawValue
()
interface
{}
{
func
(
e
*
JSONField
Test
)
RawValue
()
interface
{}
{
return
e
.
String
()
}
var
_
Fielder
=
new
(
JSONField
)
var
_
Fielder
=
new
(
JSONField
Test
)
type
Data
struct
{
ID
int
`orm:"column(id)"`
Boolean
bool
Char
string
`orm:"size(50)"`
Text
string
`orm:"type(text)"`
JSON
string
`orm:"type(json);default({\"name\":\"json\"})"`
Jsonb
string
`orm:"type(jsonb)"`
Time
time
.
Time
`orm:"type(time)"`
Date
time
.
Time
`orm:"type(date)"`
DateTime
time
.
Time
`orm:"column(datetime)"`
...
...
@@ -137,6 +139,8 @@ type DataNull struct {
Boolean
bool
`orm:"null"`
Char
string
`orm:"null;size(50)"`
Text
string
`orm:"null;type(text)"`
JSON
string
`orm:"type(json);null"`
Jsonb
string
`orm:"type(jsonb);null"`
Time
time
.
Time
`orm:"null;type(time)"`
Date
time
.
Time
`orm:"null;type(date)"`
DateTime
time
.
Time
`orm:"null;column(datetime)"`
...
...
@@ -239,7 +243,7 @@ type User struct {
ShouldSkip
string
`orm:"-"`
Nums
int
Langs
SliceStringField
`orm:"size(100)"`
Extra
JSONField
`orm:"type(text)"`
Extra
JSONField
Test
`orm:"type(text)"`
unexport
bool
`orm:"-"`
unexportBool
bool
}
...
...
@@ -390,12 +394,12 @@ func NewInLineOneToOne() *InLineOneToOne {
}
type
IntegerPk
struct
{
I
d
int64
`orm:"pk"`
I
D
int64
`orm:"pk"`
Value
string
}
type
UintPk
struct
{
I
d
uint32
`orm:"pk"`
I
D
uint32
`orm:"pk"`
Name
string
}
...
...
orm/orm_test.go
View file @
f6ad2cf8
...
...
@@ -241,6 +241,8 @@ var DataValues = map[string]interface{}{
"Boolean"
:
true
,
"Char"
:
"char"
,
"Text"
:
"text"
,
"JSON"
:
`{"name":"json"}`
,
"Jsonb"
:
`{"name": "jsonb"}`
,
"Time"
:
time
.
Now
(),
"Date"
:
time
.
Now
(),
"DateTime"
:
time
.
Now
(),
...
...
@@ -266,6 +268,9 @@ func TestDataTypes(t *testing.T) {
ind
:=
reflect
.
Indirect
(
reflect
.
ValueOf
(
&
d
))
for
name
,
value
:=
range
DataValues
{
if
name
==
"JSON"
{
continue
}
e
:=
ind
.
FieldByName
(
name
)
e
.
Set
(
reflect
.
ValueOf
(
value
))
}
...
...
@@ -310,10 +315,18 @@ func TestNullDataTypes(t *testing.T) {
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
id
,
1
))
data
:=
`{"ok":1,"data":{"arr":[1,2],"msg":"gopher"}}`
d
=
DataNull
{
ID
:
1
,
JSON
:
data
}
num
,
err
:=
dORM
.
Update
(
&
d
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
num
,
1
))
d
=
DataNull
{
ID
:
1
}
err
=
dORM
.
Read
(
&
d
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
d
.
JSON
,
data
))
throwFail
(
t
,
AssertIs
(
d
.
NullBool
.
Valid
,
false
))
throwFail
(
t
,
AssertIs
(
d
.
NullString
.
Valid
,
false
))
throwFail
(
t
,
AssertIs
(
d
.
NullInt64
.
Valid
,
false
))
...
...
@@ -2014,9 +2027,9 @@ func TestInLineOneToOne(t *testing.T) {
func
TestIntegerPk
(
t
*
testing
.
T
)
{
its
:=
[]
IntegerPk
{
{
I
d
:
math
.
MinInt64
,
Value
:
"-"
},
{
I
d
:
0
,
Value
:
"0"
},
{
I
d
:
math
.
MaxInt64
,
Value
:
"+"
},
{
I
D
:
math
.
MinInt64
,
Value
:
"-"
},
{
I
D
:
0
,
Value
:
"0"
},
{
I
D
:
math
.
MaxInt64
,
Value
:
"+"
},
}
num
,
err
:=
dORM
.
InsertMulti
(
len
(
its
),
its
)
...
...
@@ -2024,7 +2037,7 @@ func TestIntegerPk(t *testing.T) {
throwFail
(
t
,
AssertIs
(
num
,
len
(
its
)))
for
_
,
intPk
:=
range
its
{
out
:=
IntegerPk
{
I
d
:
intPk
.
Id
}
out
:=
IntegerPk
{
I
D
:
intPk
.
ID
}
err
=
dORM
.
Read
(
&
out
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
out
.
Value
,
intPk
.
Value
))
...
...
@@ -2072,21 +2085,21 @@ func TestInsertAuto(t *testing.T) {
func
TestUintPk
(
t
*
testing
.
T
)
{
name
:=
"go"
u
:=
&
UintPk
{
I
d
:
8
,
I
D
:
8
,
Name
:
name
,
}
created
,
pk
,
err
:=
dORM
.
ReadOrCreate
(
u
,
"I
d
"
)
created
,
pk
,
err
:=
dORM
.
ReadOrCreate
(
u
,
"I
D
"
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
created
,
true
))
throwFail
(
t
,
AssertIs
(
u
.
Name
,
name
))
nu
:=
&
UintPk
{
I
d
:
8
}
created
,
pk
,
err
=
dORM
.
ReadOrCreate
(
nu
,
"I
d
"
)
nu
:=
&
UintPk
{
I
D
:
8
}
created
,
pk
,
err
=
dORM
.
ReadOrCreate
(
nu
,
"I
D
"
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
created
,
false
))
throwFail
(
t
,
AssertIs
(
nu
.
I
d
,
u
.
Id
))
throwFail
(
t
,
AssertIs
(
pk
,
u
.
I
d
))
throwFail
(
t
,
AssertIs
(
nu
.
I
D
,
u
.
ID
))
throwFail
(
t
,
AssertIs
(
pk
,
u
.
I
D
))
throwFail
(
t
,
AssertIs
(
nu
.
Name
,
name
))
dORM
.
Delete
(
u
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
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 comment