fix migrate failed and org dashboard failed on MSSQL database (#1448)
parent
cf6699fb4f
commit
5acfc7c4bc
@ -1 +0,0 @@ |
||||
xorm v0.6.0.1022 |
@ -1,42 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"errors" |
||||
"regexp" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
// func init() {
|
||||
// core.RegisterDriver("goracle", &goracleDriver{})
|
||||
// }
|
||||
|
||||
type goracleDriver struct { |
||||
} |
||||
|
||||
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
db := &core.Uri{DbType: core.ORACLE} |
||||
dsnPattern := regexp.MustCompile( |
||||
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
|
||||
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
|
||||
`\/(?P<dbname>.*?)` + // /dbname
|
||||
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN]
|
||||
matches := dsnPattern.FindStringSubmatch(dataSourceName) |
||||
//tlsConfigRegister := make(map[string]*tls.Config)
|
||||
names := dsnPattern.SubexpNames() |
||||
|
||||
for i, match := range matches { |
||||
switch names[i] { |
||||
case "dbname": |
||||
db.DbName = match |
||||
} |
||||
} |
||||
if db.DbName == "" { |
||||
return nil, errors.New("dbname is empty") |
||||
} |
||||
return db, nil |
||||
} |
@ -1,65 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"errors" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
type mymysqlDriver struct { |
||||
} |
||||
|
||||
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
db := &core.Uri{DbType: core.MYSQL} |
||||
|
||||
pd := strings.SplitN(dataSourceName, "*", 2) |
||||
if len(pd) == 2 { |
||||
// Parse protocol part of URI
|
||||
p := strings.SplitN(pd[0], ":", 2) |
||||
if len(p) != 2 { |
||||
return nil, errors.New("Wrong protocol part of URI") |
||||
} |
||||
db.Proto = p[0] |
||||
options := strings.Split(p[1], ",") |
||||
db.Raddr = options[0] |
||||
for _, o := range options[1:] { |
||||
kv := strings.SplitN(o, "=", 2) |
||||
var k, v string |
||||
if len(kv) == 2 { |
||||
k, v = kv[0], kv[1] |
||||
} else { |
||||
k, v = o, "true" |
||||
} |
||||
switch k { |
||||
case "laddr": |
||||
db.Laddr = v |
||||
case "timeout": |
||||
to, err := time.ParseDuration(v) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
db.Timeout = to |
||||
default: |
||||
return nil, errors.New("Unknown option: " + k) |
||||
} |
||||
} |
||||
// Remove protocol part
|
||||
pd = pd[1:] |
||||
} |
||||
// Parse database part of URI
|
||||
dup := strings.SplitN(pd[0], "/", 3) |
||||
if len(dup) != 3 { |
||||
return nil, errors.New("Wrong database part of URI") |
||||
} |
||||
db.DbName = dup[0] |
||||
db.User = dup[1] |
||||
db.Passwd = dup[2] |
||||
|
||||
return db, nil |
||||
} |
@ -1,50 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
type mysqlDriver struct { |
||||
} |
||||
|
||||
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
dsnPattern := regexp.MustCompile( |
||||
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
|
||||
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
|
||||
`\/(?P<dbname>.*?)` + // /dbname
|
||||
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN]
|
||||
matches := dsnPattern.FindStringSubmatch(dataSourceName) |
||||
//tlsConfigRegister := make(map[string]*tls.Config)
|
||||
names := dsnPattern.SubexpNames() |
||||
|
||||
uri := &core.Uri{DbType: core.MYSQL} |
||||
|
||||
for i, match := range matches { |
||||
switch names[i] { |
||||
case "dbname": |
||||
uri.DbName = match |
||||
case "params": |
||||
if len(match) > 0 { |
||||
kvs := strings.Split(match, "&") |
||||
for _, kv := range kvs { |
||||
splits := strings.Split(kv, "=") |
||||
if len(splits) == 2 { |
||||
switch splits[0] { |
||||
case "charset": |
||||
uri.Charset = splits[1] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
return uri, nil |
||||
} |
@ -1,37 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"errors" |
||||
"regexp" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
type oci8Driver struct { |
||||
} |
||||
|
||||
//dataSourceName=user/password@ipv4:port/dbname
|
||||
//dataSourceName=user/password@[ipv6]:port/dbname
|
||||
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
db := &core.Uri{DbType: core.ORACLE} |
||||
dsnPattern := regexp.MustCompile( |
||||
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
|
||||
`(?P<net>.*)` + // ip:port
|
||||
`\/(?P<dbname>.*)`) // dbname
|
||||
matches := dsnPattern.FindStringSubmatch(dataSourceName) |
||||
names := dsnPattern.SubexpNames() |
||||
for i, match := range matches { |
||||
switch names[i] { |
||||
case "dbname": |
||||
db.DbName = match |
||||
} |
||||
} |
||||
if db.DbName == "" { |
||||
return nil, errors.New("dbname is empty") |
||||
} |
||||
return db, nil |
||||
} |
@ -1,34 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"errors" |
||||
"strings" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
type odbcDriver struct { |
||||
} |
||||
|
||||
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
kv := strings.Split(dataSourceName, ";") |
||||
var dbName string |
||||
|
||||
for _, c := range kv { |
||||
vv := strings.Split(strings.TrimSpace(c), "=") |
||||
if len(vv) == 2 { |
||||
switch strings.ToLower(vv[0]) { |
||||
case "database": |
||||
dbName = vv[1] |
||||
} |
||||
} |
||||
} |
||||
if dbName == "" { |
||||
return nil, errors.New("no db name provided") |
||||
} |
||||
return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil |
||||
} |
@ -1,119 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"errors" |
||||
"fmt" |
||||
"net/url" |
||||
"sort" |
||||
"strings" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
type pqDriver struct { |
||||
} |
||||
|
||||
type values map[string]string |
||||
|
||||
func (vs values) Set(k, v string) { |
||||
vs[k] = v |
||||
} |
||||
|
||||
func (vs values) Get(k string) (v string) { |
||||
return vs[k] |
||||
} |
||||
|
||||
func errorf(s string, args ...interface{}) { |
||||
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) |
||||
} |
||||
|
||||
func parseURL(connstr string) (string, error) { |
||||
u, err := url.Parse(connstr) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if u.Scheme != "postgresql" && u.Scheme != "postgres" { |
||||
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) |
||||
} |
||||
|
||||
var kvs []string |
||||
escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) |
||||
accrue := func(k, v string) { |
||||
if v != "" { |
||||
kvs = append(kvs, k+"="+escaper.Replace(v)) |
||||
} |
||||
} |
||||
|
||||
if u.User != nil { |
||||
v := u.User.Username() |
||||
accrue("user", v) |
||||
|
||||
v, _ = u.User.Password() |
||||
accrue("password", v) |
||||
} |
||||
|
||||
i := strings.Index(u.Host, ":") |
||||
if i < 0 { |
||||
accrue("host", u.Host) |
||||
} else { |
||||
accrue("host", u.Host[:i]) |
||||
accrue("port", u.Host[i+1:]) |
||||
} |
||||
|
||||
if u.Path != "" { |
||||
accrue("dbname", u.Path[1:]) |
||||
} |
||||
|
||||
q := u.Query() |
||||
for k := range q { |
||||
accrue(k, q.Get(k)) |
||||
} |
||||
|
||||
sort.Strings(kvs) // Makes testing easier (not a performance concern)
|
||||
return strings.Join(kvs, " "), nil |
||||
} |
||||
|
||||
func parseOpts(name string, o values) { |
||||
if len(name) == 0 { |
||||
return |
||||
} |
||||
|
||||
name = strings.TrimSpace(name) |
||||
|
||||
ps := strings.Split(name, " ") |
||||
for _, p := range ps { |
||||
kv := strings.Split(p, "=") |
||||
if len(kv) < 2 { |
||||
errorf("invalid option: %q", p) |
||||
} |
||||
o.Set(kv[0], kv[1]) |
||||
} |
||||
} |
||||
|
||||
func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
db := &core.Uri{DbType: core.POSTGRES} |
||||
o := make(values) |
||||
var err error |
||||
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") { |
||||
dataSourceName, err = parseURL(dataSourceName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
parseOpts(dataSourceName, o) |
||||
|
||||
db.DbName = o.Get("dbname") |
||||
if db.DbName == "" { |
||||
return nil, errors.New("dbname is empty") |
||||
} |
||||
/*db.Schema = o.Get("schema") |
||||
if len(db.Schema) == 0 { |
||||
db.Schema = "public" |
||||
}*/ |
||||
return db, nil |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@ |
||||
// 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 |
||||
|
||||
// Incr provides a query string like "count = count + 1"
|
||||
func (session *Session) Incr(column string, arg ...interface{}) *Session { |
||||
session.Statement.Incr(column, arg...) |
||||
return session |
||||
} |
||||
|
||||
// Decr provides a query string like "count = count - 1"
|
||||
func (session *Session) Decr(column string, arg ...interface{}) *Session { |
||||
session.Statement.Decr(column, arg...) |
||||
return session |
||||
} |
||||
|
||||
// SetExpr provides a query string like "column = {expression}"
|
||||
func (session *Session) SetExpr(column string, expression string) *Session { |
||||
session.Statement.SetExpr(column, expression) |
||||
return session |
||||
} |
||||
|
||||
// Select provides some columns to special
|
||||
func (session *Session) Select(str string) *Session { |
||||
session.Statement.Select(str) |
||||
return session |
||||
} |
||||
|
||||
// Cols provides some columns to special
|
||||
func (session *Session) Cols(columns ...string) *Session { |
||||
session.Statement.Cols(columns...) |
||||
return session |
||||
} |
||||
|
||||
// AllCols ask all columns
|
||||
func (session *Session) AllCols() *Session { |
||||
session.Statement.AllCols() |
||||
return session |
||||
} |
||||
|
||||
// MustCols specify some columns must use even if they are empty
|
||||
func (session *Session) MustCols(columns ...string) *Session { |
||||
session.Statement.MustCols(columns...) |
||||
return session |
||||
} |
||||
|
||||
// UseBool automatically retrieve condition according struct, but
|
||||
// if struct has bool field, it will ignore them. So use UseBool
|
||||
// to tell system to do not ignore them.
|
||||
// If no parameters, it will use all the bool field of struct, or
|
||||
// it will use parameters's columns
|
||||
func (session *Session) UseBool(columns ...string) *Session { |
||||
session.Statement.UseBool(columns...) |
||||
return session |
||||
} |
||||
|
||||
// Distinct use for distinct columns. Caution: when you are using cache,
|
||||
// distinct will not be cached because cache system need id,
|
||||
// but distinct will not provide id
|
||||
func (session *Session) Distinct(columns ...string) *Session { |
||||
session.Statement.Distinct(columns...) |
||||
return session |
||||
} |
||||
|
||||
// Omit Only not use the parameters as select or update columns
|
||||
func (session *Session) Omit(columns ...string) *Session { |
||||
session.Statement.Omit(columns...) |
||||
return session |
||||
} |
||||
|
||||
// Nullable Set null when column is zero-value and nullable for update
|
||||
func (session *Session) Nullable(columns ...string) *Session { |
||||
session.Statement.Nullable(columns...) |
||||
return session |
||||
} |
||||
|
||||
// NoAutoTime means do not automatically give created field and updated field
|
||||
// the current time on the current session temporarily
|
||||
func (session *Session) NoAutoTime() *Session { |
||||
session.Statement.UseAutoTime = false |
||||
return session |
||||
} |
@ -0,0 +1,70 @@ |
||||
// 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 "github.com/go-xorm/builder" |
||||
|
||||
// Sql provides raw sql input parameter. When you have a complex SQL statement
|
||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
|
||||
//
|
||||
// Deprecated: use SQL instead.
|
||||
func (session *Session) Sql(query string, args ...interface{}) *Session { |
||||
return session.SQL(query, args...) |
||||
} |
||||
|
||||
// SQL provides raw sql input parameter. When you have a complex SQL statement
|
||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
|
||||
func (session *Session) SQL(query interface{}, args ...interface{}) *Session { |
||||
session.Statement.SQL(query, args...) |
||||
return session |
||||
} |
||||
|
||||
// Where provides custom query condition.
|
||||
func (session *Session) Where(query interface{}, args ...interface{}) *Session { |
||||
session.Statement.Where(query, args...) |
||||
return session |
||||
} |
||||
|
||||
// And provides custom query condition.
|
||||
func (session *Session) And(query interface{}, args ...interface{}) *Session { |
||||
session.Statement.And(query, args...) |
||||
return session |
||||
} |
||||
|
||||
// Or provides custom query condition.
|
||||
func (session *Session) Or(query interface{}, args ...interface{}) *Session { |
||||
session.Statement.Or(query, args...) |
||||
return session |
||||
} |
||||
|
||||
// Id provides converting id as a query condition
|
||||
//
|
||||
// Deprecated: use ID instead
|
||||
func (session *Session) Id(id interface{}) *Session { |
||||
return session.ID(id) |
||||
} |
||||
|
||||
// ID provides converting id as a query condition
|
||||
func (session *Session) ID(id interface{}) *Session { |
||||
session.Statement.ID(id) |
||||
return session |
||||
} |
||||
|
||||
// In provides a query string like "id in (1, 2, 3)"
|
||||
func (session *Session) In(column string, args ...interface{}) *Session { |
||||
session.Statement.In(column, args...) |
||||
return session |
||||
} |
||||
|
||||
// NotIn provides a query string like "id in (1, 2, 3)"
|
||||
func (session *Session) NotIn(column string, args ...interface{}) *Session { |
||||
session.Statement.NotIn(column, args...) |
||||
return session |
||||
} |
||||
|
||||
// Conds returns session query conditions
|
||||
func (session *Session) Conds() builder.Cond { |
||||
return session.Statement.cond |
||||
} |
@ -0,0 +1,673 @@ |
||||
// 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 ( |
||||
"database/sql" |
||||
"database/sql/driver" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"reflect" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) { |
||||
sdata := strings.TrimSpace(data) |
||||
var x time.Time |
||||
var err error |
||||
|
||||
if sdata == "0000-00-00 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
|
||||
// time stamp
|
||||
sd, err := strconv.ParseInt(sdata, 10, 64) |
||||
if err == nil { |
||||
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) |
||||
} else { |
||||
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, "-") { |
||||
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation) |
||||
session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) |
||||
if err != nil { |
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation) |
||||
session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) |
||||
} |
||||
if err != nil { |
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation) |
||||
session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) |
||||
} |
||||
|
||||
} else if len(sdata) == 19 && strings.Contains(sdata, "-") { |
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation) |
||||
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] == '-' { |
||||
x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation) |
||||
session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) |
||||
} else if col.SQLType.Name == core.Time { |
||||
if strings.Contains(sdata, " ") { |
||||
ssd := strings.Split(sdata, " ") |
||||
sdata = ssd[1] |
||||
} |
||||
|
||||
sdata = strings.TrimSpace(sdata) |
||||
if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 { |
||||
sdata = sdata[len(sdata)-8:] |
||||
} |
||||
|
||||
st := fmt.Sprintf("2006-01-02 %v", sdata) |
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation) |
||||
session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) |
||||
} else { |
||||
outErr = fmt.Errorf("unsupported time format %v", sdata) |
||||
return |
||||
} |
||||
if err != nil { |
||||
outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err) |
||||
return |
||||
} |
||||
outTime = x |
||||
return |
||||
} |
||||
|
||||
func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) { |
||||
return session.str2Time(col, string(data)) |
||||
} |
||||
|
||||
// convert a db data([]byte) to a field value
|
||||
func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error { |
||||
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { |
||||
return structConvert.FromDB(data) |
||||
} |
||||
|
||||
if structConvert, ok := fieldValue.Interface().(core.Conversion); ok { |
||||
return structConvert.FromDB(data) |
||||
} |
||||
|
||||
var v interface{} |
||||
key := col.Name |
||||
fieldType := fieldValue.Type() |
||||
|
||||
switch fieldType.Kind() { |
||||
case reflect.Complex64, reflect.Complex128: |
||||
x := reflect.New(fieldType) |
||||
if len(data) > 0 { |
||||
err := json.Unmarshal(data, x.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return err |
||||
} |
||||
fieldValue.Set(x.Elem()) |
||||
} |
||||
case reflect.Slice, reflect.Array, reflect.Map: |
||||
v = data |
||||
t := fieldType.Elem() |
||||
k := t.Kind() |
||||
if col.SQLType.IsText() { |
||||
x := reflect.New(fieldType) |
||||
if len(data) > 0 { |
||||
err := json.Unmarshal(data, x.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return err |
||||
} |
||||
fieldValue.Set(x.Elem()) |
||||
} |
||||
} else if col.SQLType.IsBlob() { |
||||
if k == reflect.Uint8 { |
||||
fieldValue.Set(reflect.ValueOf(v)) |
||||
} else { |
||||
x := reflect.New(fieldType) |
||||
if len(data) > 0 { |
||||
err := json.Unmarshal(data, x.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return err |
||||
} |
||||
fieldValue.Set(x.Elem()) |
||||
} |
||||
} |
||||
} else { |
||||
return ErrUnSupportedType |
||||
} |
||||
case reflect.String: |
||||
fieldValue.SetString(string(data)) |
||||
case reflect.Bool: |
||||
d := string(data) |
||||
v, err := strconv.ParseBool(d) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as bool: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(v)) |
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
||||
sdata := string(data) |
||||
var x int64 |
||||
var err error |
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit && |
||||
session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
|
||||
if len(data) == 1 { |
||||
x = int64(data[0]) |
||||
} else { |
||||
x = 0 |
||||
} |
||||
} else if strings.HasPrefix(sdata, "0x") { |
||||
x, err = strconv.ParseInt(sdata, 16, 64) |
||||
} else if strings.HasPrefix(sdata, "0") { |
||||
x, err = strconv.ParseInt(sdata, 8, 64) |
||||
} else if strings.EqualFold(sdata, "true") { |
||||
x = 1 |
||||
} else if strings.EqualFold(sdata, "false") { |
||||
x = 0 |
||||
} else { |
||||
x, err = strconv.ParseInt(sdata, 10, 64) |
||||
} |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.SetInt(x) |
||||
case reflect.Float32, reflect.Float64: |
||||
x, err := strconv.ParseFloat(string(data), 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as float64: %s", key, err.Error()) |
||||
} |
||||
fieldValue.SetFloat(x) |
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: |
||||
x, err := strconv.ParseUint(string(data), 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.SetUint(x) |
||||
//Currently only support Time type
|
||||
case reflect.Struct: |
||||
// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
|
||||
if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { |
||||
if err := nulVal.Scan(data); err != nil { |
||||
return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error()) |
||||
} |
||||
} else { |
||||
if fieldType.ConvertibleTo(core.TimeType) { |
||||
x, err := session.byte2Time(col, data) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
v = x |
||||
fieldValue.Set(reflect.ValueOf(v).Convert(fieldType)) |
||||
} else if session.Statement.UseCascade { |
||||
table, err := session.Engine.autoMapType(*fieldValue) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// TODO: current only support 1 primary key
|
||||
if len(table.PrimaryKeys) > 1 { |
||||
panic("unsupported composited primary key cascade") |
||||
} |
||||
var pk = make(core.PK, len(table.PrimaryKeys)) |
||||
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) |
||||
pk[0], err = str2PK(string(data), rawValueType) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if !isPKZero(pk) { |
||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||
// property to be fetched lazily
|
||||
structInter := reflect.New(fieldValue.Type()) |
||||
newsession := session.Engine.NewSession() |
||||
defer newsession.Close() |
||||
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if has { |
||||
v = structInter.Elem().Interface() |
||||
fieldValue.Set(reflect.ValueOf(v)) |
||||
} else { |
||||
return errors.New("cascade obj is not exist") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
case reflect.Ptr: |
||||
// !nashtsai! TODO merge duplicated codes above
|
||||
//typeStr := fieldType.String()
|
||||
switch fieldType.Elem().Kind() { |
||||
// case "*string":
|
||||
case core.StringType.Kind(): |
||||
x := string(data) |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*bool":
|
||||
case core.BoolType.Kind(): |
||||
d := string(data) |
||||
v, err := strconv.ParseBool(d) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as bool: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType)) |
||||
// case "*complex64":
|
||||
case core.Complex64Type.Kind(): |
||||
var x complex64 |
||||
if len(data) > 0 { |
||||
err := json.Unmarshal(data, &x) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return err |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
} |
||||
// case "*complex128":
|
||||
case core.Complex128Type.Kind(): |
||||
var x complex128 |
||||
if len(data) > 0 { |
||||
err := json.Unmarshal(data, &x) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return err |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
} |
||||
// case "*float64":
|
||||
case core.Float64Type.Kind(): |
||||
x, err := strconv.ParseFloat(string(data), 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as float64: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*float32":
|
||||
case core.Float32Type.Kind(): |
||||
var x float32 |
||||
x1, err := strconv.ParseFloat(string(data), 32) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as float32: %s", key, err.Error()) |
||||
} |
||||
x = float32(x1) |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*uint64":
|
||||
case core.Uint64Type.Kind(): |
||||
var x uint64 |
||||
x, err := strconv.ParseUint(string(data), 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*uint":
|
||||
case core.UintType.Kind(): |
||||
var x uint |
||||
x1, err := strconv.ParseUint(string(data), 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
x = uint(x1) |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*uint32":
|
||||
case core.Uint32Type.Kind(): |
||||
var x uint32 |
||||
x1, err := strconv.ParseUint(string(data), 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
x = uint32(x1) |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*uint8":
|
||||
case core.Uint8Type.Kind(): |
||||
var x uint8 |
||||
x1, err := strconv.ParseUint(string(data), 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
x = uint8(x1) |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*uint16":
|
||||
case core.Uint16Type.Kind(): |
||||
var x uint16 |
||||
x1, err := strconv.ParseUint(string(data), 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
x = uint16(x1) |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*int64":
|
||||
case core.Int64Type.Kind(): |
||||
sdata := string(data) |
||||
var x int64 |
||||
var err error |
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit && |
||||
strings.Contains(session.Engine.DriverName(), "mysql") { |
||||
if len(data) == 1 { |
||||
x = int64(data[0]) |
||||
} else { |
||||
x = 0 |
||||
} |
||||
} else if strings.HasPrefix(sdata, "0x") { |
||||
x, err = strconv.ParseInt(sdata, 16, 64) |
||||
} else if strings.HasPrefix(sdata, "0") { |
||||
x, err = strconv.ParseInt(sdata, 8, 64) |
||||
} else { |
||||
x, err = strconv.ParseInt(sdata, 10, 64) |
||||
} |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*int":
|
||||
case core.IntType.Kind(): |
||||
sdata := string(data) |
||||
var x int |
||||
var x1 int64 |
||||
var err error |
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit && |
||||
strings.Contains(session.Engine.DriverName(), "mysql") { |
||||
if len(data) == 1 { |
||||
x = int(data[0]) |
||||
} else { |
||||
x = 0 |
||||
} |
||||
} else if strings.HasPrefix(sdata, "0x") { |
||||
x1, err = strconv.ParseInt(sdata, 16, 64) |
||||
x = int(x1) |
||||
} else if strings.HasPrefix(sdata, "0") { |
||||
x1, err = strconv.ParseInt(sdata, 8, 64) |
||||
x = int(x1) |
||||
} else { |
||||
x1, err = strconv.ParseInt(sdata, 10, 64) |
||||
x = int(x1) |
||||
} |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*int32":
|
||||
case core.Int32Type.Kind(): |
||||
sdata := string(data) |
||||
var x int32 |
||||
var x1 int64 |
||||
var err error |
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit && |
||||
session.Engine.dialect.DBType() == core.MYSQL { |
||||
if len(data) == 1 { |
||||
x = int32(data[0]) |
||||
} else { |
||||
x = 0 |
||||
} |
||||
} else if strings.HasPrefix(sdata, "0x") { |
||||
x1, err = strconv.ParseInt(sdata, 16, 64) |
||||
x = int32(x1) |
||||
} else if strings.HasPrefix(sdata, "0") { |
||||
x1, err = strconv.ParseInt(sdata, 8, 64) |
||||
x = int32(x1) |
||||
} else { |
||||
x1, err = strconv.ParseInt(sdata, 10, 64) |
||||
x = int32(x1) |
||||
} |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*int8":
|
||||
case core.Int8Type.Kind(): |
||||
sdata := string(data) |
||||
var x int8 |
||||
var x1 int64 |
||||
var err error |
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit && |
||||
strings.Contains(session.Engine.DriverName(), "mysql") { |
||||
if len(data) == 1 { |
||||
x = int8(data[0]) |
||||
} else { |
||||
x = 0 |
||||
} |
||||
} else if strings.HasPrefix(sdata, "0x") { |
||||
x1, err = strconv.ParseInt(sdata, 16, 64) |
||||
x = int8(x1) |
||||
} else if strings.HasPrefix(sdata, "0") { |
||||
x1, err = strconv.ParseInt(sdata, 8, 64) |
||||
x = int8(x1) |
||||
} else { |
||||
x1, err = strconv.ParseInt(sdata, 10, 64) |
||||
x = int8(x1) |
||||
} |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*int16":
|
||||
case core.Int16Type.Kind(): |
||||
sdata := string(data) |
||||
var x int16 |
||||
var x1 int64 |
||||
var err error |
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit && |
||||
strings.Contains(session.Engine.DriverName(), "mysql") { |
||||
if len(data) == 1 { |
||||
x = int16(data[0]) |
||||
} else { |
||||
x = 0 |
||||
} |
||||
} else if strings.HasPrefix(sdata, "0x") { |
||||
x1, err = strconv.ParseInt(sdata, 16, 64) |
||||
x = int16(x1) |
||||
} else if strings.HasPrefix(sdata, "0") { |
||||
x1, err = strconv.ParseInt(sdata, 8, 64) |
||||
x = int16(x1) |
||||
} else { |
||||
x1, err = strconv.ParseInt(sdata, 10, 64) |
||||
x = int16(x1) |
||||
} |
||||
if err != nil { |
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error()) |
||||
} |
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) |
||||
// case "*SomeStruct":
|
||||
case reflect.Struct: |
||||
switch fieldType { |
||||
// case "*.time.Time":
|
||||
case core.PtrTimeType: |
||||
x, err := session.byte2Time(col, data) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
v = x |
||||
fieldValue.Set(reflect.ValueOf(&x)) |
||||
default: |
||||
if session.Statement.UseCascade { |
||||
structInter := reflect.New(fieldType.Elem()) |
||||
table, err := session.Engine.autoMapType(structInter.Elem()) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if len(table.PrimaryKeys) > 1 { |
||||
panic("unsupported composited primary key cascade") |
||||
} |
||||
var pk = make(core.PK, len(table.PrimaryKeys)) |
||||
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) |
||||
pk[0], err = str2PK(string(data), rawValueType) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if !isPKZero(pk) { |
||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||
// property to be fetched lazily
|
||||
newsession := session.Engine.NewSession() |
||||
defer newsession.Close() |
||||
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if has { |
||||
v = structInter.Interface() |
||||
fieldValue.Set(reflect.ValueOf(v)) |
||||
} else { |
||||
return errors.New("cascade obj is not exist") |
||||
} |
||||
} |
||||
} else { |
||||
return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) |
||||
} |
||||
} |
||||
default: |
||||
return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) |
||||
} |
||||
default: |
||||
return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// convert a field value of a struct to interface for put into db
|
||||
func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) { |
||||
if fieldValue.CanAddr() { |
||||
if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { |
||||
data, err := fieldConvert.ToDB() |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
if col.SQLType.IsBlob() { |
||||
return data, nil |
||||
} |
||||
return string(data), nil |
||||
} |
||||
} |
||||
|
||||
if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok { |
||||
data, err := fieldConvert.ToDB() |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
if col.SQLType.IsBlob() { |
||||
return data, nil |
||||
} |
||||
return string(data), nil |
||||
} |
||||
|
||||
fieldType := fieldValue.Type() |
||||
k := fieldType.Kind() |
||||
if k == reflect.Ptr { |
||||
if fieldValue.IsNil() { |
||||
return nil, nil |
||||
} else if !fieldValue.IsValid() { |
||||
session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid") |
||||
return nil, nil |
||||
} else { |
||||
// !nashtsai! deference pointer type to instance type
|
||||
fieldValue = fieldValue.Elem() |
||||
fieldType = fieldValue.Type() |
||||
k = fieldType.Kind() |
||||
} |
||||
} |
||||
|
||||
switch k { |
||||
case reflect.Bool: |
||||
return fieldValue.Bool(), nil |
||||
case reflect.String: |
||||
return fieldValue.String(), nil |
||||
case reflect.Struct: |
||||
if fieldType.ConvertibleTo(core.TimeType) { |
||||
t := fieldValue.Convert(core.TimeType).Interface().(time.Time) |
||||
if session.Engine.dialect.DBType() == core.MSSQL { |
||||
if t.IsZero() { |
||||
return nil, nil |
||||
} |
||||
} |
||||
tf := session.Engine.FormatTime(col.SQLType.Name, t) |
||||
return tf, nil |
||||
} |
||||
|
||||
if !col.SQLType.IsJson() { |
||||
// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
|
||||
if v, ok := fieldValue.Interface().(driver.Valuer); ok { |
||||
return v.Value() |
||||
} |
||||
|
||||
fieldTable, err := session.Engine.autoMapType(fieldValue) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if len(fieldTable.PrimaryKeys) == 1 { |
||||
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName) |
||||
return pkField.Interface(), nil |
||||
} |
||||
return 0, fmt.Errorf("no primary key for col %v", col.Name) |
||||
} |
||||
|
||||
if col.SQLType.IsText() { |
||||
bytes, err := json.Marshal(fieldValue.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return 0, err |
||||
} |
||||
return string(bytes), nil |
||||
} else if col.SQLType.IsBlob() { |
||||
bytes, err := json.Marshal(fieldValue.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return 0, err |
||||
} |
||||
return bytes, nil |
||||
} |
||||
return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type()) |
||||
case reflect.Complex64, reflect.Complex128: |
||||
bytes, err := json.Marshal(fieldValue.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return 0, err |
||||
} |
||||
return string(bytes), nil |
||||
case reflect.Array, reflect.Slice, reflect.Map: |
||||
if !fieldValue.IsValid() { |
||||
return fieldValue.Interface(), nil |
||||
} |
||||
|
||||
if col.SQLType.IsText() { |
||||
bytes, err := json.Marshal(fieldValue.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return 0, err |
||||
} |
||||
return string(bytes), nil |
||||
} else if col.SQLType.IsBlob() { |
||||
var bytes []byte |
||||
var err error |
||||
if (k == reflect.Array || k == reflect.Slice) && |
||||
(fieldValue.Type().Elem().Kind() == reflect.Uint8) { |
||||
bytes = fieldValue.Bytes() |
||||
} else { |
||||
bytes, err = json.Marshal(fieldValue.Interface()) |
||||
if err != nil { |
||||
session.Engine.logger.Error(err) |
||||
return 0, err |
||||
} |
||||
} |
||||
return bytes, nil |
||||
} |
||||
return nil, ErrUnSupportedType |
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: |
||||
return int64(fieldValue.Uint()), nil |
||||
default: |
||||
return fieldValue.Interface(), nil |
||||
} |
||||
} |
@ -1,20 +0,0 @@ |
||||
// Copyright 2015 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 ( |
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
// func init() {
|
||||
// core.RegisterDriver("sqlite3", &sqlite3Driver{})
|
||||
// }
|
||||
|
||||
type sqlite3Driver struct { |
||||
} |
||||
|
||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { |
||||
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil |
||||
} |
@ -0,0 +1,281 @@ |
||||
// 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" |
||||
"reflect" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/go-xorm/core" |
||||
) |
||||
|
||||
type tagContext struct { |
||||
tagName string |
||||
params []string |
||||
preTag, nextTag string |
||||
table *core.Table |
||||
col *core.Column |
||||
fieldValue reflect.Value |
||||
isIndex bool |
||||
isUnique bool |
||||
indexNames map[string]int |
||||
engine *Engine |
||||
hasCacheTag bool |
||||
hasNoCacheTag bool |
||||
ignoreNext bool |
||||
} |
||||
|
||||
// tagHandler describes tag handler for XORM
|
||||
type tagHandler func(ctx *tagContext) error |
||||
|
||||
var ( |
||||
// defaultTagHandlers enumerates all the default tag handler
|
||||
defaultTagHandlers = map[string]tagHandler{ |
||||
"<-": OnlyFromDBTagHandler, |
||||
"->": OnlyToDBTagHandler, |
||||
"PK": PKTagHandler, |
||||
"NULL": NULLTagHandler, |
||||
"NOT": IgnoreTagHandler, |
||||
"AUTOINCR": AutoIncrTagHandler, |
||||
"DEFAULT": DefaultTagHandler, |
||||
"CREATED": CreatedTagHandler, |
||||
"UPDATED": UpdatedTagHandler, |
||||
"DELETED": DeletedTagHandler, |
||||
"VERSION": VersionTagHandler, |
||||
"UTC": UTCTagHandler, |
||||
"LOCAL": LocalTagHandler, |
||||
"NOTNULL": NotNullTagHandler, |
||||
"INDEX": IndexTagHandler, |
||||
"UNIQUE": UniqueTagHandler, |
||||
"CACHE": CacheTagHandler, |
||||
"NOCACHE": NoCacheTagHandler, |
||||
} |
||||
) |
||||
|
||||
func init() { |
||||
for k := range core.SqlTypes { |
||||
defaultTagHandlers[k] = SQLTypeTagHandler |
||||
} |
||||
} |
||||
|
||||
// IgnoreTagHandler describes ignored tag handler
|
||||
func IgnoreTagHandler(ctx *tagContext) error { |
||||
return nil |
||||
} |
||||
|
||||
// OnlyFromDBTagHandler describes mapping direction tag handler
|
||||
func OnlyFromDBTagHandler(ctx *tagContext) error { |
||||
ctx.col.MapType = core.ONLYFROMDB |
||||
return nil |
||||
} |
||||
|
||||
// OnlyToDBTagHandler describes mapping direction tag handler
|
||||
func OnlyToDBTagHandler(ctx *tagContext) error { |
||||
ctx.col.MapType = core.ONLYTODB |
||||
return nil |
||||
} |
||||
|
||||
// PKTagHandler decribes primary key tag handler
|
||||
func PKTagHandler(ctx *tagContext) error { |
||||
ctx.col.IsPrimaryKey = true |
||||
ctx.col.Nullable = false |
||||
return nil |
||||
} |
||||
|
||||
// NULLTagHandler describes null tag handler
|
||||
func NULLTagHandler(ctx *tagContext) error { |
||||
ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT") |
||||
return nil |
||||
} |
||||
|
||||
// NotNullTagHandler describes notnull tag handler
|
||||
func NotNullTagHandler(ctx *tagContext) error { |
||||
ctx.col.Nullable = false |
||||
return nil |
||||
} |
||||
|
||||
// AutoIncrTagHandler describes autoincr tag handler
|
||||
func AutoIncrTagHandler(ctx *tagContext) error { |
||||
ctx.col.IsAutoIncrement = true |
||||
/* |
||||
if len(ctx.params) > 0 { |
||||
autoStartInt, err := strconv.Atoi(ctx.params[0]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
ctx.col.AutoIncrStart = autoStartInt |
||||
} else { |
||||
ctx.col.AutoIncrStart = 1 |
||||
} |
||||
*/ |
||||
return nil |
||||
} |
||||
|
||||
// DefaultTagHandler describes default tag handler
|
||||
func DefaultTagHandler(ctx *tagContext) error { |
||||
if len(ctx.params) > 0 { |
||||
ctx.col.Default = ctx.params[0] |
||||
} else { |
||||
ctx.col.Default = ctx.nextTag |
||||
ctx.ignoreNext = true |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// CreatedTagHandler describes created tag handler
|
||||
func CreatedTagHandler(ctx *tagContext) error { |
||||
ctx.col.IsCreated = true |
||||
return nil |
||||
} |
||||
|
||||
// VersionTagHandler describes version tag handler
|
||||
func VersionTagHandler(ctx *tagContext) error { |
||||
ctx.col.IsVersion = true |
||||
ctx.col.Default = "1" |
||||
return nil |
||||
} |
||||
|
||||
// UTCTagHandler describes utc tag handler
|
||||
func UTCTagHandler(ctx *tagContext) error { |
||||
ctx.col.TimeZone = time.UTC |
||||
return nil |
||||
} |
||||
|
||||
// LocalTagHandler describes local tag handler
|
||||
func LocalTagHandler(ctx *tagContext) error { |
||||
if len(ctx.params) == 0 { |
||||
ctx.col.TimeZone = time.Local |
||||
} else { |
||||
var err error |
||||
ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// UpdatedTagHandler describes updated tag handler
|
||||
func UpdatedTagHandler(ctx *tagContext) error { |
||||
ctx.col.IsUpdated = true |
||||
return nil |
||||
} |
||||
|
||||
// DeletedTagHandler describes deleted tag handler
|
||||
func DeletedTagHandler(ctx *tagContext) error { |
||||
ctx.col.IsDeleted = true |
||||
return nil |
||||
} |
||||
|
||||
// IndexTagHandler describes index tag handler
|
||||
func IndexTagHandler(ctx *tagContext) error { |
||||
if len(ctx.params) > 0 { |
||||
ctx.indexNames[ctx.params[0]] = core.IndexType |
||||
} else { |
||||
ctx.isIndex = true |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// UniqueTagHandler describes unique tag handler
|
||||
func UniqueTagHandler(ctx *tagContext) error { |
||||
if len(ctx.params) > 0 { |
||||
ctx.indexNames[ctx.params[0]] = core.UniqueType |
||||
} else { |
||||
ctx.isUnique = true |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// SQLTypeTagHandler describes SQL Type tag handler
|
||||
func SQLTypeTagHandler(ctx *tagContext) error { |
||||
ctx.col.SQLType = core.SQLType{Name: ctx.tagName} |
||||
if len(ctx.params) > 0 { |
||||
if ctx.tagName == core.Enum { |
||||
ctx.col.EnumOptions = make(map[string]int) |
||||
for k, v := range ctx.params { |
||||
v = strings.TrimSpace(v) |
||||
v = strings.Trim(v, "'") |
||||
ctx.col.EnumOptions[v] = k |
||||
} |
||||
} else if ctx.tagName == core.Set { |
||||
ctx.col.SetOptions = make(map[string]int) |
||||
for k, v := range ctx.params { |
||||
v = strings.TrimSpace(v) |
||||
v = strings.Trim(v, "'") |
||||
ctx.col.SetOptions[v] = k |
||||
} |
||||
} else { |
||||
var err error |
||||
if len(ctx.params) == 2 { |
||||
ctx.col.Length, err = strconv.Atoi(ctx.params[0]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
ctx.col.Length2, err = strconv.Atoi(ctx.params[1]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} else if len(ctx.params) == 1 { |
||||
ctx.col.Length, err = strconv.Atoi(ctx.params[0]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// ExtendsTagHandler describes extends tag handler
|
||||
func ExtendsTagHandler(ctx *tagContext) error { |
||||
var fieldValue = ctx.fieldValue |
||||
switch fieldValue.Kind() { |
||||
case reflect.Ptr: |
||||
f := fieldValue.Type().Elem() |
||||
if f.Kind() == reflect.Struct { |
||||
fieldPtr := fieldValue |
||||
fieldValue = fieldValue.Elem() |
||||
if !fieldValue.IsValid() || fieldPtr.IsNil() { |
||||
fieldValue = reflect.New(f).Elem() |
||||
} |
||||
} |
||||
fallthrough |
||||
case reflect.Struct: |
||||
parentTable, err := ctx.engine.mapType(fieldValue) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
for _, col := range parentTable.Columns() { |
||||
col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName) |
||||
ctx.table.AddColumn(col) |
||||
for indexName, indexType := range col.Indexes { |
||||
addIndex(indexName, ctx.table, col, indexType) |
||||
} |
||||
} |
||||
default: |
||||
//TODO: warning
|
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// CacheTagHandler describes cache tag handler
|
||||
func CacheTagHandler(ctx *tagContext) error { |
||||
if !ctx.hasCacheTag { |
||||
ctx.hasCacheTag = true |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// NoCacheTagHandler describes nocache tag handler
|
||||
func NoCacheTagHandler(ctx *tagContext) error { |
||||
if !ctx.hasNoCacheTag { |
||||
ctx.hasNoCacheTag = true |
||||
} |
||||
return nil |
||||
} |
Loading…
Reference in new issue