orm add full regular go type support, such as int8, uint8, byte, rune. add date/…
…datetime timezone support very well.
Showing
17 changed files
with
438 additions
and
55 deletions
This diff is collapsed.
Click to expand it.
| ... | @@ -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.Println("driverName `%s` db driver already registered and is other type") |
| 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 | err := fmt.Errorf("DataBase name `%s` not registered", name) | ||
| 181 | fmt.Println(err) | ||
| 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 | ... | ... |
| ... | @@ -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: | ... | ... |
-
Please register or sign in to post a comment