fix time issues and add some tests for time (#604)
* fix time issues and add some tests for time * fix tests bug * fix tests * some fixes with tests and added mssql support * fix tests
This commit is contained in:
parent
9c179e47a1
commit
942887dea0
|
@ -21,7 +21,7 @@ database:
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
# './...' is a relative pattern which means all subdirectories
|
# './...' is a relative pattern which means all subdirectories
|
||||||
- go test -v -race -db="sqlite3;mysql;postgres" -conn_str="./test.db;root:@/xorm_test;dbname=xorm_test sslmode=disable" -coverprofile=coverage.txt -covermode=atomic
|
- go test -v -race -db="sqlite3::mysql::postgres" -conn_str="./test.db::root:@/xorm_test::dbname=xorm_test sslmode=disable" -coverprofile=coverage.txt -covermode=atomic
|
||||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
|
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
|
||||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
|
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
|
||||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh
|
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh
|
||||||
|
|
|
@ -215,7 +215,7 @@ func (db *mssql) SqlType(c *core.Column) string {
|
||||||
var res string
|
var res string
|
||||||
switch t := c.SQLType.Name; t {
|
switch t := c.SQLType.Name; t {
|
||||||
case core.Bool:
|
case core.Bool:
|
||||||
res = core.TinyInt
|
res = core.Bit
|
||||||
if strings.EqualFold(c.Default, "true") {
|
if strings.EqualFold(c.Default, "true") {
|
||||||
c.Default = "1"
|
c.Default = "1"
|
||||||
} else {
|
} else {
|
||||||
|
@ -250,6 +250,9 @@ func (db *mssql) SqlType(c *core.Column) string {
|
||||||
case core.Uuid:
|
case core.Uuid:
|
||||||
res = core.Varchar
|
res = core.Varchar
|
||||||
c.Length = 40
|
c.Length = 40
|
||||||
|
case core.TinyInt:
|
||||||
|
res = core.TinyInt
|
||||||
|
c.Length = 0
|
||||||
default:
|
default:
|
||||||
res = t
|
res = t
|
||||||
}
|
}
|
||||||
|
@ -335,9 +338,15 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||||
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
|
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
|
||||||
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault
|
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
|
||||||
from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
|
ISNULL(i.is_primary_key, 0)
|
||||||
|
from sys.columns a
|
||||||
|
left join sys.types b on a.user_type_id=b.user_type_id
|
||||||
left join sys.syscomments c on a.default_object_id=c.id
|
left join sys.syscomments c on a.default_object_id=c.id
|
||||||
|
LEFT OUTER JOIN
|
||||||
|
sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id
|
||||||
|
LEFT OUTER JOIN
|
||||||
|
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
||||||
where a.object_id=object_id('` + tableName + `')`
|
where a.object_id=object_id('` + tableName + `')`
|
||||||
db.LogSQL(s, args)
|
db.LogSQL(s, args)
|
||||||
|
|
||||||
|
@ -352,8 +361,8 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var name, ctype, vdefault string
|
var name, ctype, vdefault string
|
||||||
var maxLen, precision, scale int
|
var maxLen, precision, scale int
|
||||||
var nullable bool
|
var nullable, isPK bool
|
||||||
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault)
|
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -363,6 +372,7 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
|
||||||
col.Name = strings.Trim(name, "` ")
|
col.Name = strings.Trim(name, "` ")
|
||||||
col.Nullable = nullable
|
col.Nullable = nullable
|
||||||
col.Default = vdefault
|
col.Default = vdefault
|
||||||
|
col.IsPrimaryKey = isPK
|
||||||
ct := strings.ToUpper(ctype)
|
ct := strings.ToUpper(ctype)
|
||||||
if ct == "DECIMAL" {
|
if ct == "DECIMAL" {
|
||||||
col.Length = precision
|
col.Length = precision
|
||||||
|
@ -536,7 +546,6 @@ type odbcDriver struct {
|
||||||
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||||
kv := strings.Split(dataSourceName, ";")
|
kv := strings.Split(dataSourceName, ";")
|
||||||
var dbName string
|
var dbName string
|
||||||
|
|
||||||
for _, c := range kv {
|
for _, c := range kv {
|
||||||
vv := strings.Split(strings.TrimSpace(c), "=")
|
vv := strings.Split(strings.TrimSpace(c), "=")
|
||||||
if len(vv) == 2 {
|
if len(vv) == 2 {
|
||||||
|
|
54
engine.go
54
engine.go
|
@ -40,7 +40,7 @@ type Engine struct {
|
||||||
showExecTime bool
|
showExecTime bool
|
||||||
|
|
||||||
logger core.ILogger
|
logger core.ILogger
|
||||||
TZLocation *time.Location
|
TZLocation *time.Location // The timezone of the application
|
||||||
DatabaseTZ *time.Location // The timezone of the database
|
DatabaseTZ *time.Location // The timezone of the database
|
||||||
|
|
||||||
disableGlobalCache bool
|
disableGlobalCache bool
|
||||||
|
@ -1498,7 +1498,6 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
|
||||||
results = append(results, result)
|
results = append(results, result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
//lastError = err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1506,49 +1505,28 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
|
||||||
return results, lastError
|
return results, lastError
|
||||||
}
|
}
|
||||||
|
|
||||||
// TZTime change one time to xorm time location
|
|
||||||
func (engine *Engine) TZTime(t time.Time) time.Time {
|
|
||||||
if !t.IsZero() { // if time is not initialized it's not suitable for Time.In()
|
|
||||||
return t.In(engine.TZLocation)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// NowTime return current time
|
|
||||||
func (engine *Engine) NowTime(sqlTypeName string) interface{} {
|
|
||||||
t := time.Now()
|
|
||||||
return engine.FormatTime(sqlTypeName, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NowTime2 return current time
|
// NowTime2 return current time
|
||||||
func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) {
|
func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
return engine.FormatTime(sqlTypeName, t), t
|
return engine.formatTime(sqlTypeName, t.In(engine.DatabaseTZ)), t.In(engine.TZLocation)
|
||||||
}
|
|
||||||
|
|
||||||
// FormatTime format time
|
|
||||||
func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{}) {
|
|
||||||
return engine.formatTime(engine.TZLocation, sqlTypeName, t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) {
|
func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) {
|
||||||
if col.DisableTimeZone {
|
if t.IsZero() {
|
||||||
return engine.formatTime(nil, col.SQLType.Name, t)
|
if col.Nullable {
|
||||||
} else if col.TimeZone != nil {
|
return nil
|
||||||
return engine.formatTime(col.TimeZone, col.SQLType.Name, t)
|
|
||||||
}
|
}
|
||||||
return engine.formatTime(engine.TZLocation, col.SQLType.Name, t)
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.Time) (v interface{}) {
|
if col.TimeZone != nil {
|
||||||
if engine.dialect.DBType() == core.ORACLE {
|
return engine.formatTime(col.SQLType.Name, t.In(col.TimeZone))
|
||||||
return t
|
|
||||||
}
|
}
|
||||||
if tz != nil {
|
return engine.formatTime(col.SQLType.Name, t.In(engine.DatabaseTZ))
|
||||||
t = t.In(tz)
|
|
||||||
} else {
|
|
||||||
t = engine.TZTime(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// formatTime format time as column type
|
||||||
|
func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) {
|
||||||
switch sqlTypeName {
|
switch sqlTypeName {
|
||||||
case core.Time:
|
case core.Time:
|
||||||
s := t.Format("2006-01-02 15:04:05") //time.RFC3339
|
s := t.Format("2006-01-02 15:04:05") //time.RFC3339
|
||||||
|
@ -1556,18 +1534,10 @@ func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.T
|
||||||
case core.Date:
|
case core.Date:
|
||||||
v = t.Format("2006-01-02")
|
v = t.Format("2006-01-02")
|
||||||
case core.DateTime, core.TimeStamp:
|
case core.DateTime, core.TimeStamp:
|
||||||
if engine.dialect.DBType() == "ql" {
|
|
||||||
v = t
|
|
||||||
} else if engine.dialect.DBType() == "sqlite3" {
|
|
||||||
v = t.UTC().Format("2006-01-02 15:04:05")
|
|
||||||
} else {
|
|
||||||
v = t.Format("2006-01-02 15:04:05")
|
v = t.Format("2006-01-02 15:04:05")
|
||||||
}
|
|
||||||
case core.TimeStampz:
|
case core.TimeStampz:
|
||||||
if engine.dialect.DBType() == core.MSSQL {
|
if engine.dialect.DBType() == core.MSSQL {
|
||||||
v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
|
v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
|
||||||
} else if engine.DriverName() == "mssql" {
|
|
||||||
v = t
|
|
||||||
} else {
|
} else {
|
||||||
v = t.Format(time.RFC3339Nano)
|
v = t.Format(time.RFC3339Nano)
|
||||||
}
|
}
|
||||||
|
|
170
helpers.go
170
helpers.go
|
@ -12,6 +12,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -319,175 +320,6 @@ func sliceEq(left, right []string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func reflect2value(rawValue *reflect.Value) (str string, err error) {
|
|
||||||
aa := reflect.TypeOf((*rawValue).Interface())
|
|
||||||
vv := reflect.ValueOf((*rawValue).Interface())
|
|
||||||
switch aa.Kind() {
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
str = strconv.FormatInt(vv.Int(), 10)
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
||||||
str = strconv.FormatUint(vv.Uint(), 10)
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
|
|
||||||
case reflect.String:
|
|
||||||
str = vv.String()
|
|
||||||
case reflect.Array, reflect.Slice:
|
|
||||||
switch aa.Elem().Kind() {
|
|
||||||
case reflect.Uint8:
|
|
||||||
data := rawValue.Interface().([]byte)
|
|
||||||
str = string(data)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
|
||||||
}
|
|
||||||
// time type
|
|
||||||
case reflect.Struct:
|
|
||||||
if aa.ConvertibleTo(core.TimeType) {
|
|
||||||
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
|
||||||
}
|
|
||||||
case reflect.Bool:
|
|
||||||
str = strconv.FormatBool(vv.Bool())
|
|
||||||
case reflect.Complex128, reflect.Complex64:
|
|
||||||
str = fmt.Sprintf("%v", vv.Complex())
|
|
||||||
/* TODO: unsupported types below
|
|
||||||
case reflect.Map:
|
|
||||||
case reflect.Ptr:
|
|
||||||
case reflect.Uintptr:
|
|
||||||
case reflect.UnsafePointer:
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface:
|
|
||||||
*/
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func value2Bytes(rawValue *reflect.Value) (data []byte, err error) {
|
|
||||||
var str string
|
|
||||||
str, err = reflect2value(rawValue)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data = []byte(str)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func value2String(rawValue *reflect.Value) (data string, err error) {
|
|
||||||
data, err = reflect2value(rawValue)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
|
|
||||||
fields, err := rows.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for rows.Next() {
|
|
||||||
result, err := row2mapStr(rows, fields)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resultsSlice = append(resultsSlice, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultsSlice, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
|
|
||||||
fields, err := rows.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for rows.Next() {
|
|
||||||
result, err := row2map(rows, fields)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resultsSlice = append(resultsSlice, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultsSlice, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
|
|
||||||
result := make(map[string][]byte)
|
|
||||||
scanResultContainers := make([]interface{}, len(fields))
|
|
||||||
for i := 0; i < len(fields); i++ {
|
|
||||||
var scanResultContainer interface{}
|
|
||||||
scanResultContainers[i] = &scanResultContainer
|
|
||||||
}
|
|
||||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for ii, key := range fields {
|
|
||||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
|
||||||
//if row is null then ignore
|
|
||||||
if rawValue.Interface() == nil {
|
|
||||||
//fmt.Println("ignore ...", key, rawValue)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if data, err := value2Bytes(&rawValue); err == nil {
|
|
||||||
result[key] = data
|
|
||||||
} else {
|
|
||||||
return nil, err // !nashtsai! REVIEW, should return err or just error log?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
|
|
||||||
result := make(map[string]string)
|
|
||||||
scanResultContainers := make([]interface{}, len(fields))
|
|
||||||
for i := 0; i < len(fields); i++ {
|
|
||||||
var scanResultContainer interface{}
|
|
||||||
scanResultContainers[i] = &scanResultContainer
|
|
||||||
}
|
|
||||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for ii, key := range fields {
|
|
||||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
|
||||||
//if row is null then ignore
|
|
||||||
if rawValue.Interface() == nil {
|
|
||||||
//fmt.Println("ignore ...", key, rawValue)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if data, err := value2String(&rawValue); err == nil {
|
|
||||||
result[key] = data
|
|
||||||
} else {
|
|
||||||
return nil, err // !nashtsai! REVIEW, should return err or just error log?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) {
|
|
||||||
rows, err := tx.Query(sqlStr, params...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
return rows2Strings(rows)
|
|
||||||
}
|
|
||||||
|
|
||||||
func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) {
|
|
||||||
rows, err := db.Query(sqlStr, params...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
return rows2Strings(rows)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setColumnInt(bean interface{}, col *core.Column, t int64) {
|
func setColumnInt(bean interface{}, col *core.Column, t int64) {
|
||||||
v, err := col.ValueOf(bean)
|
v, err := col.ValueOf(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package xorm
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
zeroTime0 = "0000-00-00 00:00:00"
|
||||||
|
zeroTime1 = "0001-01-01 00:00:00"
|
||||||
|
)
|
||||||
|
|
||||||
|
func formatTime(t time.Time) string {
|
||||||
|
return t.Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTimeZero(t time.Time) bool {
|
||||||
|
return t.IsZero() || formatTime(t) == zeroTime0 ||
|
||||||
|
formatTime(t) == zeroTime1
|
||||||
|
}
|
22
session.go
22
session.go
|
@ -344,15 +344,6 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
dbTZ := session.Engine.DatabaseTZ
|
|
||||||
if dbTZ == nil {
|
|
||||||
if session.Engine.dialect.DBType() == core.SQLITE {
|
|
||||||
dbTZ = time.UTC
|
|
||||||
} else {
|
|
||||||
dbTZ = time.Local
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tempMap = make(map[string]int)
|
var tempMap = make(map[string]int)
|
||||||
var pk core.PK
|
var pk core.PK
|
||||||
for ii, key := range fields {
|
for ii, key := range fields {
|
||||||
|
@ -528,11 +519,9 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if fieldType.ConvertibleTo(core.TimeType) {
|
if fieldType.ConvertibleTo(core.TimeType) {
|
||||||
var tz *time.Location
|
dbTZ := session.Engine.DatabaseTZ
|
||||||
if col.TimeZone == nil {
|
if col.TimeZone != nil {
|
||||||
tz = session.Engine.TZLocation
|
dbTZ = col.TimeZone
|
||||||
} else {
|
|
||||||
tz = col.TimeZone
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if rawValueType == core.TimeType {
|
if rawValueType == core.TimeType {
|
||||||
|
@ -548,14 +537,13 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
|
||||||
t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
|
t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// !nashtsai! convert to engine location
|
t = t.In(session.Engine.TZLocation)
|
||||||
t = t.In(tz)
|
|
||||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||||
} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
|
} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
|
||||||
rawValueType == core.Int32Type {
|
rawValueType == core.Int32Type {
|
||||||
hasAssigned = true
|
hasAssigned = true
|
||||||
|
|
||||||
t := time.Unix(vv.Int(), 0).In(tz)
|
t := time.Unix(vv.Int(), 0).In(session.Engine.TZLocation)
|
||||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||||
} else {
|
} else {
|
||||||
if d, ok := vv.Interface().([]uint8); ok {
|
if d, ok := vv.Interface().([]uint8); ok {
|
||||||
|
|
|
@ -7,6 +7,7 @@ package xorm
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-xorm/core"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,7 +27,11 @@ func TestSetExpr(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, cnt)
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
cnt, err = testEngine.SetExpr("show", "NOT `show`").Id(1).Update(new(User))
|
var not = "NOT"
|
||||||
|
if testEngine.dialect.DBType() == core.MSSQL {
|
||||||
|
not = "~"
|
||||||
|
}
|
||||||
|
cnt, err = testEngine.SetExpr("show", not+" `show`").Id(1).Update(new(User))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, cnt)
|
assert.EqualValues(t, 1, cnt)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
|
||||||
var x time.Time
|
var x time.Time
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
var parseLoc = session.Engine.DatabaseTZ
|
||||||
|
if col.TimeZone != nil {
|
||||||
|
parseLoc = col.TimeZone
|
||||||
|
}
|
||||||
|
|
||||||
if sdata == "0000-00-00 00:00:00" ||
|
if sdata == "0000-00-00 00:00:00" ||
|
||||||
sdata == "0001-01-01 00:00:00" {
|
sdata == "0001-01-01 00:00:00" {
|
||||||
} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
|
} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
|
||||||
|
@ -30,33 +35,26 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
|
||||||
sd, err := strconv.ParseInt(sdata, 10, 64)
|
sd, err := strconv.ParseInt(sdata, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
x = time.Unix(sd, 0)
|
x = time.Unix(sd, 0)
|
||||||
// !nashtsai! HACK mymysql driver is causing Local location being change to CHAT and cause wrong time conversion
|
|
||||||
if col.TimeZone == nil {
|
|
||||||
x = x.In(session.Engine.TZLocation)
|
|
||||||
} else {
|
|
||||||
x = x.In(col.TimeZone)
|
|
||||||
}
|
|
||||||
session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
} else {
|
} else {
|
||||||
session.Engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
}
|
}
|
||||||
} else if len(sdata) > 19 && strings.Contains(sdata, "-") {
|
} else if len(sdata) > 19 && strings.Contains(sdata, "-") {
|
||||||
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation)
|
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
|
||||||
session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation)
|
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
|
||||||
session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation)
|
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
|
||||||
session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
|
} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
|
||||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation)
|
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
|
||||||
session.Engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
||||||
x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation)
|
x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
|
||||||
session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
} else if col.SQLType.Name == core.Time {
|
} else if col.SQLType.Name == core.Time {
|
||||||
if strings.Contains(sdata, " ") {
|
if strings.Contains(sdata, " ") {
|
||||||
|
@ -70,7 +68,7 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
|
||||||
}
|
}
|
||||||
|
|
||||||
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
||||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation)
|
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
|
||||||
session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||||
} else {
|
} else {
|
||||||
outErr = fmt.Errorf("unsupported time format %v", sdata)
|
outErr = fmt.Errorf("unsupported time format %v", sdata)
|
||||||
|
@ -80,7 +78,7 @@ func (session *Session) str2Time(col *core.Column, data string) (outTime time.Ti
|
||||||
outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
|
outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
outTime = x
|
outTime = x.In(session.Engine.TZLocation)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,12 +586,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if fieldType.ConvertibleTo(core.TimeType) {
|
if fieldType.ConvertibleTo(core.TimeType) {
|
||||||
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
|
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
|
||||||
if session.Engine.dialect.DBType() == core.MSSQL {
|
tf := session.Engine.formatColTime(col, t)
|
||||||
if t.IsZero() {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tf := session.Engine.FormatTime(col.SQLType.Name, t)
|
|
||||||
return tf, nil
|
return tf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-xorm/core"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,6 +120,11 @@ func TestGetStruct(t *testing.T) {
|
||||||
|
|
||||||
assert.NoError(t, testEngine.Sync(new(UserinfoGet)))
|
assert.NoError(t, testEngine.Sync(new(UserinfoGet)))
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if testEngine.dialect.DBType() == core.MSSQL {
|
||||||
|
_, err = testEngine.Exec("SET IDENTITY_INSERT userinfo_get ON")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
cnt, err := testEngine.Insert(&UserinfoGet{Uid: 2})
|
cnt, err := testEngine.Insert(&UserinfoGet{Uid: 2})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, cnt)
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
|
@ -357,10 +357,10 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
session.Engine.QuoteStr(),
|
session.Engine.QuoteStr(),
|
||||||
colPlaces)
|
colPlaces)
|
||||||
} else {
|
} else {
|
||||||
if session.Engine.dialect.DBType() == core.SQLITE || session.Engine.dialect.DBType() == core.POSTGRES {
|
if session.Engine.dialect.DBType() == core.MYSQL {
|
||||||
sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.Engine.Quote(session.Statement.TableName()))
|
|
||||||
} else {
|
|
||||||
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.Engine.Quote(session.Statement.TableName()))
|
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.Engine.Quote(session.Statement.TableName()))
|
||||||
|
} else {
|
||||||
|
sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.Engine.Quote(session.Statement.TableName()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
173
session_raw.go
173
session_raw.go
|
@ -6,6 +6,10 @@ package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
@ -59,6 +63,60 @@ func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.
|
||||||
return stmt, rows, nil
|
return stmt, rows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
|
||||||
|
fields, err := rows.Columns()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
result, err := row2map(rows, fields)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resultsSlice = append(resultsSlice, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultsSlice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func value2Bytes(rawValue *reflect.Value) (data []byte, err error) {
|
||||||
|
var str string
|
||||||
|
str, err = reflect2value(rawValue)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data = []byte(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
|
||||||
|
result := make(map[string][]byte)
|
||||||
|
scanResultContainers := make([]interface{}, len(fields))
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
var scanResultContainer interface{}
|
||||||
|
scanResultContainers[i] = &scanResultContainer
|
||||||
|
}
|
||||||
|
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for ii, key := range fields {
|
||||||
|
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||||
|
//if row is null then ignore
|
||||||
|
if rawValue.Interface() == nil {
|
||||||
|
//fmt.Println("ignore ...", key, rawValue)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, err := value2Bytes(&rawValue); err == nil {
|
||||||
|
result[key] = data
|
||||||
|
} else {
|
||||||
|
return nil, err // !nashtsai! REVIEW, should return err or just error log?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) {
|
func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) {
|
||||||
_, rows, err := session.innerQuery(sqlStr, params...)
|
_, rows, err := session.innerQuery(sqlStr, params...)
|
||||||
if rows != nil {
|
if rows != nil {
|
||||||
|
@ -80,6 +138,121 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) ([]map[str
|
||||||
return session.query(sqlStr, paramStr...)
|
return session.query(sqlStr, paramStr...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
|
||||||
|
fields, err := rows.Columns()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
result, err := row2mapStr(rows, fields)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resultsSlice = append(resultsSlice, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultsSlice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflect2value(rawValue *reflect.Value) (str string, err error) {
|
||||||
|
aa := reflect.TypeOf((*rawValue).Interface())
|
||||||
|
vv := reflect.ValueOf((*rawValue).Interface())
|
||||||
|
switch aa.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
str = strconv.FormatInt(vv.Int(), 10)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
str = strconv.FormatUint(vv.Uint(), 10)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
|
||||||
|
case reflect.String:
|
||||||
|
str = vv.String()
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
switch aa.Elem().Kind() {
|
||||||
|
case reflect.Uint8:
|
||||||
|
data := rawValue.Interface().([]byte)
|
||||||
|
str = string(data)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
||||||
|
}
|
||||||
|
// time type
|
||||||
|
case reflect.Struct:
|
||||||
|
if aa.ConvertibleTo(core.TimeType) {
|
||||||
|
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
||||||
|
}
|
||||||
|
case reflect.Bool:
|
||||||
|
str = strconv.FormatBool(vv.Bool())
|
||||||
|
case reflect.Complex128, reflect.Complex64:
|
||||||
|
str = fmt.Sprintf("%v", vv.Complex())
|
||||||
|
/* TODO: unsupported types below
|
||||||
|
case reflect.Map:
|
||||||
|
case reflect.Ptr:
|
||||||
|
case reflect.Uintptr:
|
||||||
|
case reflect.UnsafePointer:
|
||||||
|
case reflect.Chan, reflect.Func, reflect.Interface:
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func value2String(rawValue *reflect.Value) (data string, err error) {
|
||||||
|
data, err = reflect2value(rawValue)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
|
||||||
|
result := make(map[string]string)
|
||||||
|
scanResultContainers := make([]interface{}, len(fields))
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
var scanResultContainer interface{}
|
||||||
|
scanResultContainers[i] = &scanResultContainer
|
||||||
|
}
|
||||||
|
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for ii, key := range fields {
|
||||||
|
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||||
|
//if row is null then ignore
|
||||||
|
if rawValue.Interface() == nil {
|
||||||
|
//fmt.Println("ignore ...", key, rawValue)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, err := value2String(&rawValue); err == nil {
|
||||||
|
result[key] = data
|
||||||
|
} else {
|
||||||
|
return nil, err // !nashtsai! REVIEW, should return err or just error log?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) {
|
||||||
|
rows, err := tx.Query(sqlStr, params...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
return rows2Strings(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) {
|
||||||
|
rows, err := db.Query(sqlStr, params...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return rows2Strings(rows)
|
||||||
|
}
|
||||||
|
|
||||||
// QueryString runs a raw sql and return records as []map[string]string
|
// QueryString runs a raw sql and return records as []map[string]string
|
||||||
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
|
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
|
||||||
defer session.resetStatement()
|
defer session.resetStatement()
|
||||||
|
|
|
@ -298,7 +298,19 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
condSQL = "WHERE " + condSQL
|
condSQL = "WHERE " + condSQL
|
||||||
}
|
}
|
||||||
} else if st.Engine.dialect.DBType() == core.MSSQL {
|
} else if st.Engine.dialect.DBType() == core.MSSQL {
|
||||||
top = fmt.Sprintf("top (%d) ", st.LimitN)
|
if st.OrderStr != "" && st.Engine.dialect.DBType() == core.MSSQL &&
|
||||||
|
table != nil && len(table.PrimaryKeys) == 1 {
|
||||||
|
cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)",
|
||||||
|
table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0],
|
||||||
|
session.Engine.Quote(session.Statement.TableName()), condSQL), condArgs...)
|
||||||
|
|
||||||
|
condSQL, condArgs, _ = builder.ToSQL(cond)
|
||||||
|
if len(condSQL) > 0 {
|
||||||
|
condSQL = "WHERE " + condSQL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
top = fmt.Sprintf("TOP (%d) ", st.LimitN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,6 @@ func TestUpdate1(t *testing.T) {
|
||||||
And("departname = ?", "").
|
And("departname = ?", "").
|
||||||
And("detail_id = ?", 0).
|
And("detail_id = ?", 0).
|
||||||
And("is_man = ?", 0).
|
And("is_man = ?", 0).
|
||||||
And("created IS NOT NULL").
|
|
||||||
Get(&Userinfo{})
|
Get(&Userinfo{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
|
|
@ -376,7 +376,7 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||||
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = engine.FormatTime(col.SQLType.Name, t)
|
val = engine.formatColTime(col, t)
|
||||||
} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
|
} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||||
val, _ = nulType.Value()
|
val, _ = nulType.Value()
|
||||||
} else {
|
} else {
|
||||||
|
@ -612,7 +612,7 @@ func buildConds(engine *Engine, table *core.Table, bean interface{},
|
||||||
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = engine.FormatTime(col.SQLType.Name, t)
|
val = engine.formatColTime(col, t)
|
||||||
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
|
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
|
||||||
continue
|
continue
|
||||||
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
|
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||||
|
|
|
@ -26,7 +26,7 @@ var colStrTests = []struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColumnsStringGeneration(t *testing.T) {
|
func TestColumnsStringGeneration(t *testing.T) {
|
||||||
if dbType == "postgres" {
|
if dbType == "postgres" || dbType == "mssql" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-xorm/core"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -328,6 +329,11 @@ func TestExtends2(t *testing.T) {
|
||||||
Uid: sender.Id,
|
Uid: sender.Id,
|
||||||
ToUid: receiver.Id,
|
ToUid: receiver.Id,
|
||||||
}
|
}
|
||||||
|
if testEngine.dialect.DBType() == core.MSSQL {
|
||||||
|
_, err = testEngine.Exec("SET IDENTITY_INSERT message ON")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = testEngine.Insert(&msg)
|
_, err = testEngine.Insert(&msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -395,6 +401,10 @@ func TestExtends3(t *testing.T) {
|
||||||
Uid: sender.Id,
|
Uid: sender.Id,
|
||||||
ToUid: receiver.Id,
|
ToUid: receiver.Id,
|
||||||
}
|
}
|
||||||
|
if testEngine.dialect.DBType() == core.MSSQL {
|
||||||
|
_, err = testEngine.Exec("SET IDENTITY_INSERT message ON")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
_, err = testEngine.Insert(&msg)
|
_, err = testEngine.Insert(&msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -478,6 +488,10 @@ func TestExtends4(t *testing.T) {
|
||||||
Content: "test",
|
Content: "test",
|
||||||
Uid: sender.Id,
|
Uid: sender.Id,
|
||||||
}
|
}
|
||||||
|
if testEngine.dialect.DBType() == core.MSSQL {
|
||||||
|
_, err = testEngine.Exec("SET IDENTITY_INSERT message ON")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
_, err = testEngine.Insert(&msg)
|
_, err = testEngine.Insert(&msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
|
|
@ -38,7 +38,7 @@ func TestGonicMapperID(t *testing.T) {
|
||||||
|
|
||||||
for _, tb := range tables {
|
for _, tb := range tables {
|
||||||
if tb.Name == "id_gonic_mapper" {
|
if tb.Name == "id_gonic_mapper" {
|
||||||
if len(tb.PKColumns()) != 1 && !tb.PKColumns()[0].IsPrimaryKey && !tb.PKColumns()[0].IsPrimaryKey {
|
if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "id" {
|
||||||
t.Fatal(tb)
|
t.Fatal(tb)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -75,7 +75,7 @@ func TestSameMapperID(t *testing.T) {
|
||||||
|
|
||||||
for _, tb := range tables {
|
for _, tb := range tables {
|
||||||
if tb.Name == "IDSameMapper" {
|
if tb.Name == "IDSameMapper" {
|
||||||
if len(tb.PKColumns()) != 1 && !tb.PKColumns()[0].IsPrimaryKey && !tb.PKColumns()[0].IsPrimaryKey {
|
if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "ID" {
|
||||||
t.Fatal(tb)
|
t.Fatal(tb)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test"
|
|
@ -0,0 +1,476 @@
|
||||||
|
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package xorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTimeUserTime(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
|
type TimeUser struct {
|
||||||
|
Id string
|
||||||
|
OperTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(TimeUser))
|
||||||
|
|
||||||
|
var user = TimeUser{
|
||||||
|
Id: "lunny",
|
||||||
|
OperTime: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("user", user.OperTime)
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
|
var user2 TimeUser
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.OperTime.Unix(), user2.OperTime.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.OperTime), formatTime(user2.OperTime))
|
||||||
|
fmt.Println("user2", user2.OperTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserTimeDiffLoc(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.TZLocation = loc
|
||||||
|
dbLoc, err := time.LoadLocation("America/New_York")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.DatabaseTZ = dbLoc
|
||||||
|
|
||||||
|
type TimeUser struct {
|
||||||
|
Id string
|
||||||
|
OperTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(TimeUser))
|
||||||
|
|
||||||
|
var user = TimeUser{
|
||||||
|
Id: "lunny",
|
||||||
|
OperTime: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("user", user.OperTime)
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
|
var user2 TimeUser
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.OperTime.Unix(), user2.OperTime.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.OperTime.In(loc)), formatTime(user2.OperTime))
|
||||||
|
fmt.Println("user2", user2.OperTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserCreated(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
|
type UserCreated struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt time.Time `xorm:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserCreated))
|
||||||
|
|
||||||
|
var user = UserCreated{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("user", user.CreatedAt)
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
|
var user2 UserCreated
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt))
|
||||||
|
fmt.Println("user2", user2.CreatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserCreatedDiffLoc(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.TZLocation = loc
|
||||||
|
dbLoc, err := time.LoadLocation("America/New_York")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.DatabaseTZ = dbLoc
|
||||||
|
|
||||||
|
type UserCreated struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt time.Time `xorm:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserCreated))
|
||||||
|
|
||||||
|
var user = UserCreated{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("user", user.CreatedAt)
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
|
var user2 UserCreated
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt))
|
||||||
|
fmt.Println("user2", user2.CreatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserUpdated(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
|
type UserUpdated struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt time.Time `xorm:"created"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserUpdated))
|
||||||
|
|
||||||
|
var user = UserUpdated{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("user", user.CreatedAt, user.UpdatedAt)
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
|
var user2 UserUpdated
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt))
|
||||||
|
assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt))
|
||||||
|
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt)
|
||||||
|
|
||||||
|
var user3 = UserUpdated{
|
||||||
|
Id: "lunny2",
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt, err = testEngine.Update(&user3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
assert.True(t, user.UpdatedAt.Unix() <= user3.UpdatedAt.Unix())
|
||||||
|
|
||||||
|
var user4 UserUpdated
|
||||||
|
has, err = testEngine.Get(&user4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user4.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user4.CreatedAt))
|
||||||
|
assert.EqualValues(t, user3.UpdatedAt.Unix(), user4.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user3.UpdatedAt), formatTime(user4.UpdatedAt))
|
||||||
|
fmt.Println("user3", user.CreatedAt, user4.UpdatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserUpdatedDiffLoc(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.TZLocation = loc
|
||||||
|
dbLoc, err := time.LoadLocation("America/New_York")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.DatabaseTZ = dbLoc
|
||||||
|
|
||||||
|
type UserUpdated struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt time.Time `xorm:"created"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserUpdated))
|
||||||
|
|
||||||
|
var user = UserUpdated{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("user", user.CreatedAt, user.UpdatedAt)
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
|
||||||
|
var user2 UserUpdated
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt))
|
||||||
|
assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt))
|
||||||
|
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt)
|
||||||
|
|
||||||
|
var user3 = UserUpdated{
|
||||||
|
Id: "lunny2",
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt, err = testEngine.Update(&user3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
assert.True(t, user.UpdatedAt.Unix() <= user3.UpdatedAt.Unix())
|
||||||
|
|
||||||
|
var user4 UserUpdated
|
||||||
|
has, err = testEngine.Get(&user4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user4.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user4.CreatedAt))
|
||||||
|
assert.EqualValues(t, user3.UpdatedAt.Unix(), user4.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user3.UpdatedAt), formatTime(user4.UpdatedAt))
|
||||||
|
fmt.Println("user3", user.CreatedAt, user4.UpdatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserDeleted(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
|
type UserDeleted struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt time.Time `xorm:"created"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated"`
|
||||||
|
DeletedAt time.Time `xorm:"deleted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserDeleted))
|
||||||
|
|
||||||
|
var user = UserDeleted{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt)
|
||||||
|
|
||||||
|
var user2 UserDeleted
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt))
|
||||||
|
assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt))
|
||||||
|
assert.True(t, isTimeZero(user2.DeletedAt))
|
||||||
|
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
|
||||||
|
|
||||||
|
var user3 UserDeleted
|
||||||
|
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
assert.True(t, !isTimeZero(user3.DeletedAt))
|
||||||
|
|
||||||
|
var user4 UserDeleted
|
||||||
|
has, err = testEngine.Unscoped().Get(&user4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user3.DeletedAt), formatTime(user4.DeletedAt))
|
||||||
|
fmt.Println("user3", user3.DeletedAt, user4.DeletedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeUserDeletedDiffLoc(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.TZLocation = loc
|
||||||
|
dbLoc, err := time.LoadLocation("America/New_York")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.DatabaseTZ = dbLoc
|
||||||
|
|
||||||
|
type UserDeleted struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt time.Time `xorm:"created"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated"`
|
||||||
|
DeletedAt time.Time `xorm:"deleted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserDeleted))
|
||||||
|
|
||||||
|
var user = UserDeleted{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt)
|
||||||
|
|
||||||
|
var user2 UserDeleted
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt))
|
||||||
|
assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt))
|
||||||
|
assert.True(t, isTimeZero(user2.DeletedAt))
|
||||||
|
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
|
||||||
|
|
||||||
|
var user3 UserDeleted
|
||||||
|
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
assert.True(t, !isTimeZero(user3.DeletedAt))
|
||||||
|
|
||||||
|
var user4 UserDeleted
|
||||||
|
has, err = testEngine.Unscoped().Get(&user4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(user3.DeletedAt), formatTime(user4.DeletedAt))
|
||||||
|
fmt.Println("user3", user3.DeletedAt, user4.DeletedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JsonDate time.Time
|
||||||
|
|
||||||
|
func (j JsonDate) MarshalJSON() ([]byte, error) {
|
||||||
|
if time.Time(j).IsZero() {
|
||||||
|
return []byte(`""`), nil
|
||||||
|
}
|
||||||
|
return []byte(`"` + time.Time(j).Format("2006-01-02 15:04:05") + `"`), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JsonDate) UnmarshalJSON(value []byte) error {
|
||||||
|
var v = strings.TrimSpace(strings.Trim(string(value), "\""))
|
||||||
|
|
||||||
|
t, err := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*j = JsonDate(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JsonDate) Unix() int64 {
|
||||||
|
return (*time.Time)(j).Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomTimeUserDeleted(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
|
type UserDeleted struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt JsonDate `xorm:"created"`
|
||||||
|
UpdatedAt JsonDate `xorm:"updated"`
|
||||||
|
DeletedAt JsonDate `xorm:"deleted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserDeleted))
|
||||||
|
|
||||||
|
var user = UserDeleted{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt)
|
||||||
|
|
||||||
|
var user2 UserDeleted
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(time.Time(user.CreatedAt)), formatTime(time.Time(user2.CreatedAt)))
|
||||||
|
assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(time.Time(user.UpdatedAt)), formatTime(time.Time(user2.UpdatedAt)))
|
||||||
|
assert.True(t, isTimeZero(time.Time(user2.DeletedAt)))
|
||||||
|
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
|
||||||
|
|
||||||
|
var user3 UserDeleted
|
||||||
|
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
assert.True(t, !isTimeZero(time.Time(user3.DeletedAt)))
|
||||||
|
|
||||||
|
var user4 UserDeleted
|
||||||
|
has, err = testEngine.Unscoped().Get(&user4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(time.Time(user3.DeletedAt)), formatTime(time.Time(user4.DeletedAt)))
|
||||||
|
fmt.Println("user3", user3.DeletedAt, user4.DeletedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomTimeUserDeletedDiffLoc(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.TZLocation = loc
|
||||||
|
dbLoc, err := time.LoadLocation("America/New_York")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testEngine.DatabaseTZ = dbLoc
|
||||||
|
|
||||||
|
type UserDeleted struct {
|
||||||
|
Id string
|
||||||
|
CreatedAt JsonDate `xorm:"created"`
|
||||||
|
UpdatedAt JsonDate `xorm:"updated"`
|
||||||
|
DeletedAt JsonDate `xorm:"deleted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(UserDeleted))
|
||||||
|
|
||||||
|
var user = UserDeleted{
|
||||||
|
Id: "lunny",
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt, err := testEngine.Insert(&user)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt)
|
||||||
|
|
||||||
|
var user2 UserDeleted
|
||||||
|
has, err := testEngine.Get(&user2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(time.Time(user.CreatedAt)), formatTime(time.Time(user2.CreatedAt)))
|
||||||
|
assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(time.Time(user.UpdatedAt)), formatTime(time.Time(user2.UpdatedAt)))
|
||||||
|
assert.True(t, isTimeZero(time.Time(user2.DeletedAt)))
|
||||||
|
fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt)
|
||||||
|
|
||||||
|
var user3 UserDeleted
|
||||||
|
cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, cnt)
|
||||||
|
assert.True(t, !isTimeZero(time.Time(user3.DeletedAt)))
|
||||||
|
|
||||||
|
var user4 UserDeleted
|
||||||
|
has, err = testEngine.Unscoped().Get(&user4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, has)
|
||||||
|
assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix())
|
||||||
|
assert.EqualValues(t, formatTime(time.Time(user3.DeletedAt)), formatTime(time.Time(user4.DeletedAt)))
|
||||||
|
fmt.Println("user3", user3.DeletedAt, user4.DeletedAt)
|
||||||
|
}
|
6
xorm.go
6
xorm.go
|
@ -89,6 +89,12 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||||
tagHandlers: defaultTagHandlers,
|
tagHandlers: defaultTagHandlers,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if uri.DbType == core.SQLITE {
|
||||||
|
engine.DatabaseTZ = time.UTC
|
||||||
|
} else {
|
||||||
|
engine.DatabaseTZ = time.Local
|
||||||
|
}
|
||||||
|
|
||||||
logger := NewSimpleLogger(os.Stdout)
|
logger := NewSimpleLogger(os.Stdout)
|
||||||
logger.SetLevel(core.LOG_INFO)
|
logger.SetLevel(core.LOG_INFO)
|
||||||
engine.SetLogger(logger)
|
engine.SetLogger(logger)
|
||||||
|
|
10
xorm_test.go
10
xorm_test.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
_ "github.com/denisenkom/go-mssqldb"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
|
@ -45,7 +46,10 @@ func createEngine(dbType, connStr string) error {
|
||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
tableNames = append(tableNames, table.Name)
|
tableNames = append(tableNames, table.Name)
|
||||||
}
|
}
|
||||||
return testEngine.DropTables(tableNames...)
|
if err = testEngine.DropTables(tableNames...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareEngine() error {
|
func prepareEngine() error {
|
||||||
|
@ -70,8 +74,8 @@ func TestMain(m *testing.M) {
|
||||||
connString = *ptrConnStr
|
connString = *ptrConnStr
|
||||||
}
|
}
|
||||||
|
|
||||||
dbs := strings.Split(*db, ";")
|
dbs := strings.Split(*db, "::")
|
||||||
conns := strings.Split(connString, ";")
|
conns := strings.Split(connString, "::")
|
||||||
|
|
||||||
var res int
|
var res int
|
||||||
for i := 0; i < len(dbs); i++ {
|
for i := 0; i < len(dbs); i++ {
|
||||||
|
|
Loading…
Reference in New Issue