1977d87d by benlovell

Merge branch 'master' of https://github.com/astaxie/beego into spelling

2 parents 9cbefacf 42f1d1ae
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
13 "time" 13 "time"
14 ) 14 )
15 15
16 const VERSION = "0.8.0" 16 const VERSION = "0.9.0"
17 17
18 var ( 18 var (
19 BeeApp *App 19 BeeApp *App
......
1 # beego orm 1 # beego orm
2 2
3 a powerful orm framework 3 [![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest)
4
5 A powerful orm framework for go.
6
7 It is heavily influenced by Django ORM, SQLAlchemy.
4 8
5 now, beta, unstable, may be changing some api make your app build failed. 9 now, beta, unstable, may be changing some api make your app build failed.
6 10
...@@ -14,12 +18,25 @@ Passed all test, but need more feedback. ...@@ -14,12 +18,25 @@ Passed all test, but need more feedback.
14 18
15 **Features:** 19 **Features:**
16 20
17 ... 21 * full go type support
22 * easy for usage, simple CRUD operation
23 * auto join with relation table
24 * cross DataBase compatible query
25 * Raw SQL query / mapper without orm model
26 * full test keep stable and strong
27
28 more features please read the docs
18 29
19 **Install:** 30 **Install:**
20 31
21 go get github.com/astaxie/beego/orm 32 go get github.com/astaxie/beego/orm
22 33
34 ## Changelog
35
36 * 2013-08-13: update test for database types
37 * 2013-08-13: go type support, such as int8, uint8, byte, rune
38 * 2013-08-13: date / datetime timezone support very well
39
23 ## Quick Start 40 ## Quick Start
24 41
25 #### Simple Usage 42 #### Simple Usage
...@@ -143,5 +160,3 @@ more details and examples in docs and test ...@@ -143,5 +160,3 @@ more details and examples in docs and test
143 - some unrealized api 160 - some unrealized api
144 - examples 161 - examples
145 - docs 162 - docs
146
147 ##
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
5 "fmt" 5 "fmt"
6 "os" 6 "os"
7 "sync" 7 "sync"
8 "time"
8 ) 9 )
9 10
10 const defaultMaxIdle = 30 11 const defaultMaxIdle = 30
...@@ -82,6 +83,7 @@ type alias struct { ...@@ -82,6 +83,7 @@ type alias struct {
82 MaxIdle int 83 MaxIdle int
83 DB *sql.DB 84 DB *sql.DB
84 DbBaser dbBaser 85 DbBaser dbBaser
86 TZ *time.Location
85 } 87 }
86 88
87 func RegisterDataBase(name, driverName, dataSource string, maxIdle int) { 89 func RegisterDataBase(name, driverName, dataSource string, maxIdle int) {
...@@ -120,6 +122,33 @@ func RegisterDataBase(name, driverName, dataSource string, maxIdle int) { ...@@ -120,6 +122,33 @@ func RegisterDataBase(name, driverName, dataSource string, maxIdle int) {
120 122
121 al.DB.SetMaxIdleConns(al.MaxIdle) 123 al.DB.SetMaxIdleConns(al.MaxIdle)
122 124
125 // orm timezone system match database
126 // default use Local
127 al.TZ = time.Local
128
129 switch al.Driver {
130 case DR_MySQL:
131 row := al.DB.QueryRow("SELECT @@session.time_zone")
132 var tz string
133 row.Scan(&tz)
134 if tz != "SYSTEM" {
135 t, err := time.Parse("-07:00", tz)
136 if err == nil {
137 al.TZ = t.Location()
138 }
139 }
140 case DR_Sqlite:
141 al.TZ = time.UTC
142 case DR_Postgres:
143 row := al.DB.QueryRow("SELECT current_setting('TIMEZONE')")
144 var tz string
145 row.Scan(&tz)
146 loc, err := time.LoadLocation(tz)
147 if err == nil {
148 al.TZ = loc
149 }
150 }
151
123 err = al.DB.Ping() 152 err = al.DB.Ping()
124 if err != nil { 153 if err != nil {
125 err = fmt.Errorf("register db `%s`, %s", name, err.Error()) 154 err = fmt.Errorf("register db `%s`, %s", name, err.Error())
...@@ -133,13 +162,22 @@ end: ...@@ -133,13 +162,22 @@ end:
133 } 162 }
134 } 163 }
135 164
136 func RegisterDriver(name string, typ DriverType) { 165 func RegisterDriver(driverName string, typ DriverType) {
137 if t, ok := drivers[name]; ok == false { 166 if t, ok := drivers[driverName]; ok == false {
138 drivers[name] = typ 167 drivers[driverName] = typ
139 } else { 168 } else {
140 if t != typ { 169 if t != typ {
141 fmt.Println("name `%s` db driver already registered and is other type") 170 fmt.Sprintf("driverName `%s` db driver already registered and is other type\n", driverName)
142 os.Exit(2) 171 os.Exit(2)
143 } 172 }
144 } 173 }
145 } 174 }
175
176 func SetDataBaseTZ(name string, tz *time.Location) {
177 if al, ok := dataBaseCache.get(name); ok {
178 al.TZ = tz
179 } else {
180 fmt.Sprintf("DataBase name `%s` not registered\n", name)
181 os.Exit(2)
182 }
183 }
......
...@@ -30,7 +30,7 @@ func (d *dbBasePostgres) OperatorSql(operator string) string { ...@@ -30,7 +30,7 @@ func (d *dbBasePostgres) OperatorSql(operator string) string {
30 return postgresOperators[operator] 30 return postgresOperators[operator]
31 } 31 }
32 32
33 func (d *dbBasePostgres) GenerateOperatorLeftCol(operator string, leftCol *string) { 33 func (d *dbBasePostgres) GenerateOperatorLeftCol(fi *fieldInfo, operator string, leftCol *string) {
34 switch operator { 34 switch operator {
35 case "contains", "startswith", "endswith": 35 case "contains", "startswith", "endswith":
36 *leftCol = fmt.Sprintf("%s::text", *leftCol) 36 *leftCol = fmt.Sprintf("%s::text", *leftCol)
......
1 package orm 1 package orm
2 2
3 import (
4 "fmt"
5 )
6
3 var sqliteOperators = map[string]string{ 7 var sqliteOperators = map[string]string{
4 "exact": "= ?", 8 "exact": "= ?",
5 "iexact": "LIKE ? ESCAPE '\\'", 9 "iexact": "LIKE ? ESCAPE '\\'",
...@@ -25,6 +29,12 @@ func (d *dbBaseSqlite) OperatorSql(operator string) string { ...@@ -25,6 +29,12 @@ func (d *dbBaseSqlite) OperatorSql(operator string) string {
25 return sqliteOperators[operator] 29 return sqliteOperators[operator]
26 } 30 }
27 31
32 func (d *dbBaseSqlite) GenerateOperatorLeftCol(fi *fieldInfo, operator string, leftCol *string) {
33 if fi.fieldType == TypeDateField {
34 *leftCol = fmt.Sprintf("DATE(%s)", *leftCol)
35 }
36 }
37
28 func (d *dbBaseSqlite) SupportUpdateJoin() bool { 38 func (d *dbBaseSqlite) SupportUpdateJoin() bool {
29 return false 39 return false
30 } 40 }
......
...@@ -3,6 +3,7 @@ package orm ...@@ -3,6 +3,7 @@ package orm
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "strings" 5 "strings"
6 "time"
6 ) 7 )
7 8
8 type dbTable struct { 9 type dbTable struct {
...@@ -266,7 +267,7 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string ...@@ -266,7 +267,7 @@ func (d *dbTables) parseExprs(mi *modelInfo, exprs []string) (index, name string
266 return 267 return
267 } 268 }
268 269
269 func (d *dbTables) getCondSql(cond *Condition, sub bool) (where string, params []interface{}) { 270 func (d *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (where string, params []interface{}) {
270 if cond == nil || cond.IsEmpty() { 271 if cond == nil || cond.IsEmpty() {
271 return 272 return
272 } 273 }
...@@ -288,7 +289,7 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool) (where string, params [ ...@@ -288,7 +289,7 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool) (where string, params [
288 where += "NOT " 289 where += "NOT "
289 } 290 }
290 if p.isCond { 291 if p.isCond {
291 w, ps := d.getCondSql(p.cond, true) 292 w, ps := d.getCondSql(p.cond, true, tz)
292 if w != "" { 293 if w != "" {
293 w = fmt.Sprintf("( %s) ", w) 294 w = fmt.Sprintf("( %s) ", w)
294 } 295 }
...@@ -313,10 +314,10 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool) (where string, params [ ...@@ -313,10 +314,10 @@ func (d *dbTables) getCondSql(cond *Condition, sub bool) (where string, params [
313 operator = "exact" 314 operator = "exact"
314 } 315 }
315 316
316 operSql, args := d.base.GenerateOperatorSql(mi, fi, operator, p.args) 317 operSql, args := d.base.GenerateOperatorSql(mi, fi, operator, p.args, tz)
317 318
318 leftCol := fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q) 319 leftCol := fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q)
319 d.base.GenerateOperatorLeftCol(operator, &leftCol) 320 d.base.GenerateOperatorLeftCol(fi, operator, &leftCol)
320 321
321 where += fmt.Sprintf("%s %s ", leftCol, operSql) 322 where += fmt.Sprintf("%s %s ", leftCol, operSql)
322 params = append(params, args...) 323 params = append(params, args...)
......
...@@ -24,7 +24,7 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac ...@@ -24,7 +24,7 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac
24 return 24 return
25 } 25 }
26 26
27 func getFlatParams(fi *fieldInfo, args []interface{}) (params []interface{}) { 27 func getFlatParams(fi *fieldInfo, args []interface{}, tz *time.Location) (params []interface{}) {
28 28
29 outFor: 29 outFor:
30 for _, arg := range args { 30 for _, arg := range args {
...@@ -39,9 +39,9 @@ outFor: ...@@ -39,9 +39,9 @@ outFor:
39 case []byte: 39 case []byte:
40 case time.Time: 40 case time.Time:
41 if fi != nil && fi.fieldType == TypeDateField { 41 if fi != nil && fi.fieldType == TypeDateField {
42 arg = v.Format(format_Date) 42 arg = v.In(DefaultTimeLoc).Format(format_Date)
43 } else { 43 } else {
44 arg = v.Format(format_DateTime) 44 arg = v.In(tz).Format(format_DateTime)
45 } 45 }
46 default: 46 default:
47 kind := val.Kind() 47 kind := val.Kind()
...@@ -65,7 +65,7 @@ outFor: ...@@ -65,7 +65,7 @@ outFor:
65 } 65 }
66 66
67 if len(args) > 0 { 67 if len(args) > 0 {
68 p := getFlatParams(fi, args) 68 p := getFlatParams(fi, args, tz)
69 params = append(params, p...) 69 params = append(params, p...)
70 } 70 }
71 continue outFor 71 continue outFor
......
...@@ -164,27 +164,91 @@ type Profile struct { ...@@ -164,27 +164,91 @@ type Profile struct {
164 ``` 164 ```
165 165
166 166
167 ## Struct Field 类型与数据库的对应 167 ## 模型字段与数据库类型的对应
168 168
169 现在 orm 支持下面的字段形式 169 在此列出 orm 推荐的对应数据库类型,自动建表功能也会以此为标准。
170 170
171 | go type | field type | mysql type 171 默认所有的字段都是 **NOT NULL**
172 | :--- | :--- | :--- 172
173 | bool | TypeBooleanField | tinyint 173 #### MySQL
174 | string | TypeCharField | varchar 174
175 | string | TypeTextField | longtext 175 | go |mysql
176 | time.Time | TypeDateField | date 176 | :--- | :---
177 | time.TIme | TypeDateTimeField | datetime 177 | bool | bool
178 | int16 |TypeSmallIntegerField | int(4) 178 | string - 设置 size 时 | varchar(size)
179 | int, int32 |TypeIntegerField | int(11) 179 | string | longtext
180 | int64 |TypeBigIntegerField | bigint(20) 180 | time.Time - 设置 type 为 date 时 | date
181 | uint, uint16 |TypePositiveSmallIntegerField | int(4) unsigned 181 | time.TIme | datetime
182 | uint32 |TypePositiveIntegerField | int(11) unsigned 182 | byte | tinyint unsigned
183 | uint64 |TypePositiveBigIntegerField | bigint(20) unsigned 183 | rune | integer
184 | float32, float64 | TypeFloatField | double 184 | int | integer
185 | float32, float64 | TypeDecimalField | double(digits, decimals) 185 | int8 | tinyint
186 186 | int16 | smallint
187 关系型的字段,其字段类型取决于对应的主键。 187 | int32 | integer
188 | int64 | bigint
189 | uint | integer unsigned
190 | uint8 | tinyint unsigned
191 | uint16 | smallint unsigned
192 | uint32 | integer unsigned
193 | uint64 | bigint unsigned
194 | float32 | double precision
195 | float64 | double precision
196 | float64 - 设置 digits, decimals 时 | numeric(digits, decimals)
197
198 #### Sqlite3
199
200 | go | sqlite3
201 | :--- | :---
202 | bool | bool
203 | string - 设置 size 时 | varchar(size)
204 | string | text
205 | time.Time - 设置 type 为 date 时 | date
206 | time.TIme | datetime
207 | byte | tinyint unsigned
208 | rune | integer
209 | int | integer
210 | int8 | tinyint
211 | int16 | smallint
212 | int32 | integer
213 | int64 | bigint
214 | uint | integer unsigned
215 | uint8 | tinyint unsigned
216 | uint16 | smallint unsigned
217 | uint32 | integer unsigned
218 | uint64 | bigint unsigned
219 | float32 | real
220 | float64 | real
221 | float64 - 设置 digits, decimals 时 | decimal
222
223 #### PostgreSQL
224
225 | go | postgres
226 | :--- | :---
227 | bool | bool
228 | string - 设置 size 时 | varchar(size)
229 | string | text
230 | time.Time - 设置 type 为 date 时 | date
231 | time.TIme | timestamp with time zone
232 | byte | smallint CHECK("column" >= 0 AND "column" <= 255)
233 | rune | integer
234 | int | integer
235 | int8 | smallint CHECK("column" >= -127 AND "column" <= 128)
236 | int16 | smallint
237 | int32 | integer
238 | int64 | bigint
239 | uint | bigint CHECK("column" >= 0)
240 | uint8 | smallint CHECK("column" >= 0 AND "column" <= 255)
241 | uint16 | integer CHECK("column" >= 0)
242 | uint32 | bigint CHECK("column" >= 0)
243 | uint64 | bigint CHECK("column" >= 0)
244 | float32 | double precision
245 | float64 | double precision
246 | float64 - 设置 digits, decimals 时 | numeric(digits, decimals)
247
248
249 ## 关系型字段
250
251 其字段类型取决于对应的主键。
188 252
189 * RelForeignKey 253 * RelForeignKey
190 * RelOneToOne 254 * RelOneToOne
......
...@@ -80,7 +80,7 @@ import ( ...@@ -80,7 +80,7 @@ import (
80 80
81 #### RegisterDriver 81 #### RegisterDriver
82 82
83 三种数据库类型 83 三种默认数据库类型
84 84
85 ```go 85 ```go
86 orm.DR_MySQL 86 orm.DR_MySQL
...@@ -93,7 +93,7 @@ orm.DR_Postgres ...@@ -93,7 +93,7 @@ orm.DR_Postgres
93 // 参数2 数据库类型 93 // 参数2 数据库类型
94 // 这个用来设置 driverName 对应的数据库类型 94 // 这个用来设置 driverName 对应的数据库类型
95 // mysql / sqlite3 / postgres 这三种是默认已经注册过的,所以可以无需设置 95 // mysql / sqlite3 / postgres 这三种是默认已经注册过的,所以可以无需设置
96 orm.RegisterDriver("mysql", orm.DR_MySQL) 96 orm.RegisterDriver("mymysql", orm.DR_MySQL)
97 ``` 97 ```
98 98
99 #### RegisterDataBase 99 #### RegisterDataBase
...@@ -108,6 +108,56 @@ orm 必须注册一个名称为 `default` 的数据库,用以作为默认使 ...@@ -108,6 +108,56 @@ orm 必须注册一个名称为 `default` 的数据库,用以作为默认使
108 orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8", 30) 108 orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8", 30)
109 ``` 109 ```
110 110
111 #### 时区设置
112
113 orm 默认使用 time.Local 本地时区
114
115 * 作用于 orm 自动创建的时间
116 * 从数据库中取回的时间转换成 orm 本地时间
117
118 如果需要的话,你也可以进行更改
119
120 ```go
121 // 设置为 UTC 时间
122 orm.DefaultTimeLoc = time.UTC
123 ```
124
125 orm 在进行 RegisterDataBase 的同时,会获取数据库使用的时区,然后在 time.Time 类型存取的时做相应转换,以匹配时间系统,从而保证时间不会出错。
126
127 **注意:** 鉴于 Sqlite3 的设计,存取默认都为 UTC 时间
128
129 ## RegisterModel
130
131 如果使用 orm.QuerySeter 进行高级查询的话,这个是必须的。
132
133 反之,如果只使用 Raw 查询和 map struct,是无需这一步的。您可以去查看 [Raw SQL 查询](Raw.md)
134
135 将你定义的 Model 进行注册,最佳设计是有单独的 models.go 文件,在他的 init 函数中进行注册。
136
137
138 迷你版 models.go
139 ```go
140 package main
141
142 import "github.com/astaxie/beego/orm"
143
144 type User struct {
145 Id int `orm:"auto"`
146 name string
147 }
148
149 func init(){
150 orm.RegisterModel(new(User))
151 }
152 ```
153
154 RegisterModel 也可以同时注册多个 model
155
156 ```go
157 orm.RegisterModel(new(User), new(Profile), new(Post))
158 ```
159
160
111 ## ORM 接口使用 161 ## ORM 接口使用
112 162
113 使用 orm 必然接触的 Ormer 接口,我们来熟悉一下 163 使用 orm 必然接触的 Ormer 接口,我们来熟悉一下
......
...@@ -15,7 +15,7 @@ qs = o.QueryTable(user) // 返回 QuerySeter ...@@ -15,7 +15,7 @@ qs = o.QueryTable(user) // 返回 QuerySeter
15 ``` 15 ```
16 ## expr 16 ## expr
17 17
18 QuerySeter 中用于描述字段和 sql 操作符使用简单的 expr 查询方法 18 QuerySeter 中用于描述字段和 sql 操作符使用简单的 expr 查询方法
19 19
20 字段组合的前后顺序依照表的关系,比如 User 表拥有 Profile 的外键,那么对 User 表查询对应的 Profile.Age 为条件,则使用 `Profile__Age` 注意,字段的分隔符号使用双下划线 `__`,除了描述字段, expr 的尾部可以增加操作符以执行对应的 sql 操作。比如 `Profile__Age__gt` 代表 Profile.Age > 18 的条件查询。 20 字段组合的前后顺序依照表的关系,比如 User 表拥有 Profile 的外键,那么对 User 表查询对应的 Profile.Age 为条件,则使用 `Profile__Age` 注意,字段的分隔符号使用双下划线 `__`,除了描述字段, expr 的尾部可以增加操作符以执行对应的 sql 操作。比如 `Profile__Age__gt` 代表 Profile.Age > 18 的条件查询。
21 21
......
1 ## 文档目录 1 ## 文档目录
2 2
3
4 1. [Orm 使用方法](Orm.md) 3 1. [Orm 使用方法](Orm.md)
5 - [数据库的设置](Orm.md#数据库的设置) 4 - [数据库的设置](Orm.md#数据库的设置)
5 * [驱动类型设置](Orm.md#registerdriver)
6 * [参数设置](Orm.md#registerdataBase)
7 * [时区设置](Orm.md#时区设置)
8 - [注册 ORM 使用的模型](Orm.md#registermodel)
6 - [ORM 接口使用](Orm.md#orm-接口使用) 9 - [ORM 接口使用](Orm.md#orm-接口使用)
7 - [调试模式打印查询语句](Orm.md#调试模式打印查询语句) 10 - [调试模式打印查询语句](Orm.md#调试模式打印查询语句)
8 2. [对象的CRUD操作](Object.md) 11 2. [对象的CRUD操作](Object.md)
...@@ -15,6 +18,12 @@ ...@@ -15,6 +18,12 @@
15 6. [模型定义](Models.md) 18 6. [模型定义](Models.md)
16 - [Struct Tag 设置参数](Models.md#struct-tag-设置参数) 19 - [Struct Tag 设置参数](Models.md#struct-tag-设置参数)
17 - [表关系设置](Models.md#表关系设置) 20 - [表关系设置](Models.md#表关系设置)
18 - [Struct Field 类型与数据库的对应](Models.md#struct-field-类型与数据库的对应) 21 - [模型字段与数据库类型的对应](Models.md#模型字段与数据库类型的对应)
19 7. Custom Fields 22 7. Custom Fields
20 8. Faq 23 8. Faq
24
25
26 ### 文档更新记录
27
28 * 2013-08-13: ORM 的 [时区设置](Orm.md#时区设置)
29 * 2013-08-13: [模型字段与数据库类型的对应](Models.md#模型字段与数据库类型的对应) 推荐的数据库对应使用的类型
......
...@@ -22,12 +22,16 @@ const ( ...@@ -22,12 +22,16 @@ const (
22 // time.Time 22 // time.Time
23 TypeDateTimeField 23 TypeDateTimeField
24 24
25 // int8
26 TypeBitField
25 // int16 27 // int16
26 TypeSmallIntegerField 28 TypeSmallIntegerField
27 // int32 29 // int32
28 TypeIntegerField 30 TypeIntegerField
29 // int64 31 // int64
30 TypeBigIntegerField 32 TypeBigIntegerField
33 // uint8
34 TypePostiveBitField
31 // uint16 35 // uint16
32 TypePositiveSmallIntegerField 36 TypePositiveSmallIntegerField
33 // uint32 37 // uint32
...@@ -49,8 +53,8 @@ const ( ...@@ -49,8 +53,8 @@ const (
49 53
50 const ( 54 const (
51 IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 55 IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5
52 IsPostiveIntegerField = ^-TypePositiveBigIntegerField >> 7 << 8 56 IsPostiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9
53 IsRelField = ^-RelReverseMany >> 12 << 13 57 IsRelField = ^-RelReverseMany >> 14 << 15
54 IsFieldType = ^-RelReverseMany<<1 + 1 58 IsFieldType = ^-RelReverseMany<<1 + 1
55 ) 59 )
56 60
......
...@@ -327,8 +327,8 @@ checkType: ...@@ -327,8 +327,8 @@ checkType:
327 case TypeDecimalField: 327 case TypeDecimalField:
328 d1 := digits 328 d1 := digits
329 d2 := decimals 329 d2 := decimals
330 v1, er1 := StrTo(d1).Int16() 330 v1, er1 := StrTo(d1).Int8()
331 v2, er2 := StrTo(d2).Int16() 331 v2, er2 := StrTo(d2).Int8()
332 if er1 != nil || er2 != nil { 332 if er1 != nil || er2 != nil {
333 err = fmt.Errorf("wrong digits/decimals value %s/%s", d2, d1) 333 err = fmt.Errorf("wrong digits/decimals value %s/%s", d2, d1)
334 goto end 334 goto end
...@@ -383,12 +383,16 @@ checkType: ...@@ -383,12 +383,16 @@ checkType:
383 _, err = v.Bool() 383 _, err = v.Bool()
384 case TypeFloatField, TypeDecimalField: 384 case TypeFloatField, TypeDecimalField:
385 _, err = v.Float64() 385 _, err = v.Float64()
386 case TypeBitField:
387 _, err = v.Int8()
386 case TypeSmallIntegerField: 388 case TypeSmallIntegerField:
387 _, err = v.Int16() 389 _, err = v.Int16()
388 case TypeIntegerField: 390 case TypeIntegerField:
389 _, err = v.Int32() 391 _, err = v.Int32()
390 case TypeBigIntegerField: 392 case TypeBigIntegerField:
391 _, err = v.Int64() 393 _, err = v.Int64()
394 case TypePostiveBitField:
395 _, err = v.Uint8()
392 case TypePositiveSmallIntegerField: 396 case TypePositiveSmallIntegerField:
393 _, err = v.Uint16() 397 _, err = v.Uint16()
394 case TypePositiveIntegerField: 398 case TypePositiveIntegerField:
......
...@@ -6,11 +6,60 @@ import ( ...@@ -6,11 +6,60 @@ import (
6 "strings" 6 "strings"
7 "time" 7 "time"
8 8
9 // _ "github.com/bylevel/pq"
9 _ "github.com/go-sql-driver/mysql" 10 _ "github.com/go-sql-driver/mysql"
10 _ "github.com/lib/pq" 11 _ "github.com/lib/pq"
11 _ "github.com/mattn/go-sqlite3" 12 _ "github.com/mattn/go-sqlite3"
12 ) 13 )
13 14
15 type Data struct {
16 Id int `orm:"auto"`
17 Boolean bool
18 Char string `orm:"size(50)"`
19 Text string
20 Date time.Time `orm:"type(date)"`
21 DateTime time.Time
22 Byte byte
23 Rune rune
24 Int int
25 Int8 int8
26 Int16 int16
27 Int32 int32
28 Int64 int64
29 Uint uint
30 Uint8 uint8
31 Uint16 uint16
32 Uint32 uint32
33 Uint64 uint64
34 Float32 float32
35 Float64 float64
36 Decimal float64 `orm:"digits(8);decimals(4)"`
37 }
38
39 type DataNull struct {
40 Id int `orm:"auto"`
41 Boolean bool `orm:"null"`
42 Char string `orm:"size(50);null"`
43 Text string `orm:"null"`
44 Date time.Time `orm:"type(date);null"`
45 DateTime time.Time `orm:"null"`
46 Byte byte `orm:"null"`
47 Rune rune `orm:"null"`
48 Int int `orm:"null"`
49 Int8 int8 `orm:"null"`
50 Int16 int16 `orm:"null"`
51 Int32 int32 `orm:"null"`
52 Int64 int64 `orm:"null"`
53 Uint uint `orm:"null"`
54 Uint8 uint8 `orm:"null"`
55 Uint16 uint16 `orm:"null"`
56 Uint32 uint32 `orm:"null"`
57 Uint64 uint64 `orm:"null"`
58 Float32 float32 `orm:"null"`
59 Float64 float64 `orm:"null"`
60 Decimal float64 `orm:"digits(8);decimals(4);null"`
61 }
62
14 type User struct { 63 type User struct {
15 Id int `orm:"auto"` 64 Id int `orm:"auto"`
16 UserName string `orm:"size(30);unique"` 65 UserName string `orm:"size(30);unique"`
...@@ -111,6 +160,8 @@ var initSQLs = map[string]string{ ...@@ -111,6 +160,8 @@ var initSQLs = map[string]string{
111 "DROP TABLE IF EXISTS `tag`;\n" + 160 "DROP TABLE IF EXISTS `tag`;\n" +
112 "DROP TABLE IF EXISTS `post_tags`;\n" + 161 "DROP TABLE IF EXISTS `post_tags`;\n" +
113 "DROP TABLE IF EXISTS `comment`;\n" + 162 "DROP TABLE IF EXISTS `comment`;\n" +
163 "DROP TABLE IF EXISTS `data`;\n" +
164 "DROP TABLE IF EXISTS `data_null`;\n" +
114 "CREATE TABLE `user_profile` (\n" + 165 "CREATE TABLE `user_profile` (\n" +
115 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" + 166 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
116 " `age` smallint NOT NULL,\n" + 167 " `age` smallint NOT NULL,\n" +
...@@ -153,6 +204,52 @@ var initSQLs = map[string]string{ ...@@ -153,6 +204,52 @@ var initSQLs = map[string]string{
153 " `parent_id` integer,\n" + 204 " `parent_id` integer,\n" +
154 " `created` datetime NOT NULL\n" + 205 " `created` datetime NOT NULL\n" +
155 ") ENGINE=INNODB;\n" + 206 ") ENGINE=INNODB;\n" +
207 "CREATE TABLE `data` (\n" +
208 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
209 " `boolean` bool NOT NULL,\n" +
210 " `char` varchar(50) NOT NULL,\n" +
211 " `text` longtext NOT NULL,\n" +
212 " `date` date NOT NULL,\n" +
213 " `date_time` datetime NOT NULL,\n" +
214 " `byte` tinyint unsigned NOT NULL,\n" +
215 " `rune` integer NOT NULL,\n" +
216 " `int` integer NOT NULL,\n" +
217 " `int8` tinyint NOT NULL,\n" +
218 " `int16` smallint NOT NULL,\n" +
219 " `int32` integer NOT NULL,\n" +
220 " `int64` bigint NOT NULL,\n" +
221 " `uint` integer unsigned NOT NULL,\n" +
222 " `uint8` tinyint unsigned NULL,\n" +
223 " `uint16` smallint unsigned NOT NULL,\n" +
224 " `uint32` integer unsigned NOT NULL,\n" +
225 " `uint64` bigint unsigned NOT NULL,\n" +
226 " `float32` double precision NOT NULL,\n" +
227 " `float64` double precision NOT NULL,\n" +
228 " `decimal` numeric(8,4) NOT NULL\n" +
229 ") ENGINE=INNODB;\n" +
230 "CREATE TABLE `data_null` (\n" +
231 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
232 " `boolean` bool,\n" +
233 " `char` varchar(50),\n" +
234 " `text` longtext,\n" +
235 " `date` date,\n" +
236 " `date_time` datetime,\n" +
237 " `byte` tinyint unsigned,\n" +
238 " `rune` integer,\n" +
239 " `int` integer,\n" +
240 " `int8` tinyint,\n" +
241 " `int16` smallint,\n" +
242 " `int32` integer,\n" +
243 " `int64` bigint,\n" +
244 " `uint` integer unsigned,\n" +
245 " `uint8` tinyint unsigned,\n" +
246 " `uint16` smallint unsigned,\n" +
247 " `uint32` integer unsigned,\n" +
248 " `uint64` bigint unsigned,\n" +
249 " `float32` double precision,\n" +
250 " `float64` double precision,\n" +
251 " `decimal` numeric(8,4)\n" +
252 ") ENGINE=INNODB;\n" +
156 "CREATE INDEX `user_141c6eec` ON `user` (`profile_id`);\n" + 253 "CREATE INDEX `user_141c6eec` ON `user` (`profile_id`);\n" +
157 "CREATE INDEX `post_fbfc09f1` ON `post` (`user_id`);\n" + 254 "CREATE INDEX `post_fbfc09f1` ON `post` (`user_id`);\n" +
158 "CREATE INDEX `comment_699ae8ca` ON `comment` (`post_id`);\n" + 255 "CREATE INDEX `comment_699ae8ca` ON `comment` (`post_id`);\n" +
...@@ -165,6 +262,8 @@ DROP TABLE IF EXISTS "post"; ...@@ -165,6 +262,8 @@ DROP TABLE IF EXISTS "post";
165 DROP TABLE IF EXISTS "tag"; 262 DROP TABLE IF EXISTS "tag";
166 DROP TABLE IF EXISTS "post_tags"; 263 DROP TABLE IF EXISTS "post_tags";
167 DROP TABLE IF EXISTS "comment"; 264 DROP TABLE IF EXISTS "comment";
265 DROP TABLE IF EXISTS "data";
266 DROP TABLE IF EXISTS "data_null";
168 CREATE TABLE "user_profile" ( 267 CREATE TABLE "user_profile" (
169 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 268 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
170 "age" smallint NOT NULL, 269 "age" smallint NOT NULL,
...@@ -207,6 +306,52 @@ CREATE TABLE "comment" ( ...@@ -207,6 +306,52 @@ CREATE TABLE "comment" (
207 "parent_id" integer, 306 "parent_id" integer,
208 "created" datetime NOT NULL 307 "created" datetime NOT NULL
209 ); 308 );
309 CREATE TABLE "data" (
310 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
311 "boolean" bool NOT NULL,
312 "char" varchar(50) NOT NULL,
313 "text" text NOT NULL,
314 "date" date NOT NULL,
315 "date_time" datetime NOT NULL,
316 "byte" tinyint unsigned NOT NULL,
317 "rune" integer NOT NULL,
318 "int" integer NOT NULL,
319 "int8" tinyint NOT NULL,
320 "int16" smallint NOT NULL,
321 "int32" integer NOT NULL,
322 "int64" bigint NOT NULL,
323 "uint" integer unsigned NOT NULL,
324 "uint8" tinyint unsigned NOT NULL,
325 "uint16" smallint unsigned NOT NULL,
326 "uint32" integer unsigned NOT NULL,
327 "uint64" bigint unsigned NOT NULL,
328 "float32" real NOT NULL,
329 "float64" real NOT NULL,
330 "decimal" decimal
331 );
332 CREATE TABLE "data_null" (
333 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
334 "boolean" bool,
335 "char" varchar(50),
336 "text" text,
337 "date" date,
338 "date_time" datetime,
339 "byte" tinyint unsigned,
340 "rune" integer,
341 "int" integer,
342 "int8" tinyint,
343 "int16" smallint,
344 "int32" integer,
345 "int64" bigint,
346 "uint" integer unsigned,
347 "uint8" tinyint unsigned,
348 "uint16" smallint unsigned,
349 "uint32" integer unsigned,
350 "uint64" bigint unsigned,
351 "float32" real,
352 "float64" real,
353 "decimal" decimal
354 );
210 CREATE INDEX "user_141c6eec" ON "user" ("profile_id"); 355 CREATE INDEX "user_141c6eec" ON "user" ("profile_id");
211 CREATE INDEX "post_fbfc09f1" ON "post" ("user_id"); 356 CREATE INDEX "post_fbfc09f1" ON "post" ("user_id");
212 CREATE INDEX "comment_699ae8ca" ON "comment" ("post_id"); 357 CREATE INDEX "comment_699ae8ca" ON "comment" ("post_id");
...@@ -220,6 +365,8 @@ DROP TABLE IF EXISTS "post"; ...@@ -220,6 +365,8 @@ DROP TABLE IF EXISTS "post";
220 DROP TABLE IF EXISTS "tag"; 365 DROP TABLE IF EXISTS "tag";
221 DROP TABLE IF EXISTS "post_tags"; 366 DROP TABLE IF EXISTS "post_tags";
222 DROP TABLE IF EXISTS "comment"; 367 DROP TABLE IF EXISTS "comment";
368 DROP TABLE IF EXISTS "data";
369 DROP TABLE IF EXISTS "data_null";
223 CREATE TABLE "user_profile" ( 370 CREATE TABLE "user_profile" (
224 "id" serial NOT NULL PRIMARY KEY, 371 "id" serial NOT NULL PRIMARY KEY,
225 "age" smallint NOT NULL, 372 "age" smallint NOT NULL,
...@@ -262,6 +409,52 @@ CREATE TABLE "comment" ( ...@@ -262,6 +409,52 @@ CREATE TABLE "comment" (
262 "parent_id" integer, 409 "parent_id" integer,
263 "created" timestamp with time zone NOT NULL 410 "created" timestamp with time zone NOT NULL
264 ); 411 );
412 CREATE TABLE "data" (
413 "id" serial NOT NULL PRIMARY KEY,
414 "boolean" bool NOT NULL,
415 "char" varchar(50) NOT NULL,
416 "text" text NOT NULL,
417 "date" date NOT NULL,
418 "date_time" timestamp with time zone NOT NULL,
419 "byte" smallint CHECK("byte" >= 0 AND "byte" <= 255) NOT NULL,
420 "rune" integer NOT NULL,
421 "int" integer NOT NULL,
422 "int8" smallint CHECK("int8" >= -127 AND "int8" <= 128) NOT NULL,
423 "int16" smallint NOT NULL,
424 "int32" integer NOT NULL,
425 "int64" bigint NOT NULL,
426 "uint" bigint CHECK("uint" >= 0) NOT NULL,
427 "uint8" smallint CHECK("uint8" >= 0 AND "uint8" <= 255) NOT NULL,
428 "uint16" integer CHECK("uint16" >= 0) NOT NULL,
429 "uint32" bigint CHECK("uint32" >= 0) NOT NULL,
430 "uint64" bigint CHECK("uint64" >= 0) NOT NULL,
431 "float32" double precision NOT NULL,
432 "float64" double precision NOT NULL,
433 "decimal" numeric(8, 4)
434 );
435 CREATE TABLE "data_null" (
436 "id" serial NOT NULL PRIMARY KEY,
437 "boolean" bool,
438 "char" varchar(50),
439 "text" text,
440 "date" date,
441 "date_time" timestamp with time zone,
442 "byte" smallint CHECK("byte" >= 0 AND "byte" <= 255),
443 "rune" integer,
444 "int" integer,
445 "int8" smallint CHECK("int8" >= -127 AND "int8" <= 128),
446 "int16" smallint,
447 "int32" integer,
448 "int64" bigint,
449 "uint" bigint CHECK("uint" >= 0),
450 "uint8" smallint CHECK("uint8" >= 0 AND "uint8" <= 255),
451 "uint16" integer CHECK("uint16" >= 0),
452 "uint32" bigint CHECK("uint32" >= 0),
453 "uint64" bigint CHECK("uint64" >= 0),
454 "float32" double precision,
455 "float64" double precision,
456 "decimal" numeric(8, 4)
457 );
265 CREATE INDEX "user_profile_id" ON "user" ("profile_id"); 458 CREATE INDEX "user_profile_id" ON "user" ("profile_id");
266 CREATE INDEX "post_user_id" ON "post" ("user_id"); 459 CREATE INDEX "post_user_id" ON "post" ("user_id");
267 CREATE INDEX "comment_post_id" ON "comment" ("post_id"); 460 CREATE INDEX "comment_post_id" ON "comment" ("post_id");
...@@ -269,6 +462,10 @@ CREATE INDEX "comment_parent_id" ON "comment" ("parent_id"); ...@@ -269,6 +462,10 @@ CREATE INDEX "comment_parent_id" ON "comment" ("parent_id");
269 `} 462 `}
270 463
271 func init() { 464 func init() {
465 // err := os.Setenv("TZ", "+00:00")
466 // fmt.Println(err)
467
468 RegisterModel(new(Data), new(DataNull))
272 RegisterModel(new(User)) 469 RegisterModel(new(User))
273 RegisterModel(new(Profile)) 470 RegisterModel(new(Profile))
274 RegisterModel(new(Post)) 471 RegisterModel(new(Post))
......
...@@ -43,15 +43,19 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col ...@@ -43,15 +43,19 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col
43 func getFieldType(val reflect.Value) (ft int, err error) { 43 func getFieldType(val reflect.Value) (ft int, err error) {
44 elm := reflect.Indirect(val) 44 elm := reflect.Indirect(val)
45 switch elm.Kind() { 45 switch elm.Kind() {
46 case reflect.Int8:
47 ft = TypeBitField
46 case reflect.Int16: 48 case reflect.Int16:
47 ft = TypeSmallIntegerField 49 ft = TypeSmallIntegerField
48 case reflect.Int32, reflect.Int: 50 case reflect.Int32, reflect.Int:
49 ft = TypeIntegerField 51 ft = TypeIntegerField
50 case reflect.Int64: 52 case reflect.Int64:
51 ft = TypeBigIntegerField 53 ft = TypeBigIntegerField
54 case reflect.Uint8:
55 ft = TypePostiveBitField
52 case reflect.Uint16: 56 case reflect.Uint16:
53 ft = TypePositiveSmallIntegerField 57 ft = TypePositiveSmallIntegerField
54 case reflect.Uint32: 58 case reflect.Uint32, reflect.Uint:
55 ft = TypePositiveIntegerField 59 ft = TypePositiveIntegerField
56 case reflect.Uint64: 60 case reflect.Uint64:
57 ft = TypePositiveBigIntegerField 61 ft = TypePositiveBigIntegerField
......
...@@ -55,7 +55,7 @@ func (o *orm) getMiInd(md interface{}) (mi *modelInfo, ind reflect.Value) { ...@@ -55,7 +55,7 @@ func (o *orm) getMiInd(md interface{}) (mi *modelInfo, ind reflect.Value) {
55 55
56 func (o *orm) Read(md interface{}) error { 56 func (o *orm) Read(md interface{}) error {
57 mi, ind := o.getMiInd(md) 57 mi, ind := o.getMiInd(md)
58 err := o.alias.DbBaser.Read(o.db, mi, ind) 58 err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ)
59 if err != nil { 59 if err != nil {
60 return err 60 return err
61 } 61 }
...@@ -64,7 +64,7 @@ func (o *orm) Read(md interface{}) error { ...@@ -64,7 +64,7 @@ func (o *orm) Read(md interface{}) error {
64 64
65 func (o *orm) Insert(md interface{}) (int64, error) { 65 func (o *orm) Insert(md interface{}) (int64, error) {
66 mi, ind := o.getMiInd(md) 66 mi, ind := o.getMiInd(md)
67 id, err := o.alias.DbBaser.Insert(o.db, mi, ind) 67 id, err := o.alias.DbBaser.Insert(o.db, mi, ind, o.alias.TZ)
68 if err != nil { 68 if err != nil {
69 return id, err 69 return id, err
70 } 70 }
...@@ -78,7 +78,7 @@ func (o *orm) Insert(md interface{}) (int64, error) { ...@@ -78,7 +78,7 @@ func (o *orm) Insert(md interface{}) (int64, error) {
78 78
79 func (o *orm) Update(md interface{}) (int64, error) { 79 func (o *orm) Update(md interface{}) (int64, error) {
80 mi, ind := o.getMiInd(md) 80 mi, ind := o.getMiInd(md)
81 num, err := o.alias.DbBaser.Update(o.db, mi, ind) 81 num, err := o.alias.DbBaser.Update(o.db, mi, ind, o.alias.TZ)
82 if err != nil { 82 if err != nil {
83 return num, err 83 return num, err
84 } 84 }
...@@ -87,7 +87,7 @@ func (o *orm) Update(md interface{}) (int64, error) { ...@@ -87,7 +87,7 @@ func (o *orm) Update(md interface{}) (int64, error) {
87 87
88 func (o *orm) Delete(md interface{}) (int64, error) { 88 func (o *orm) Delete(md interface{}) (int64, error) {
89 mi, ind := o.getMiInd(md) 89 mi, ind := o.getMiInd(md)
90 num, err := o.alias.DbBaser.Delete(o.db, mi, ind) 90 num, err := o.alias.DbBaser.Delete(o.db, mi, ind, o.alias.TZ)
91 if err != nil { 91 if err != nil {
92 return num, err 92 return num, err
93 } 93 }
......
...@@ -28,7 +28,7 @@ func (o *insertSet) Insert(md interface{}) (int64, error) { ...@@ -28,7 +28,7 @@ func (o *insertSet) Insert(md interface{}) (int64, error) {
28 if name != o.mi.fullName { 28 if name != o.mi.fullName {
29 panic(fmt.Sprintf("<Inserter.Insert> need model `%s` but found `%s`", o.mi.fullName, name)) 29 panic(fmt.Sprintf("<Inserter.Insert> need model `%s` but found `%s`", o.mi.fullName, name))
30 } 30 }
31 id, err := o.orm.alias.DbBaser.InsertStmt(o.stmt, o.mi, ind) 31 id, err := o.orm.alias.DbBaser.InsertStmt(o.stmt, o.mi, ind, o.orm.alias.TZ)
32 if err != nil { 32 if err != nil {
33 return id, err 33 return id, err
34 } 34 }
......
...@@ -77,15 +77,15 @@ func (o querySet) SetCond(cond *Condition) QuerySeter { ...@@ -77,15 +77,15 @@ func (o querySet) SetCond(cond *Condition) QuerySeter {
77 } 77 }
78 78
79 func (o *querySet) Count() (int64, error) { 79 func (o *querySet) Count() (int64, error) {
80 return o.orm.alias.DbBaser.Count(o.orm.db, o, o.mi, o.cond) 80 return o.orm.alias.DbBaser.Count(o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
81 } 81 }
82 82
83 func (o *querySet) Update(values Params) (int64, error) { 83 func (o *querySet) Update(values Params) (int64, error) {
84 return o.orm.alias.DbBaser.UpdateBatch(o.orm.db, o, o.mi, o.cond, values) 84 return o.orm.alias.DbBaser.UpdateBatch(o.orm.db, o, o.mi, o.cond, values, o.orm.alias.TZ)
85 } 85 }
86 86
87 func (o *querySet) Delete() (int64, error) { 87 func (o *querySet) Delete() (int64, error) {
88 return o.orm.alias.DbBaser.DeleteBatch(o.orm.db, o, o.mi, o.cond) 88 return o.orm.alias.DbBaser.DeleteBatch(o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
89 } 89 }
90 90
91 func (o *querySet) PrepareInsert() (Inserter, error) { 91 func (o *querySet) PrepareInsert() (Inserter, error) {
...@@ -93,11 +93,11 @@ func (o *querySet) PrepareInsert() (Inserter, error) { ...@@ -93,11 +93,11 @@ func (o *querySet) PrepareInsert() (Inserter, error) {
93 } 93 }
94 94
95 func (o *querySet) All(container interface{}) (int64, error) { 95 func (o *querySet) All(container interface{}) (int64, error) {
96 return o.orm.alias.DbBaser.ReadBatch(o.orm.db, o, o.mi, o.cond, container) 96 return o.orm.alias.DbBaser.ReadBatch(o.orm.db, o, o.mi, o.cond, container, o.orm.alias.TZ)
97 } 97 }
98 98
99 func (o *querySet) One(container interface{}) error { 99 func (o *querySet) One(container interface{}) error {
100 num, err := o.orm.alias.DbBaser.ReadBatch(o.orm.db, o, o.mi, o.cond, container) 100 num, err := o.orm.alias.DbBaser.ReadBatch(o.orm.db, o, o.mi, o.cond, container, o.orm.alias.TZ)
101 if err != nil { 101 if err != nil {
102 return err 102 return err
103 } 103 }
...@@ -111,15 +111,15 @@ func (o *querySet) One(container interface{}) error { ...@@ -111,15 +111,15 @@ func (o *querySet) One(container interface{}) error {
111 } 111 }
112 112
113 func (o *querySet) Values(results *[]Params, exprs ...string) (int64, error) { 113 func (o *querySet) Values(results *[]Params, exprs ...string) (int64, error) {
114 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, exprs, results) 114 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, exprs, results, o.orm.alias.TZ)
115 } 115 }
116 116
117 func (o *querySet) ValuesList(results *[]ParamsList, exprs ...string) (int64, error) { 117 func (o *querySet) ValuesList(results *[]ParamsList, exprs ...string) (int64, error) {
118 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, exprs, results) 118 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, exprs, results, o.orm.alias.TZ)
119 } 119 }
120 120
121 func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) { 121 func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) {
122 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, []string{expr}, result) 122 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, []string{expr}, result, o.orm.alias.TZ)
123 } 123 }
124 124
125 func newQuerySet(orm *orm, mi *modelInfo) QuerySeter { 125 func newQuerySet(orm *orm, mi *modelInfo) QuerySeter {
......
...@@ -60,7 +60,7 @@ func (o *rawSet) Exec() (sql.Result, error) { ...@@ -60,7 +60,7 @@ func (o *rawSet) Exec() (sql.Result, error) {
60 query := o.query 60 query := o.query
61 o.orm.alias.DbBaser.ReplaceMarks(&query) 61 o.orm.alias.DbBaser.ReplaceMarks(&query)
62 62
63 args := getFlatParams(nil, o.args) 63 args := getFlatParams(nil, o.args, o.orm.alias.TZ)
64 return o.orm.db.Exec(query, args...) 64 return o.orm.db.Exec(query, args...)
65 } 65 }
66 66
...@@ -96,7 +96,7 @@ func (o *rawSet) readValues(container interface{}) (int64, error) { ...@@ -96,7 +96,7 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
96 query := o.query 96 query := o.query
97 o.orm.alias.DbBaser.ReplaceMarks(&query) 97 o.orm.alias.DbBaser.ReplaceMarks(&query)
98 98
99 args := getFlatParams(nil, o.args) 99 args := getFlatParams(nil, o.args, o.orm.alias.TZ)
100 100
101 var rs *sql.Rows 101 var rs *sql.Rows
102 if r, err := o.orm.db.Query(query, args...); err != nil { 102 if r, err := o.orm.db.Query(query, args...); err != nil {
......
...@@ -15,6 +15,11 @@ import ( ...@@ -15,6 +15,11 @@ import (
15 15
16 var _ = os.PathSeparator 16 var _ = os.PathSeparator
17 17
18 var (
19 test_Date = format_Date + " -0700"
20 test_DateTime = format_DateTime + " -0700"
21 )
22
18 type T_Code int 23 type T_Code int
19 24
20 const ( 25 const (
...@@ -141,7 +146,7 @@ func getCaller(skip int) string { ...@@ -141,7 +146,7 @@ func getCaller(skip int) string {
141 if cur == line { 146 if cur == line {
142 flag = ">>" 147 flag = ">>"
143 } 148 }
144 code := fmt.Sprintf(" %s %5d: %s", flag, cur, strings.TrimSpace(string(lines[o+i]))) 149 code := fmt.Sprintf(" %s %5d: %s", flag, cur, strings.Replace(string(lines[o+i]), "\t", " ", -1))
145 if code != "" { 150 if code != "" {
146 codes = append(codes, code) 151 codes = append(codes, code)
147 } 152 }
...@@ -158,7 +163,11 @@ func throwFail(t *testing.T, err error, args ...interface{}) { ...@@ -158,7 +163,11 @@ func throwFail(t *testing.T, err error, args ...interface{}) {
158 if err != nil { 163 if err != nil {
159 con := fmt.Sprintf("\t\nError: %s\n%s\n", err.Error(), getCaller(2)) 164 con := fmt.Sprintf("\t\nError: %s\n%s\n", err.Error(), getCaller(2))
160 if len(args) > 0 { 165 if len(args) > 0 {
161 con += fmt.Sprint(args...) 166 parts := make([]string, 0, len(args))
167 for _, arg := range args {
168 parts = append(parts, fmt.Sprintf("%v", arg))
169 }
170 con += " " + strings.Join(parts, ", ")
162 } 171 }
163 t.Error(con) 172 t.Error(con)
164 t.Fail() 173 t.Fail()
...@@ -169,7 +178,11 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { ...@@ -169,7 +178,11 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) {
169 if err != nil { 178 if err != nil {
170 con := fmt.Sprintf("\t\nError: %s\n%s\n", err.Error(), getCaller(2)) 179 con := fmt.Sprintf("\t\nError: %s\n%s\n", err.Error(), getCaller(2))
171 if len(args) > 0 { 180 if len(args) > 0 {
172 con += fmt.Sprint(args...) 181 parts := make([]string, 0, len(args))
182 for _, arg := range args {
183 parts = append(parts, fmt.Sprintf("%v", arg))
184 }
185 con += " " + strings.Join(parts, ", ")
173 } 186 }
174 t.Error(con) 187 t.Error(con)
175 t.FailNow() 188 t.FailNow()
...@@ -177,13 +190,100 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { ...@@ -177,13 +190,100 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) {
177 } 190 }
178 191
179 func TestModelSyntax(t *testing.T) { 192 func TestModelSyntax(t *testing.T) {
180 mi, ok := modelCache.get("user") 193 user := &User{}
194 ind := reflect.ValueOf(user).Elem()
195 fn := getFullName(ind.Type())
196 mi, ok := modelCache.getByFN(fn)
197 throwFail(t, AssertIs(ok, T_Equal, true))
198
199 mi, ok = modelCache.get("user")
181 throwFail(t, AssertIs(ok, T_Equal, true)) 200 throwFail(t, AssertIs(ok, T_Equal, true))
182 if ok { 201 if ok {
183 throwFail(t, AssertIs(mi.fields.GetByName("ShouldSkip") == nil, T_Equal, true)) 202 throwFail(t, AssertIs(mi.fields.GetByName("ShouldSkip") == nil, T_Equal, true))
184 } 203 }
185 } 204 }
186 205
206 func TestDataTypes(t *testing.T) {
207 values := map[string]interface{}{
208 "Boolean": true,
209 "Char": "char",
210 "Text": "text",
211 "Date": time.Now(),
212 "DateTime": time.Now(),
213 "Byte": byte(1<<8 - 1),
214 "Rune": rune(1<<31 - 1),
215 "Int": int(1<<31 - 1),
216 "Int8": int8(1<<7 - 1),
217 "Int16": int16(1<<15 - 1),
218 "Int32": int32(1<<31 - 1),
219 "Int64": int64(1<<63 - 1),
220 "Uint": uint(1<<32 - 1),
221 "Uint8": uint8(1<<8 - 1),
222 "Uint16": uint16(1<<16 - 1),
223 "Uint32": uint32(1<<32 - 1),
224 "Uint64": uint64(1<<63 - 1), // uint64 values with high bit set are not supported
225 "Float32": float32(100.1234),
226 "Float64": float64(100.1234),
227 "Decimal": float64(100.1234),
228 }
229 d := Data{}
230 ind := reflect.Indirect(reflect.ValueOf(&d))
231
232 for name, value := range values {
233 e := ind.FieldByName(name)
234 e.Set(reflect.ValueOf(value))
235 }
236
237 id, err := dORM.Insert(&d)
238 throwFail(t, err)
239 throwFail(t, AssertIs(id, T_Equal, 1))
240
241 d = Data{Id: 1}
242 err = dORM.Read(&d)
243 throwFail(t, err)
244
245 ind = reflect.Indirect(reflect.ValueOf(&d))
246
247 for name, value := range values {
248 e := ind.FieldByName(name)
249 vu := e.Interface()
250 switch name {
251 case "Date":
252 vu = vu.(time.Time).In(DefaultTimeLoc).Format(test_Date)
253 value = value.(time.Time).In(DefaultTimeLoc).Format(test_Date)
254 case "DateTime":
255 vu = vu.(time.Time).In(DefaultTimeLoc).Format(test_DateTime)
256 value = value.(time.Time).In(DefaultTimeLoc).Format(test_DateTime)
257 }
258 throwFail(t, AssertIs(vu == value, T_Equal, true), value, vu)
259 }
260 }
261
262 func TestNullDataTypes(t *testing.T) {
263 d := DataNull{}
264
265 if IsPostgres {
266 // can removed when this fixed
267 // https://github.com/lib/pq/pull/125
268 d.DateTime = time.Now()
269 }
270
271 id, err := dORM.Insert(&d)
272 throwFail(t, err)
273 throwFail(t, AssertIs(id, T_Equal, 1))
274
275 d = DataNull{Id: 1}
276 err = dORM.Read(&d)
277 throwFail(t, err)
278
279 _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec()
280 throwFail(t, err)
281
282 d = DataNull{Id: 2}
283 err = dORM.Read(&d)
284 throwFail(t, err)
285 }
286
187 func TestCRUD(t *testing.T) { 287 func TestCRUD(t *testing.T) {
188 profile := NewProfile() 288 profile := NewProfile()
189 profile.Age = 30 289 profile.Age = 30
...@@ -214,8 +314,8 @@ func TestCRUD(t *testing.T) { ...@@ -214,8 +314,8 @@ func TestCRUD(t *testing.T) {
214 throwFail(t, AssertIs(u.Status, T_Equal, 3)) 314 throwFail(t, AssertIs(u.Status, T_Equal, 3))
215 throwFail(t, AssertIs(u.IsStaff, T_Equal, true)) 315 throwFail(t, AssertIs(u.IsStaff, T_Equal, true))
216 throwFail(t, AssertIs(u.IsActive, T_Equal, true)) 316 throwFail(t, AssertIs(u.IsActive, T_Equal, true))
217 throwFail(t, AssertIs(u.Created, T_Equal, user.Created, format_Date)) 317 throwFail(t, AssertIs(u.Created.In(DefaultTimeLoc), T_Equal, user.Created.In(DefaultTimeLoc), test_Date))
218 throwFail(t, AssertIs(u.Updated, T_Equal, user.Updated, format_DateTime)) 318 throwFail(t, AssertIs(u.Updated.In(DefaultTimeLoc), T_Equal, user.Updated.In(DefaultTimeLoc), test_DateTime))
219 319
220 user.UserName = "astaxie" 320 user.UserName = "astaxie"
221 user.Profile = profile 321 user.Profile = profile
...@@ -360,7 +460,9 @@ The program—and web server—godoc processes Go source files to extract docume ...@@ -360,7 +460,9 @@ The program—and web server—godoc processes Go source files to extract docume
360 } 460 }
361 461
362 func TestExpr(t *testing.T) { 462 func TestExpr(t *testing.T) {
363 qs := dORM.QueryTable("User") 463 user := &User{}
464 qs := dORM.QueryTable(user)
465 qs = dORM.QueryTable("User")
364 qs = dORM.QueryTable("user") 466 qs = dORM.QueryTable("user")
365 num, err := qs.Filter("UserName", "slene").Filter("user_name", "slene").Filter("profile__Age", 28).Count() 467 num, err := qs.Filter("UserName", "slene").Filter("user_name", "slene").Filter("profile__Age", 28).Count()
366 throwFail(t, err) 468 throwFail(t, err)
...@@ -369,6 +471,10 @@ func TestExpr(t *testing.T) { ...@@ -369,6 +471,10 @@ func TestExpr(t *testing.T) {
369 num, err = qs.Filter("created", time.Now()).Count() 471 num, err = qs.Filter("created", time.Now()).Count()
370 throwFail(t, err) 472 throwFail(t, err)
371 throwFail(t, AssertIs(num, T_Equal, 3)) 473 throwFail(t, AssertIs(num, T_Equal, 3))
474
475 num, err = qs.Filter("created", time.Now().Format(format_Date)).Count()
476 throwFail(t, err)
477 throwFail(t, AssertIs(num, T_Equal, 3))
372 } 478 }
373 479
374 func TestOperators(t *testing.T) { 480 func TestOperators(t *testing.T) {
...@@ -820,9 +926,11 @@ func TestRaw(t *testing.T) { ...@@ -820,9 +926,11 @@ func TestRaw(t *testing.T) {
820 res, err := dORM.Raw(`DELETE FROM "tag" WHERE "name" IN (?, ?, ?)`, []string{"name1", "name2", "name3"}).Exec() 926 res, err := dORM.Raw(`DELETE FROM "tag" WHERE "name" IN (?, ?, ?)`, []string{"name1", "name2", "name3"}).Exec()
821 throwFail(t, err) 927 throwFail(t, err)
822 928
823 num, err := res.RowsAffected() 929 if err == nil {
824 throwFail(t, err) 930 num, err := res.RowsAffected()
825 throwFail(t, AssertIs(num, T_Equal, 3)) 931 throwFail(t, err)
932 throwFail(t, AssertIs(num, T_Equal, 3))
933 }
826 } 934 }
827 } 935 }
828 } 936 }
......
...@@ -3,6 +3,7 @@ package orm ...@@ -3,6 +3,7 @@ package orm
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "reflect" 5 "reflect"
6 "time"
6 ) 7 )
7 8
8 type Driver interface { 9 type Driver interface {
...@@ -110,23 +111,25 @@ type txEnder interface { ...@@ -110,23 +111,25 @@ type txEnder interface {
110 } 111 }
111 112
112 type dbBaser interface { 113 type dbBaser interface {
113 Read(dbQuerier, *modelInfo, reflect.Value) error 114 Read(dbQuerier, *modelInfo, reflect.Value, *time.Location) error
114 Insert(dbQuerier, *modelInfo, reflect.Value) (int64, error) 115 Insert(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
115 InsertStmt(stmtQuerier, *modelInfo, reflect.Value) (int64, error) 116 InsertStmt(stmtQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
116 Update(dbQuerier, *modelInfo, reflect.Value) (int64, error) 117 Update(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
117 Delete(dbQuerier, *modelInfo, reflect.Value) (int64, error) 118 Delete(dbQuerier, *modelInfo, reflect.Value, *time.Location) (int64, error)
118 ReadBatch(dbQuerier, *querySet, *modelInfo, *Condition, interface{}) (int64, error) 119 ReadBatch(dbQuerier, *querySet, *modelInfo, *Condition, interface{}, *time.Location) (int64, error)
119 SupportUpdateJoin() bool 120 SupportUpdateJoin() bool
120 UpdateBatch(dbQuerier, *querySet, *modelInfo, *Condition, Params) (int64, error) 121 UpdateBatch(dbQuerier, *querySet, *modelInfo, *Condition, Params, *time.Location) (int64, error)
121 DeleteBatch(dbQuerier, *querySet, *modelInfo, *Condition) (int64, error) 122 DeleteBatch(dbQuerier, *querySet, *modelInfo, *Condition, *time.Location) (int64, error)
122 Count(dbQuerier, *querySet, *modelInfo, *Condition) (int64, error) 123 Count(dbQuerier, *querySet, *modelInfo, *Condition, *time.Location) (int64, error)
123 OperatorSql(string) string 124 OperatorSql(string) string
124 GenerateOperatorSql(*modelInfo, *fieldInfo, string, []interface{}) (string, []interface{}) 125 GenerateOperatorSql(*modelInfo, *fieldInfo, string, []interface{}, *time.Location) (string, []interface{})
125 GenerateOperatorLeftCol(string, *string) 126 GenerateOperatorLeftCol(*fieldInfo, string, *string)
126 PrepareInsert(dbQuerier, *modelInfo) (stmtQuerier, string, error) 127 PrepareInsert(dbQuerier, *modelInfo) (stmtQuerier, string, error)
127 ReadValues(dbQuerier, *querySet, *modelInfo, *Condition, []string, interface{}) (int64, error) 128 ReadValues(dbQuerier, *querySet, *modelInfo, *Condition, []string, interface{}, *time.Location) (int64, error)
128 MaxLimit() uint64 129 MaxLimit() uint64
129 TableQuote() string 130 TableQuote() string
130 ReplaceMarks(*string) 131 ReplaceMarks(*string)
131 HasReturningID(*modelInfo, *string) bool 132 HasReturningID(*modelInfo, *string) bool
133 TimeFromDB(*time.Time, *time.Location)
134 TimeToDB(*time.Time, *time.Location)
132 } 135 }
......
...@@ -38,6 +38,11 @@ func (f StrTo) Float64() (float64, error) { ...@@ -38,6 +38,11 @@ func (f StrTo) Float64() (float64, error) {
38 return strconv.ParseFloat(f.String(), 64) 38 return strconv.ParseFloat(f.String(), 64)
39 } 39 }
40 40
41 func (f StrTo) Int8() (int8, error) {
42 v, err := strconv.ParseInt(f.String(), 10, 8)
43 return int8(v), err
44 }
45
41 func (f StrTo) Int16() (int16, error) { 46 func (f StrTo) Int16() (int16, error) {
42 v, err := strconv.ParseInt(f.String(), 10, 16) 47 v, err := strconv.ParseInt(f.String(), 10, 16)
43 return int16(v), err 48 return int16(v), err
...@@ -53,6 +58,11 @@ func (f StrTo) Int64() (int64, error) { ...@@ -53,6 +58,11 @@ func (f StrTo) Int64() (int64, error) {
53 return int64(v), err 58 return int64(v), err
54 } 59 }
55 60
61 func (f StrTo) Uint8() (uint8, error) {
62 v, err := strconv.ParseUint(f.String(), 10, 8)
63 return uint8(v), err
64 }
65
56 func (f StrTo) Uint16() (uint16, error) { 66 func (f StrTo) Uint16() (uint16, error) {
57 v, err := strconv.ParseUint(f.String(), 10, 16) 67 v, err := strconv.ParseUint(f.String(), 10, 16)
58 return uint16(v), err 68 return uint16(v), err
...@@ -85,6 +95,8 @@ func ToStr(value interface{}, args ...int) (s string) { ...@@ -85,6 +95,8 @@ func ToStr(value interface{}, args ...int) (s string) {
85 s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64)) 95 s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
86 case int: 96 case int:
87 s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) 97 s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
98 case int8:
99 s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
88 case int16: 100 case int16:
89 s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) 101 s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
90 case int32: 102 case int32:
...@@ -93,6 +105,8 @@ func ToStr(value interface{}, args ...int) (s string) { ...@@ -93,6 +105,8 @@ func ToStr(value interface{}, args ...int) (s string) {
93 s = strconv.FormatInt(v, argInt(args).Get(0, 10)) 105 s = strconv.FormatInt(v, argInt(args).Get(0, 10))
94 case uint: 106 case uint:
95 s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) 107 s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
108 case uint8:
109 s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
96 case uint16: 110 case uint16:
97 s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) 111 s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
98 case uint32: 112 case uint32:
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!