Update xorm to v1 (#323)
Fix limit for databases other than sqlite go mod tidy && go mod vendor Remove unneeded break statements Make everything work with the new xorm version Fix xorm logging Fix lint Fix redis init Fix using id field Fix database init for testing Change default database log level Add xorm logger Use const for postgres go mod tidy Merge branch 'master' into update/xorm # Conflicts: # go.mod # go.sum # vendor/modules.txt go mod vendor Fix loading fixtures for postgres Go mod vendor1 Update xorm to version 1 Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/323
This commit is contained in:
79
vendor/xorm.io/xorm/internal/statements/cache.go
generated
vendored
Normal file
79
vendor/xorm.io/xorm/internal/statements/cache.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2019 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 statements
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) ConvertIDSQL(sqlStr string) string {
|
||||
if statement.RefTable != nil {
|
||||
cols := statement.RefTable.PKColumns()
|
||||
if len(cols) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
colstrs := statement.joinColumns(cols, false)
|
||||
sqls := utils.SplitNNoCase(sqlStr, " from ", 2)
|
||||
if len(sqls) != 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var top string
|
||||
pLimitN := statement.LimitN
|
||||
if pLimitN != nil && statement.dialect.URI().DBType == schemas.MSSQL {
|
||||
top = fmt.Sprintf("TOP %d ", *pLimitN)
|
||||
}
|
||||
|
||||
newsql := fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1])
|
||||
return newsql
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (statement *Statement) ConvertUpdateSQL(sqlStr string) (string, string) {
|
||||
if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
colstrs := statement.joinColumns(statement.RefTable.PKColumns(), true)
|
||||
sqls := utils.SplitNNoCase(sqlStr, "where", 2)
|
||||
if len(sqls) != 2 {
|
||||
if len(sqls) == 1 {
|
||||
return sqls[0], fmt.Sprintf("SELECT %v FROM %v",
|
||||
colstrs, statement.quote(statement.TableName()))
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
var whereStr = sqls[1]
|
||||
|
||||
// TODO: for postgres only, if any other database?
|
||||
var paraStr string
|
||||
if statement.dialect.URI().DBType == schemas.POSTGRES {
|
||||
paraStr = "$"
|
||||
} else if statement.dialect.URI().DBType == schemas.MSSQL {
|
||||
paraStr = ":"
|
||||
}
|
||||
|
||||
if paraStr != "" {
|
||||
if strings.Contains(sqls[1], paraStr) {
|
||||
dollers := strings.Split(sqls[1], paraStr)
|
||||
whereStr = dollers[0]
|
||||
for i, c := range dollers[1:] {
|
||||
ccs := strings.SplitN(c, " ", 2)
|
||||
whereStr += fmt.Sprintf(paraStr+"%v %v", i+1, ccs[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v",
|
||||
colstrs, statement.quote(statement.TableName()),
|
||||
whereStr)
|
||||
}
|
66
vendor/xorm.io/xorm/internal/statements/column_map.go
generated
vendored
Normal file
66
vendor/xorm.io/xorm/internal/statements/column_map.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2019 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 statements
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type columnMap []string
|
||||
|
||||
func (m columnMap) Contain(colName string) bool {
|
||||
if len(m) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
n := len(colName)
|
||||
for _, mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, colName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m columnMap) Len() int {
|
||||
return len(m)
|
||||
}
|
||||
|
||||
func (m columnMap) IsEmpty() bool {
|
||||
return len(m) == 0
|
||||
}
|
||||
|
||||
func (m *columnMap) Add(colName string) bool {
|
||||
if m.Contain(colName) {
|
||||
return false
|
||||
}
|
||||
*m = append(*m, colName)
|
||||
return true
|
||||
}
|
||||
|
||||
func getFlagForColumn(m map[string]bool, col *schemas.Column) (val bool, has bool) {
|
||||
if len(m) == 0 {
|
||||
return false, false
|
||||
}
|
||||
|
||||
n := len(col.Name)
|
||||
|
||||
for mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, col.Name) {
|
||||
return m[mk], true
|
||||
}
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
126
vendor/xorm.io/xorm/internal/statements/expr_param.go
generated
vendored
Normal file
126
vendor/xorm.io/xorm/internal/statements/expr_param.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright 2019 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 statements
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type ErrUnsupportedExprType struct {
|
||||
tp string
|
||||
}
|
||||
|
||||
func (err ErrUnsupportedExprType) Error() string {
|
||||
return fmt.Sprintf("Unsupported expression type: %v", err.tp)
|
||||
}
|
||||
|
||||
type exprParam struct {
|
||||
colName string
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
type exprParams struct {
|
||||
ColNames []string
|
||||
Args []interface{}
|
||||
}
|
||||
|
||||
func (exprs *exprParams) Len() int {
|
||||
return len(exprs.ColNames)
|
||||
}
|
||||
|
||||
func (exprs *exprParams) addParam(colName string, arg interface{}) {
|
||||
exprs.ColNames = append(exprs.ColNames, colName)
|
||||
exprs.Args = append(exprs.Args, arg)
|
||||
}
|
||||
|
||||
func (exprs *exprParams) IsColExist(colName string) bool {
|
||||
for _, name := range exprs.ColNames {
|
||||
if strings.EqualFold(schemas.CommonQuoter.Trim(name), schemas.CommonQuoter.Trim(colName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (exprs *exprParams) getByName(colName string) (exprParam, bool) {
|
||||
for i, name := range exprs.ColNames {
|
||||
if strings.EqualFold(name, colName) {
|
||||
return exprParam{name, exprs.Args[i]}, true
|
||||
}
|
||||
}
|
||||
return exprParam{}, false
|
||||
}
|
||||
|
||||
func (exprs *exprParams) WriteArgs(w *builder.BytesWriter) error {
|
||||
for i, expr := range exprs.Args {
|
||||
switch arg := expr.(type) {
|
||||
case *builder.Builder:
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := arg.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case string:
|
||||
if arg == "" {
|
||||
arg = "''"
|
||||
}
|
||||
if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if _, err := w.WriteString("?"); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(arg)
|
||||
}
|
||||
if i != len(exprs.Args)-1 {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (exprs *exprParams) writeNameArgs(w *builder.BytesWriter) error {
|
||||
for i, colName := range exprs.ColNames {
|
||||
if _, err := w.WriteString(colName); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString("="); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch arg := exprs.Args[i].(type) {
|
||||
case *builder.Builder:
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := arg.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
w.Append(exprs.Args[i])
|
||||
}
|
||||
|
||||
if i+1 != len(exprs.ColNames) {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
143
vendor/xorm.io/xorm/internal/statements/insert.go
generated
vendored
Normal file
143
vendor/xorm.io/xorm/internal/statements/insert.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright 2020 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 statements
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) writeInsertOutput(buf *strings.Builder, table *schemas.Table) error {
|
||||
if statement.dialect.URI().DBType == schemas.MSSQL && len(table.AutoIncrement) > 0 {
|
||||
if _, err := buf.WriteString(" OUTPUT Inserted."); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := buf.WriteString(table.AutoIncrement); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) (string, []interface{}, error) {
|
||||
var (
|
||||
table = statement.RefTable
|
||||
tableName = statement.TableName()
|
||||
exprs = statement.ExprColumns
|
||||
colPlaces = strings.Repeat("?, ", len(colNames))
|
||||
)
|
||||
if exprs.Len() <= 0 && len(colPlaces) > 0 {
|
||||
colPlaces = colPlaces[0 : len(colPlaces)-2]
|
||||
}
|
||||
|
||||
var buf = builder.NewWriter()
|
||||
if _, err := buf.WriteString("INSERT INTO "); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if err := statement.dialect.Quoter().QuoteTo(buf.Builder, tableName); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if len(colPlaces) <= 0 {
|
||||
if statement.dialect.URI().DBType == schemas.MYSQL {
|
||||
if _, err := buf.WriteString(" VALUES ()"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
if err := statement.writeInsertOutput(buf.Builder, table); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if _, err := buf.WriteString(" DEFAULT VALUES"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := buf.WriteString(" ("); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames...), ","); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if statement.Conds().IsValid() {
|
||||
if _, err := buf.WriteString(")"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if err := statement.writeInsertOutput(buf.Builder, table); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if _, err := buf.WriteString(" SELECT "); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if err := statement.WriteArgs(buf, args); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if len(exprs.Args) > 0 {
|
||||
if _, err := buf.WriteString(","); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
if err := exprs.WriteArgs(buf); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(" FROM "); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if err := statement.dialect.Quoter().QuoteTo(buf.Builder, tableName); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(" WHERE "); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if err := statement.Conds().WriteTo(buf); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
buf.Append(args...)
|
||||
|
||||
if _, err := buf.WriteString(")"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if err := statement.writeInsertOutput(buf.Builder, table); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if _, err := buf.WriteString(" VALUES ("); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if _, err := buf.WriteString(colPlaces); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if err := exprs.WriteArgs(buf); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(")"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.POSTGRES {
|
||||
if _, err := buf.WriteString(" RETURNING "); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if err := statement.dialect.Quoter().QuoteTo(buf.Builder, table.AutoIncrement); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String(), buf.Args(), nil
|
||||
}
|
79
vendor/xorm.io/xorm/internal/statements/pk.go
generated
vendored
Normal file
79
vendor/xorm.io/xorm/internal/statements/pk.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// 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 statements
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
ptrPkType = reflect.TypeOf(&schemas.PK{})
|
||||
pkType = reflect.TypeOf(schemas.PK{})
|
||||
stringType = reflect.TypeOf("")
|
||||
intType = reflect.TypeOf(int64(0))
|
||||
uintType = reflect.TypeOf(uint64(0))
|
||||
)
|
||||
|
||||
// ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
|
||||
func (statement *Statement) ID(id interface{}) *Statement {
|
||||
switch t := id.(type) {
|
||||
case *schemas.PK:
|
||||
statement.idParam = *t
|
||||
case schemas.PK:
|
||||
statement.idParam = t
|
||||
case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
statement.idParam = schemas.PK{id}
|
||||
default:
|
||||
idValue := reflect.ValueOf(id)
|
||||
idType := idValue.Type()
|
||||
|
||||
switch idType.Kind() {
|
||||
case reflect.String:
|
||||
statement.idParam = schemas.PK{idValue.Convert(stringType).Interface()}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
statement.idParam = schemas.PK{idValue.Convert(intType).Interface()}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
statement.idParam = schemas.PK{idValue.Convert(uintType).Interface()}
|
||||
case reflect.Slice:
|
||||
if idType.ConvertibleTo(pkType) {
|
||||
statement.idParam = idValue.Convert(pkType).Interface().(schemas.PK)
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if idType.ConvertibleTo(ptrPkType) {
|
||||
statement.idParam = idValue.Convert(ptrPkType).Elem().Interface().(schemas.PK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if statement.idParam == nil {
|
||||
statement.LastError = fmt.Errorf("ID param %#v is not supported", id)
|
||||
}
|
||||
|
||||
return statement
|
||||
}
|
||||
|
||||
func (statement *Statement) ProcessIDParam() error {
|
||||
if statement.idParam == nil || statement.RefTable == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(statement.RefTable.PrimaryKeys) != len(statement.idParam) {
|
||||
fmt.Println("=====", statement.RefTable.PrimaryKeys, statement.idParam)
|
||||
return fmt.Errorf("ID condition is error, expect %d primarykeys, there are %d",
|
||||
len(statement.RefTable.PrimaryKeys),
|
||||
len(statement.idParam),
|
||||
)
|
||||
}
|
||||
|
||||
for i, col := range statement.RefTable.PKColumns() {
|
||||
var colName = statement.colName(col, statement.TableName())
|
||||
statement.cond = statement.cond.And(builder.Eq{colName: statement.idParam[i]})
|
||||
}
|
||||
return nil
|
||||
}
|
441
vendor/xorm.io/xorm/internal/statements/query.go
generated
vendored
Normal file
441
vendor/xorm.io/xorm/internal/statements/query.go
generated
vendored
Normal file
@ -0,0 +1,441 @@
|
||||
// Copyright 2019 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 statements
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) GenQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
||||
if len(sqlOrArgs) > 0 {
|
||||
return statement.ConvertSQLOrArgs(sqlOrArgs...)
|
||||
}
|
||||
|
||||
if statement.RawSQL != "" {
|
||||
return statement.GenRawSQL(), statement.RawParams, nil
|
||||
}
|
||||
|
||||
if len(statement.TableName()) <= 0 {
|
||||
return "", nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
var columnStr = statement.ColumnStr()
|
||||
if len(statement.SelectStr) > 0 {
|
||||
columnStr = statement.SelectStr
|
||||
} else {
|
||||
if statement.JoinStr == "" {
|
||||
if columnStr == "" {
|
||||
if statement.GroupByStr != "" {
|
||||
columnStr = statement.quoteColumnStr(statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = statement.genColumnStr()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if columnStr == "" {
|
||||
if statement.GroupByStr != "" {
|
||||
columnStr = statement.quoteColumnStr(statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
if columnStr == "" {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
|
||||
if err := statement.ProcessIDParam(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
sqlStr, condArgs, err := statement.genSelectSQL(columnStr, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
args := append(statement.joinArgs, condArgs...)
|
||||
|
||||
// for mssql and use limit
|
||||
qs := strings.Count(sqlStr, "?")
|
||||
if len(args)*2 == qs {
|
||||
args = append(args, args...)
|
||||
}
|
||||
|
||||
return sqlStr, args, nil
|
||||
}
|
||||
|
||||
func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) {
|
||||
if statement.RawSQL != "" {
|
||||
return statement.GenRawSQL(), statement.RawParams, nil
|
||||
}
|
||||
|
||||
statement.SetRefBean(bean)
|
||||
|
||||
var sumStrs = make([]string, 0, len(columns))
|
||||
for _, colName := range columns {
|
||||
if !strings.Contains(colName, " ") && !strings.Contains(colName, "(") {
|
||||
colName = statement.quote(colName)
|
||||
} else {
|
||||
colName = statement.ReplaceQuote(colName)
|
||||
}
|
||||
sumStrs = append(sumStrs, fmt.Sprintf("COALESCE(sum(%s),0)", colName))
|
||||
}
|
||||
sumSelect := strings.Join(sumStrs, ", ")
|
||||
|
||||
if err := statement.mergeConds(bean); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
sqlStr, condArgs, err := statement.genSelectSQL(sumSelect, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return sqlStr, append(statement.joinArgs, condArgs...), nil
|
||||
}
|
||||
|
||||
func (statement *Statement) GenGetSQL(bean interface{}) (string, []interface{}, error) {
|
||||
v := rValue(bean)
|
||||
isStruct := v.Kind() == reflect.Struct
|
||||
if isStruct {
|
||||
statement.SetRefBean(bean)
|
||||
}
|
||||
|
||||
var columnStr = statement.ColumnStr()
|
||||
if len(statement.SelectStr) > 0 {
|
||||
columnStr = statement.SelectStr
|
||||
} else {
|
||||
// TODO: always generate column names, not use * even if join
|
||||
if len(statement.JoinStr) == 0 {
|
||||
if len(columnStr) == 0 {
|
||||
if len(statement.GroupByStr) > 0 {
|
||||
columnStr = statement.quoteColumnStr(statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = statement.genColumnStr()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(columnStr) == 0 {
|
||||
if len(statement.GroupByStr) > 0 {
|
||||
columnStr = statement.quoteColumnStr(statement.GroupByStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(columnStr) == 0 {
|
||||
columnStr = "*"
|
||||
}
|
||||
|
||||
if isStruct {
|
||||
if err := statement.mergeConds(bean); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
if err := statement.ProcessIDParam(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
sqlStr, condArgs, err := statement.genSelectSQL(columnStr, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return sqlStr, append(statement.joinArgs, condArgs...), nil
|
||||
}
|
||||
|
||||
// GenCountSQL generates the SQL for counting
|
||||
func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interface{}, error) {
|
||||
if statement.RawSQL != "" {
|
||||
return statement.GenRawSQL(), statement.RawParams, nil
|
||||
}
|
||||
|
||||
var condArgs []interface{}
|
||||
var err error
|
||||
if len(beans) > 0 {
|
||||
statement.SetRefBean(beans[0])
|
||||
if err := statement.mergeConds(beans[0]); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var selectSQL = statement.SelectStr
|
||||
if len(selectSQL) <= 0 {
|
||||
if statement.IsDistinct {
|
||||
selectSQL = fmt.Sprintf("count(DISTINCT %s)", statement.ColumnStr())
|
||||
} else if statement.ColumnStr() != "" {
|
||||
selectSQL = fmt.Sprintf("count(%s)", statement.ColumnStr())
|
||||
} else {
|
||||
selectSQL = "count(*)"
|
||||
}
|
||||
}
|
||||
sqlStr, condArgs, err := statement.genSelectSQL(selectSQL, false, false)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return sqlStr, append(statement.joinArgs, condArgs...), nil
|
||||
}
|
||||
|
||||
func (statement *Statement) genSelectSQL(columnStr string, needLimit, needOrderBy bool) (string, []interface{}, error) {
|
||||
var (
|
||||
distinct string
|
||||
dialect = statement.dialect
|
||||
quote = statement.quote
|
||||
fromStr = " FROM "
|
||||
top, mssqlCondi, whereStr string
|
||||
)
|
||||
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
|
||||
distinct = "DISTINCT "
|
||||
}
|
||||
|
||||
condSQL, condArgs, err := statement.GenCondSQL(statement.cond)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if len(condSQL) > 0 {
|
||||
whereStr = " WHERE " + condSQL
|
||||
}
|
||||
|
||||
if dialect.URI().DBType == schemas.MSSQL && strings.Contains(statement.TableName(), "..") {
|
||||
fromStr += statement.TableName()
|
||||
} else {
|
||||
fromStr += quote(statement.TableName())
|
||||
}
|
||||
|
||||
if statement.TableAlias != "" {
|
||||
if dialect.URI().DBType == schemas.ORACLE {
|
||||
fromStr += " " + quote(statement.TableAlias)
|
||||
} else {
|
||||
fromStr += " AS " + quote(statement.TableAlias)
|
||||
}
|
||||
}
|
||||
if statement.JoinStr != "" {
|
||||
fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
|
||||
}
|
||||
|
||||
pLimitN := statement.LimitN
|
||||
if dialect.URI().DBType == schemas.MSSQL {
|
||||
if pLimitN != nil {
|
||||
LimitNValue := *pLimitN
|
||||
top = fmt.Sprintf("TOP %d ", LimitNValue)
|
||||
}
|
||||
if statement.Start > 0 {
|
||||
var column string
|
||||
if len(statement.RefTable.PKColumns()) == 0 {
|
||||
for _, index := range statement.RefTable.Indexes {
|
||||
if len(index.Cols) == 1 {
|
||||
column = index.Cols[0]
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(column) == 0 {
|
||||
column = statement.RefTable.ColumnsSeq()[0]
|
||||
}
|
||||
} else {
|
||||
column = statement.RefTable.PKColumns()[0].Name
|
||||
}
|
||||
if statement.needTableName() {
|
||||
if len(statement.TableAlias) > 0 {
|
||||
column = statement.TableAlias + "." + column
|
||||
} else {
|
||||
column = statement.TableName() + "." + column
|
||||
}
|
||||
}
|
||||
|
||||
var orderStr string
|
||||
if needOrderBy && len(statement.OrderStr) > 0 {
|
||||
orderStr = " ORDER BY " + statement.OrderStr
|
||||
}
|
||||
|
||||
var groupStr string
|
||||
if len(statement.GroupByStr) > 0 {
|
||||
groupStr = " GROUP BY " + statement.GroupByStr
|
||||
}
|
||||
mssqlCondi = fmt.Sprintf("(%s NOT IN (SELECT TOP %d %s%s%s%s%s))",
|
||||
column, statement.Start, column, fromStr, whereStr, orderStr, groupStr)
|
||||
}
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
||||
if len(mssqlCondi) > 0 {
|
||||
if len(whereStr) > 0 {
|
||||
fmt.Fprint(&buf, " AND ", mssqlCondi)
|
||||
} else {
|
||||
fmt.Fprint(&buf, " WHERE ", mssqlCondi)
|
||||
}
|
||||
}
|
||||
|
||||
if statement.GroupByStr != "" {
|
||||
fmt.Fprint(&buf, " GROUP BY ", statement.GroupByStr)
|
||||
}
|
||||
if statement.HavingStr != "" {
|
||||
fmt.Fprint(&buf, " ", statement.HavingStr)
|
||||
}
|
||||
if needOrderBy && statement.OrderStr != "" {
|
||||
fmt.Fprint(&buf, " ORDER BY ", statement.OrderStr)
|
||||
}
|
||||
if needLimit {
|
||||
if dialect.URI().DBType != schemas.MSSQL && dialect.URI().DBType != schemas.ORACLE {
|
||||
if statement.Start > 0 {
|
||||
if pLimitN != nil {
|
||||
fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", *pLimitN, statement.Start)
|
||||
} else {
|
||||
fmt.Fprintf(&buf, "LIMIT 0 OFFSET %v", statement.Start)
|
||||
}
|
||||
} else if pLimitN != nil {
|
||||
fmt.Fprint(&buf, " LIMIT ", *pLimitN)
|
||||
}
|
||||
} else if dialect.URI().DBType == schemas.ORACLE {
|
||||
if statement.Start != 0 || pLimitN != nil {
|
||||
oldString := buf.String()
|
||||
buf.Reset()
|
||||
rawColStr := columnStr
|
||||
if rawColStr == "*" {
|
||||
rawColStr = "at.*"
|
||||
}
|
||||
fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d",
|
||||
columnStr, rawColStr, oldString, statement.Start+*pLimitN, statement.Start)
|
||||
}
|
||||
}
|
||||
}
|
||||
if statement.IsForUpdate {
|
||||
return dialect.ForUpdateSQL(buf.String()), condArgs, nil
|
||||
}
|
||||
|
||||
return buf.String(), condArgs, nil
|
||||
}
|
||||
|
||||
func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interface{}, error) {
|
||||
if statement.RawSQL != "" {
|
||||
return statement.GenRawSQL(), statement.RawParams, nil
|
||||
}
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var joinStr string
|
||||
var err error
|
||||
if len(bean) == 0 {
|
||||
tableName := statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return "", nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
tableName = statement.quote(tableName)
|
||||
if len(statement.JoinStr) > 0 {
|
||||
joinStr = statement.JoinStr
|
||||
}
|
||||
|
||||
if statement.Conds().IsValid() {
|
||||
condSQL, condArgs, err := statement.GenCondSQL(statement.Conds())
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if statement.dialect.URI().DBType == schemas.MSSQL {
|
||||
sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s %s WHERE %s", tableName, joinStr, condSQL)
|
||||
} else if statement.dialect.URI().DBType == schemas.ORACLE {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) %s AND ROWNUM=1", tableName, joinStr, condSQL)
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s %s WHERE %s LIMIT 1", tableName, joinStr, condSQL)
|
||||
}
|
||||
args = condArgs
|
||||
} else {
|
||||
if statement.dialect.URI().DBType == schemas.MSSQL {
|
||||
sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s %s", tableName, joinStr)
|
||||
} else if statement.dialect.URI().DBType == schemas.ORACLE {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s %s WHERE ROWNUM=1", tableName, joinStr)
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s %s LIMIT 1", tableName, joinStr)
|
||||
}
|
||||
args = []interface{}{}
|
||||
}
|
||||
} else {
|
||||
beanValue := reflect.ValueOf(bean[0])
|
||||
if beanValue.Kind() != reflect.Ptr {
|
||||
return "", nil, errors.New("needs a pointer")
|
||||
}
|
||||
|
||||
if beanValue.Elem().Kind() == reflect.Struct {
|
||||
if err := statement.SetRefBean(bean[0]); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(statement.TableName()) <= 0 {
|
||||
return "", nil, ErrTableNotFound
|
||||
}
|
||||
statement.Limit(1)
|
||||
sqlStr, args, err = statement.GenGetSQL(bean[0])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sqlStr, args, nil
|
||||
}
|
||||
|
||||
func (statement *Statement) GenFindSQL(autoCond builder.Cond) (string, []interface{}, error) {
|
||||
if statement.RawSQL != "" {
|
||||
return statement.GenRawSQL(), statement.RawParams, nil
|
||||
}
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var err error
|
||||
|
||||
if len(statement.TableName()) <= 0 {
|
||||
return "", nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
var columnStr = statement.ColumnStr()
|
||||
if len(statement.SelectStr) > 0 {
|
||||
columnStr = statement.SelectStr
|
||||
} else {
|
||||
if statement.JoinStr == "" {
|
||||
if columnStr == "" {
|
||||
if statement.GroupByStr != "" {
|
||||
columnStr = statement.quoteColumnStr(statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = statement.genColumnStr()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if columnStr == "" {
|
||||
if statement.GroupByStr != "" {
|
||||
columnStr = statement.quoteColumnStr(statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
if columnStr == "" {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
|
||||
statement.cond = statement.cond.And(autoCond)
|
||||
|
||||
sqlStr, condArgs, err := statement.genSelectSQL(columnStr, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
args = append(statement.joinArgs, condArgs...)
|
||||
// for mssql and use limit
|
||||
qs := strings.Count(sqlStr, "?")
|
||||
if len(args)*2 == qs {
|
||||
args = append(args, args...)
|
||||
}
|
||||
|
||||
return sqlStr, args, nil
|
||||
}
|
996
vendor/xorm.io/xorm/internal/statements/statement.go
generated
vendored
Normal file
996
vendor/xorm.io/xorm/internal/statements/statement.go
generated
vendored
Normal file
@ -0,0 +1,996 @@
|
||||
// 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 statements
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/schemas"
|
||||
"xorm.io/xorm/tags"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrConditionType condition type unsupported
|
||||
ErrConditionType = errors.New("Unsupported condition type")
|
||||
// ErrUnSupportedSQLType parameter of SQL is not supported
|
||||
ErrUnSupportedSQLType = errors.New("Unsupported sql type")
|
||||
// ErrUnSupportedType unsupported error
|
||||
ErrUnSupportedType = errors.New("Unsupported type error")
|
||||
// ErrTableNotFound table not found error
|
||||
ErrTableNotFound = errors.New("Table not found")
|
||||
)
|
||||
|
||||
// Statement save all the sql info for executing SQL
|
||||
type Statement struct {
|
||||
RefTable *schemas.Table
|
||||
dialect dialects.Dialect
|
||||
defaultTimeZone *time.Location
|
||||
tagParser *tags.Parser
|
||||
Start int
|
||||
LimitN *int
|
||||
idParam schemas.PK
|
||||
OrderStr string
|
||||
JoinStr string
|
||||
joinArgs []interface{}
|
||||
GroupByStr string
|
||||
HavingStr string
|
||||
SelectStr string
|
||||
useAllCols bool
|
||||
AltTableName string
|
||||
tableName string
|
||||
RawSQL string
|
||||
RawParams []interface{}
|
||||
UseCascade bool
|
||||
UseAutoJoin bool
|
||||
StoreEngine string
|
||||
Charset string
|
||||
UseCache bool
|
||||
UseAutoTime bool
|
||||
NoAutoCondition bool
|
||||
IsDistinct bool
|
||||
IsForUpdate bool
|
||||
TableAlias string
|
||||
allUseBool bool
|
||||
CheckVersion bool
|
||||
unscoped bool
|
||||
ColumnMap columnMap
|
||||
OmitColumnMap columnMap
|
||||
MustColumnMap map[string]bool
|
||||
NullableMap map[string]bool
|
||||
IncrColumns exprParams
|
||||
DecrColumns exprParams
|
||||
ExprColumns exprParams
|
||||
cond builder.Cond
|
||||
BufferSize int
|
||||
Context contexts.ContextCache
|
||||
LastError error
|
||||
}
|
||||
|
||||
// NewStatement creates a new statement
|
||||
func NewStatement(dialect dialects.Dialect, tagParser *tags.Parser, defaultTimeZone *time.Location) *Statement {
|
||||
statement := &Statement{
|
||||
dialect: dialect,
|
||||
tagParser: tagParser,
|
||||
defaultTimeZone: defaultTimeZone,
|
||||
}
|
||||
statement.Reset()
|
||||
return statement
|
||||
}
|
||||
|
||||
func (statement *Statement) SetTableName(tableName string) {
|
||||
statement.tableName = tableName
|
||||
}
|
||||
|
||||
func (statement *Statement) omitStr() string {
|
||||
return statement.dialect.Quoter().Join(statement.OmitColumnMap, " ,")
|
||||
}
|
||||
|
||||
// GenRawSQL generates correct raw sql
|
||||
func (statement *Statement) GenRawSQL() string {
|
||||
return statement.ReplaceQuote(statement.RawSQL)
|
||||
}
|
||||
|
||||
func (statement *Statement) GenCondSQL(condOrBuilder interface{}) (string, []interface{}, error) {
|
||||
condSQL, condArgs, err := builder.ToSQL(condOrBuilder)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return statement.ReplaceQuote(condSQL), condArgs, nil
|
||||
}
|
||||
|
||||
func (statement *Statement) ReplaceQuote(sql string) string {
|
||||
if sql == "" || statement.dialect.URI().DBType == schemas.MYSQL ||
|
||||
statement.dialect.URI().DBType == schemas.SQLITE {
|
||||
return sql
|
||||
}
|
||||
return statement.dialect.Quoter().Replace(sql)
|
||||
}
|
||||
|
||||
func (statement *Statement) SetContextCache(ctxCache contexts.ContextCache) {
|
||||
statement.Context = ctxCache
|
||||
}
|
||||
|
||||
// Init reset all the statement's fields
|
||||
func (statement *Statement) Reset() {
|
||||
statement.RefTable = nil
|
||||
statement.Start = 0
|
||||
statement.LimitN = nil
|
||||
statement.OrderStr = ""
|
||||
statement.UseCascade = true
|
||||
statement.JoinStr = ""
|
||||
statement.joinArgs = make([]interface{}, 0)
|
||||
statement.GroupByStr = ""
|
||||
statement.HavingStr = ""
|
||||
statement.ColumnMap = columnMap{}
|
||||
statement.OmitColumnMap = columnMap{}
|
||||
statement.AltTableName = ""
|
||||
statement.tableName = ""
|
||||
statement.idParam = nil
|
||||
statement.RawSQL = ""
|
||||
statement.RawParams = make([]interface{}, 0)
|
||||
statement.UseCache = true
|
||||
statement.UseAutoTime = true
|
||||
statement.NoAutoCondition = false
|
||||
statement.IsDistinct = false
|
||||
statement.IsForUpdate = false
|
||||
statement.TableAlias = ""
|
||||
statement.SelectStr = ""
|
||||
statement.allUseBool = false
|
||||
statement.useAllCols = false
|
||||
statement.MustColumnMap = make(map[string]bool)
|
||||
statement.NullableMap = make(map[string]bool)
|
||||
statement.CheckVersion = true
|
||||
statement.unscoped = false
|
||||
statement.IncrColumns = exprParams{}
|
||||
statement.DecrColumns = exprParams{}
|
||||
statement.ExprColumns = exprParams{}
|
||||
statement.cond = builder.NewCond()
|
||||
statement.BufferSize = 0
|
||||
statement.Context = nil
|
||||
statement.LastError = nil
|
||||
}
|
||||
|
||||
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function
|
||||
func (statement *Statement) SetNoAutoCondition(no ...bool) *Statement {
|
||||
statement.NoAutoCondition = true
|
||||
if len(no) > 0 {
|
||||
statement.NoAutoCondition = no[0]
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// Alias set the table alias
|
||||
func (statement *Statement) Alias(alias string) *Statement {
|
||||
statement.TableAlias = alias
|
||||
return statement
|
||||
}
|
||||
|
||||
// SQL adds raw sql statement
|
||||
func (statement *Statement) SQL(query interface{}, args ...interface{}) *Statement {
|
||||
switch query.(type) {
|
||||
case (*builder.Builder):
|
||||
var err error
|
||||
statement.RawSQL, statement.RawParams, err = query.(*builder.Builder).ToSQL()
|
||||
if err != nil {
|
||||
statement.LastError = err
|
||||
}
|
||||
case string:
|
||||
statement.RawSQL = query.(string)
|
||||
statement.RawParams = args
|
||||
default:
|
||||
statement.LastError = ErrUnSupportedSQLType
|
||||
}
|
||||
|
||||
return statement
|
||||
}
|
||||
|
||||
// Where add Where statement
|
||||
func (statement *Statement) Where(query interface{}, args ...interface{}) *Statement {
|
||||
return statement.And(query, args...)
|
||||
}
|
||||
|
||||
func (statement *Statement) quote(s string) string {
|
||||
return statement.dialect.Quoter().Quote(s)
|
||||
}
|
||||
|
||||
// And add Where & and statement
|
||||
func (statement *Statement) And(query interface{}, args ...interface{}) *Statement {
|
||||
switch query.(type) {
|
||||
case string:
|
||||
cond := builder.Expr(query.(string), args...)
|
||||
statement.cond = statement.cond.And(cond)
|
||||
case map[string]interface{}:
|
||||
queryMap := query.(map[string]interface{})
|
||||
newMap := make(map[string]interface{})
|
||||
for k, v := range queryMap {
|
||||
newMap[statement.quote(k)] = v
|
||||
}
|
||||
statement.cond = statement.cond.And(builder.Eq(newMap))
|
||||
case builder.Cond:
|
||||
cond := query.(builder.Cond)
|
||||
statement.cond = statement.cond.And(cond)
|
||||
for _, v := range args {
|
||||
if vv, ok := v.(builder.Cond); ok {
|
||||
statement.cond = statement.cond.And(vv)
|
||||
}
|
||||
}
|
||||
default:
|
||||
statement.LastError = ErrConditionType
|
||||
}
|
||||
|
||||
return statement
|
||||
}
|
||||
|
||||
// Or add Where & Or statement
|
||||
func (statement *Statement) Or(query interface{}, args ...interface{}) *Statement {
|
||||
switch query.(type) {
|
||||
case string:
|
||||
cond := builder.Expr(query.(string), args...)
|
||||
statement.cond = statement.cond.Or(cond)
|
||||
case map[string]interface{}:
|
||||
cond := builder.Eq(query.(map[string]interface{}))
|
||||
statement.cond = statement.cond.Or(cond)
|
||||
case builder.Cond:
|
||||
cond := query.(builder.Cond)
|
||||
statement.cond = statement.cond.Or(cond)
|
||||
for _, v := range args {
|
||||
if vv, ok := v.(builder.Cond); ok {
|
||||
statement.cond = statement.cond.Or(vv)
|
||||
}
|
||||
}
|
||||
default:
|
||||
// TODO: not support condition type
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// In generate "Where column IN (?) " statement
|
||||
func (statement *Statement) In(column string, args ...interface{}) *Statement {
|
||||
in := builder.In(statement.quote(column), args...)
|
||||
statement.cond = statement.cond.And(in)
|
||||
return statement
|
||||
}
|
||||
|
||||
// NotIn generate "Where column NOT IN (?) " statement
|
||||
func (statement *Statement) NotIn(column string, args ...interface{}) *Statement {
|
||||
notIn := builder.NotIn(statement.quote(column), args...)
|
||||
statement.cond = statement.cond.And(notIn)
|
||||
return statement
|
||||
}
|
||||
|
||||
func (statement *Statement) SetRefValue(v reflect.Value) error {
|
||||
var err error
|
||||
statement.RefTable, err = statement.tagParser.ParseWithCache(reflect.Indirect(v))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
statement.tableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), v, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func rValue(bean interface{}) reflect.Value {
|
||||
return reflect.Indirect(reflect.ValueOf(bean))
|
||||
}
|
||||
|
||||
func (statement *Statement) SetRefBean(bean interface{}) error {
|
||||
var err error
|
||||
statement.RefTable, err = statement.tagParser.ParseWithCache(rValue(bean))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
statement.tableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), bean, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (statement *Statement) needTableName() bool {
|
||||
return len(statement.JoinStr) > 0
|
||||
}
|
||||
|
||||
func (statement *Statement) colName(col *schemas.Column, tableName string) string {
|
||||
if statement.needTableName() {
|
||||
var nm = tableName
|
||||
if len(statement.TableAlias) > 0 {
|
||||
nm = statement.TableAlias
|
||||
}
|
||||
return statement.quote(nm) + "." + statement.quote(col.Name)
|
||||
}
|
||||
return statement.quote(col.Name)
|
||||
}
|
||||
|
||||
// TableName return current tableName
|
||||
func (statement *Statement) TableName() string {
|
||||
if statement.AltTableName != "" {
|
||||
return statement.AltTableName
|
||||
}
|
||||
|
||||
return statement.tableName
|
||||
}
|
||||
|
||||
// Incr Generate "Update ... Set column = column + arg" statement
|
||||
func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
|
||||
if len(arg) > 0 {
|
||||
statement.IncrColumns.addParam(column, arg[0])
|
||||
} else {
|
||||
statement.IncrColumns.addParam(column, 1)
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// Decr Generate "Update ... Set column = column - arg" statement
|
||||
func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
|
||||
if len(arg) > 0 {
|
||||
statement.DecrColumns.addParam(column, arg[0])
|
||||
} else {
|
||||
statement.DecrColumns.addParam(column, 1)
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// SetExpr Generate "Update ... Set column = {expression}" statement
|
||||
func (statement *Statement) SetExpr(column string, expression interface{}) *Statement {
|
||||
if e, ok := expression.(string); ok {
|
||||
statement.ExprColumns.addParam(column, statement.dialect.Quoter().Replace(e))
|
||||
} else {
|
||||
statement.ExprColumns.addParam(column, expression)
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// Distinct generates "DISTINCT col1, col2 " statement
|
||||
func (statement *Statement) Distinct(columns ...string) *Statement {
|
||||
statement.IsDistinct = true
|
||||
statement.Cols(columns...)
|
||||
return statement
|
||||
}
|
||||
|
||||
// ForUpdate generates "SELECT ... FOR UPDATE" statement
|
||||
func (statement *Statement) ForUpdate() *Statement {
|
||||
statement.IsForUpdate = true
|
||||
return statement
|
||||
}
|
||||
|
||||
// Select replace select
|
||||
func (statement *Statement) Select(str string) *Statement {
|
||||
statement.SelectStr = statement.ReplaceQuote(str)
|
||||
return statement
|
||||
}
|
||||
|
||||
func col2NewCols(columns ...string) []string {
|
||||
newColumns := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
col = strings.Replace(col, "`", "", -1)
|
||||
col = strings.Replace(col, `"`, "", -1)
|
||||
ccols := strings.Split(col, ",")
|
||||
for _, c := range ccols {
|
||||
newColumns = append(newColumns, strings.TrimSpace(c))
|
||||
}
|
||||
}
|
||||
return newColumns
|
||||
}
|
||||
|
||||
// Cols generate "col1, col2" statement
|
||||
func (statement *Statement) Cols(columns ...string) *Statement {
|
||||
cols := col2NewCols(columns...)
|
||||
for _, nc := range cols {
|
||||
statement.ColumnMap.Add(nc)
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
func (statement *Statement) ColumnStr() string {
|
||||
return statement.dialect.Quoter().Join(statement.ColumnMap, ", ")
|
||||
}
|
||||
|
||||
// AllCols update use only: update all columns
|
||||
func (statement *Statement) AllCols() *Statement {
|
||||
statement.useAllCols = true
|
||||
return statement
|
||||
}
|
||||
|
||||
// MustCols update use only: must update columns
|
||||
func (statement *Statement) MustCols(columns ...string) *Statement {
|
||||
newColumns := col2NewCols(columns...)
|
||||
for _, nc := range newColumns {
|
||||
statement.MustColumnMap[strings.ToLower(nc)] = true
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// UseBool indicates that use bool fields as update contents and query contiditions
|
||||
func (statement *Statement) UseBool(columns ...string) *Statement {
|
||||
if len(columns) > 0 {
|
||||
statement.MustCols(columns...)
|
||||
} else {
|
||||
statement.allUseBool = true
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// Omit do not use the columns
|
||||
func (statement *Statement) Omit(columns ...string) {
|
||||
newColumns := col2NewCols(columns...)
|
||||
for _, nc := range newColumns {
|
||||
statement.OmitColumnMap = append(statement.OmitColumnMap, nc)
|
||||
}
|
||||
}
|
||||
|
||||
// Nullable Update use only: update columns to null when value is nullable and zero-value
|
||||
func (statement *Statement) Nullable(columns ...string) {
|
||||
newColumns := col2NewCols(columns...)
|
||||
for _, nc := range newColumns {
|
||||
statement.NullableMap[strings.ToLower(nc)] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Top generate LIMIT limit statement
|
||||
func (statement *Statement) Top(limit int) *Statement {
|
||||
statement.Limit(limit)
|
||||
return statement
|
||||
}
|
||||
|
||||
// Limit generate LIMIT start, limit statement
|
||||
func (statement *Statement) Limit(limit int, start ...int) *Statement {
|
||||
statement.LimitN = &limit
|
||||
if len(start) > 0 {
|
||||
statement.Start = start[0]
|
||||
}
|
||||
return statement
|
||||
}
|
||||
|
||||
// OrderBy generate "Order By order" statement
|
||||
func (statement *Statement) OrderBy(order string) *Statement {
|
||||
if len(statement.OrderStr) > 0 {
|
||||
statement.OrderStr += ", "
|
||||
}
|
||||
statement.OrderStr += statement.ReplaceQuote(order)
|
||||
return statement
|
||||
}
|
||||
|
||||
// Desc generate `ORDER BY xx DESC`
|
||||
func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||
var buf strings.Builder
|
||||
if len(statement.OrderStr) > 0 {
|
||||
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||
}
|
||||
for i, col := range colNames {
|
||||
if i > 0 {
|
||||
fmt.Fprint(&buf, ", ")
|
||||
}
|
||||
statement.dialect.Quoter().QuoteTo(&buf, col)
|
||||
fmt.Fprint(&buf, " DESC")
|
||||
}
|
||||
statement.OrderStr = buf.String()
|
||||
return statement
|
||||
}
|
||||
|
||||
// Asc provide asc order by query condition, the input parameters are columns.
|
||||
func (statement *Statement) Asc(colNames ...string) *Statement {
|
||||
var buf strings.Builder
|
||||
if len(statement.OrderStr) > 0 {
|
||||
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||
}
|
||||
for i, col := range colNames {
|
||||
if i > 0 {
|
||||
fmt.Fprint(&buf, ", ")
|
||||
}
|
||||
statement.dialect.Quoter().QuoteTo(&buf, col)
|
||||
fmt.Fprint(&buf, " ASC")
|
||||
}
|
||||
statement.OrderStr = buf.String()
|
||||
return statement
|
||||
}
|
||||
|
||||
func (statement *Statement) Conds() builder.Cond {
|
||||
return statement.cond
|
||||
}
|
||||
|
||||
// Table tempororily set table name, the parameter could be a string or a pointer of struct
|
||||
func (statement *Statement) SetTable(tableNameOrBean interface{}) error {
|
||||
v := rValue(tableNameOrBean)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
var err error
|
||||
statement.RefTable, err = statement.tagParser.ParseWithCache(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
statement.AltTableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tableNameOrBean, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
||||
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
|
||||
var buf strings.Builder
|
||||
if len(statement.JoinStr) > 0 {
|
||||
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
||||
} else {
|
||||
fmt.Fprintf(&buf, "%v JOIN ", joinOP)
|
||||
}
|
||||
|
||||
switch tp := tablename.(type) {
|
||||
case builder.Builder:
|
||||
subSQL, subQueryArgs, err := tp.ToSQL()
|
||||
if err != nil {
|
||||
statement.LastError = err
|
||||
return statement
|
||||
}
|
||||
|
||||
fields := strings.Split(tp.TableName(), ".")
|
||||
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
|
||||
aliasName = schemas.CommonQuoter.Trim(aliasName)
|
||||
|
||||
fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), aliasName, statement.ReplaceQuote(condition))
|
||||
statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
|
||||
case *builder.Builder:
|
||||
subSQL, subQueryArgs, err := tp.ToSQL()
|
||||
if err != nil {
|
||||
statement.LastError = err
|
||||
return statement
|
||||
}
|
||||
|
||||
fields := strings.Split(tp.TableName(), ".")
|
||||
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
|
||||
aliasName = schemas.CommonQuoter.Trim(aliasName)
|
||||
|
||||
fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), aliasName, statement.ReplaceQuote(condition))
|
||||
statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
|
||||
default:
|
||||
tbName := dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tablename, true)
|
||||
if !utils.IsSubQuery(tbName) {
|
||||
var buf strings.Builder
|
||||
statement.dialect.Quoter().QuoteTo(&buf, tbName)
|
||||
tbName = buf.String()
|
||||
}
|
||||
fmt.Fprintf(&buf, "%s ON %v", tbName, statement.ReplaceQuote(condition))
|
||||
}
|
||||
|
||||
statement.JoinStr = buf.String()
|
||||
statement.joinArgs = append(statement.joinArgs, args...)
|
||||
return statement
|
||||
}
|
||||
|
||||
// tbName get some table's table name
|
||||
func (statement *Statement) tbNameNoSchema(table *schemas.Table) string {
|
||||
if len(statement.AltTableName) > 0 {
|
||||
return statement.AltTableName
|
||||
}
|
||||
|
||||
return table.Name
|
||||
}
|
||||
|
||||
// GroupBy generate "Group By keys" statement
|
||||
func (statement *Statement) GroupBy(keys string) *Statement {
|
||||
statement.GroupByStr = statement.ReplaceQuote(keys)
|
||||
return statement
|
||||
}
|
||||
|
||||
// Having generate "Having conditions" statement
|
||||
func (statement *Statement) Having(conditions string) *Statement {
|
||||
statement.HavingStr = fmt.Sprintf("HAVING %v", statement.ReplaceQuote(conditions))
|
||||
return statement
|
||||
}
|
||||
|
||||
// Unscoped always disable struct tag "deleted"
|
||||
func (statement *Statement) SetUnscoped() *Statement {
|
||||
statement.unscoped = true
|
||||
return statement
|
||||
}
|
||||
|
||||
func (statement *Statement) GetUnscoped() bool {
|
||||
return statement.unscoped
|
||||
}
|
||||
|
||||
func (statement *Statement) genColumnStr() string {
|
||||
if statement.RefTable == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
columns := statement.RefTable.Columns()
|
||||
|
||||
for _, col := range columns {
|
||||
if statement.OmitColumnMap.Contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(statement.ColumnMap) > 0 && !statement.ColumnMap.Contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.MapType == schemas.ONLYTODB {
|
||||
continue
|
||||
}
|
||||
|
||||
if buf.Len() != 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
|
||||
if statement.JoinStr != "" {
|
||||
if statement.TableAlias != "" {
|
||||
buf.WriteString(statement.TableAlias)
|
||||
} else {
|
||||
buf.WriteString(statement.TableName())
|
||||
}
|
||||
|
||||
buf.WriteString(".")
|
||||
}
|
||||
|
||||
statement.dialect.Quoter().QuoteTo(&buf, col.Name)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (statement *Statement) GenCreateTableSQL() []string {
|
||||
statement.RefTable.StoreEngine = statement.StoreEngine
|
||||
statement.RefTable.Charset = statement.Charset
|
||||
s, _ := statement.dialect.CreateTableSQL(statement.RefTable, statement.TableName())
|
||||
return s
|
||||
}
|
||||
|
||||
func (statement *Statement) GenIndexSQL() []string {
|
||||
var sqls []string
|
||||
tbName := statement.TableName()
|
||||
for _, index := range statement.RefTable.Indexes {
|
||||
if index.Type == schemas.IndexType {
|
||||
sql := statement.dialect.CreateIndexSQL(tbName, index)
|
||||
sqls = append(sqls, sql)
|
||||
}
|
||||
}
|
||||
return sqls
|
||||
}
|
||||
|
||||
func uniqueName(tableName, uqeName string) string {
|
||||
return fmt.Sprintf("UQE_%v_%v", tableName, uqeName)
|
||||
}
|
||||
|
||||
func (statement *Statement) GenUniqueSQL() []string {
|
||||
var sqls []string
|
||||
tbName := statement.TableName()
|
||||
for _, index := range statement.RefTable.Indexes {
|
||||
if index.Type == schemas.UniqueType {
|
||||
sql := statement.dialect.CreateIndexSQL(tbName, index)
|
||||
sqls = append(sqls, sql)
|
||||
}
|
||||
}
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (statement *Statement) GenDelIndexSQL() []string {
|
||||
var sqls []string
|
||||
tbName := statement.TableName()
|
||||
idx := strings.Index(tbName, ".")
|
||||
if idx > -1 {
|
||||
tbName = tbName[idx+1:]
|
||||
}
|
||||
for _, index := range statement.RefTable.Indexes {
|
||||
sqls = append(sqls, statement.dialect.DropIndexSQL(tbName, index))
|
||||
}
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
|
||||
includeVersion bool, includeUpdated bool, includeNil bool,
|
||||
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
|
||||
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
|
||||
var conds []builder.Cond
|
||||
for _, col := range table.Columns() {
|
||||
if !includeVersion && col.IsVersion {
|
||||
continue
|
||||
}
|
||||
if !includeUpdated && col.IsUpdated {
|
||||
continue
|
||||
}
|
||||
if !includeAutoIncr && col.IsAutoIncrement {
|
||||
continue
|
||||
}
|
||||
|
||||
if statement.dialect.URI().DBType == schemas.MSSQL && (col.SQLType.Name == schemas.Text ||
|
||||
col.SQLType.IsBlob() || col.SQLType.Name == schemas.TimeStampz) {
|
||||
continue
|
||||
}
|
||||
if col.SQLType.IsJson() {
|
||||
continue
|
||||
}
|
||||
|
||||
var colName string
|
||||
if addedTableName {
|
||||
var nm = tableName
|
||||
if len(aliasName) > 0 {
|
||||
nm = aliasName
|
||||
}
|
||||
colName = statement.quote(nm) + "." + statement.quote(col.Name)
|
||||
} else {
|
||||
colName = statement.quote(col.Name)
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "is not valid") {
|
||||
//engine.logger.Warn(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
|
||||
conds = append(conds, statement.CondDeleted(col))
|
||||
}
|
||||
|
||||
fieldValue := *fieldValuePtr
|
||||
if fieldValue.Interface() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldType := reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField := useAllCols
|
||||
|
||||
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
|
||||
if b {
|
||||
requiredField = true
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if fieldType.Kind() == reflect.Ptr {
|
||||
if fieldValue.IsNil() {
|
||||
if includeNil {
|
||||
conds = append(conds, builder.Eq{colName: nil})
|
||||
}
|
||||
continue
|
||||
} else if !fieldValue.IsValid() {
|
||||
continue
|
||||
} else {
|
||||
// dereference ptr type to instance type
|
||||
fieldValue = fieldValue.Elem()
|
||||
fieldType = reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField = true
|
||||
}
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Bool:
|
||||
if allUseBool || requiredField {
|
||||
val = fieldValue.Interface()
|
||||
} else {
|
||||
// if a bool in a struct, it will not be as a condition because it default is false,
|
||||
// please use Where() instead
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if !requiredField && fieldValue.String() == "" {
|
||||
continue
|
||||
}
|
||||
// for MyString, should convert to string or panic
|
||||
if fieldType.String() != reflect.String.String() {
|
||||
val = fieldValue.String()
|
||||
} else {
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
|
||||
if !requiredField && fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if !requiredField && fieldValue.Float() == 0.0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
|
||||
if !requiredField && fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
t := int64(fieldValue.Uint())
|
||||
val = reflect.ValueOf(&t).Interface()
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(schemas.TimeType) {
|
||||
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
|
||||
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
||||
continue
|
||||
}
|
||||
val = dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
|
||||
} else if _, ok := reflect.New(fieldType).Interface().(convert.Conversion); ok {
|
||||
continue
|
||||
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
val, _ = valNul.Value()
|
||||
if val == nil && !requiredField {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if col.SQLType.IsJson() {
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
table, err := statement.tagParser.ParseWithCache(fieldValue)
|
||||
if err != nil {
|
||||
val = fieldValue.Interface()
|
||||
} else {
|
||||
if len(table.PrimaryKeys) == 1 {
|
||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||
// fix non-int pk issues
|
||||
//if pkField.Int() != 0 {
|
||||
if pkField.IsValid() && !utils.IsZero(pkField.Interface()) {
|
||||
val = pkField.Interface()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
//TODO: how to handler?
|
||||
return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Array:
|
||||
continue
|
||||
case reflect.Slice, reflect.Map:
|
||||
if fieldValue == reflect.Zero(fieldType) {
|
||||
continue
|
||||
}
|
||||
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
|
||||
fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
if fieldValue.Len() > 0 {
|
||||
val = fieldValue.Bytes()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
|
||||
conds = append(conds, builder.Eq{colName: val})
|
||||
}
|
||||
|
||||
return builder.And(conds...), nil
|
||||
}
|
||||
|
||||
func (statement *Statement) BuildConds(table *schemas.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) {
|
||||
return statement.buildConds2(table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols,
|
||||
statement.unscoped, statement.MustColumnMap, statement.TableName(), statement.TableAlias, addedTableName)
|
||||
}
|
||||
|
||||
func (statement *Statement) mergeConds(bean interface{}) error {
|
||||
if !statement.NoAutoCondition && statement.RefTable != nil {
|
||||
var addedTableName = (len(statement.JoinStr) > 0)
|
||||
autoCond, err := statement.BuildConds(statement.RefTable, bean, true, true, false, true, addedTableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
statement.cond = statement.cond.And(autoCond)
|
||||
}
|
||||
|
||||
if err := statement.ProcessIDParam(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (statement *Statement) GenConds(bean interface{}) (string, []interface{}, error) {
|
||||
if err := statement.mergeConds(bean); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return statement.GenCondSQL(statement.cond)
|
||||
}
|
||||
|
||||
func (statement *Statement) quoteColumnStr(columnStr string) string {
|
||||
columns := strings.Split(columnStr, ",")
|
||||
return statement.dialect.Quoter().Join(columns, ",")
|
||||
}
|
||||
|
||||
func (statement *Statement) ConvertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
||||
sql, args, err := convertSQLOrArgs(sqlOrArgs...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return statement.ReplaceQuote(sql), args, nil
|
||||
}
|
||||
|
||||
func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
||||
switch sqlOrArgs[0].(type) {
|
||||
case string:
|
||||
return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
|
||||
case *builder.Builder:
|
||||
return sqlOrArgs[0].(*builder.Builder).ToSQL()
|
||||
case builder.Builder:
|
||||
bd := sqlOrArgs[0].(builder.Builder)
|
||||
return bd.ToSQL()
|
||||
}
|
||||
|
||||
return "", nil, ErrUnSupportedType
|
||||
}
|
||||
|
||||
func (statement *Statement) joinColumns(cols []*schemas.Column, includeTableName bool) string {
|
||||
var colnames = make([]string, len(cols))
|
||||
for i, col := range cols {
|
||||
if includeTableName {
|
||||
colnames[i] = statement.quote(statement.TableName()) +
|
||||
"." + statement.quote(col.Name)
|
||||
} else {
|
||||
colnames[i] = statement.quote(col.Name)
|
||||
}
|
||||
}
|
||||
return strings.Join(colnames, ", ")
|
||||
}
|
||||
|
||||
// CondDeleted returns the conditions whether a record is soft deleted.
|
||||
func (statement *Statement) CondDeleted(col *schemas.Column) builder.Cond {
|
||||
var colName = col.Name
|
||||
if statement.JoinStr != "" {
|
||||
var prefix string
|
||||
if statement.TableAlias != "" {
|
||||
prefix = statement.TableAlias
|
||||
} else {
|
||||
prefix = statement.TableName()
|
||||
}
|
||||
colName = statement.quote(prefix) + "." + statement.quote(col.Name)
|
||||
}
|
||||
var cond = builder.NewCond()
|
||||
if col.SQLType.IsNumeric() {
|
||||
cond = builder.Eq{colName: 0}
|
||||
} else {
|
||||
// FIXME: mssql: The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.
|
||||
if statement.dialect.URI().DBType != schemas.MSSQL {
|
||||
cond = builder.Eq{colName: utils.ZeroTime1}
|
||||
}
|
||||
}
|
||||
|
||||
if col.Nullable {
|
||||
cond = cond.Or(builder.IsNull{colName})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
146
vendor/xorm.io/xorm/internal/statements/statement_args.go
generated
vendored
Normal file
146
vendor/xorm.io/xorm/internal/statements/statement_args.go
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2019 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 statements
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func quoteNeeded(a interface{}) bool {
|
||||
switch a.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
return false
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return false
|
||||
case float32, float64:
|
||||
return false
|
||||
case bool:
|
||||
return false
|
||||
case string:
|
||||
return true
|
||||
case time.Time, *time.Time:
|
||||
return true
|
||||
case builder.Builder, *builder.Builder:
|
||||
return false
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(a)
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return false
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return false
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return false
|
||||
case reflect.Bool:
|
||||
return false
|
||||
case reflect.String:
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func convertStringSingleQuote(arg string) string {
|
||||
return "'" + strings.Replace(arg, "'", "''", -1) + "'"
|
||||
}
|
||||
|
||||
func convertString(arg string) string {
|
||||
var buf strings.Builder
|
||||
buf.WriteRune('\'')
|
||||
for _, c := range arg {
|
||||
if c == '\\' || c == '\'' {
|
||||
buf.WriteRune('\\')
|
||||
}
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
buf.WriteRune('\'')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func convertArg(arg interface{}, convertFunc func(string) string) string {
|
||||
if quoteNeeded(arg) {
|
||||
argv := fmt.Sprintf("%v", arg)
|
||||
return convertFunc(argv)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", arg)
|
||||
}
|
||||
|
||||
const insertSelectPlaceHolder = true
|
||||
|
||||
func (statement *Statement) WriteArg(w *builder.BytesWriter, arg interface{}) error {
|
||||
switch argv := arg.(type) {
|
||||
case bool:
|
||||
if statement.dialect.URI().DBType == schemas.MSSQL {
|
||||
if argv {
|
||||
if _, err := w.WriteString("1"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := w.WriteString("0"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if argv {
|
||||
if _, err := w.WriteString("true"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := w.WriteString("false"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case *builder.Builder:
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := argv.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(")"); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if insertSelectPlaceHolder {
|
||||
if err := w.WriteByte('?'); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(arg)
|
||||
} else {
|
||||
var convertFunc = convertStringSingleQuote
|
||||
if statement.dialect.URI().DBType == schemas.MYSQL {
|
||||
convertFunc = convertString
|
||||
}
|
||||
if _, err := w.WriteString(convertArg(arg, convertFunc)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (statement *Statement) WriteArgs(w *builder.BytesWriter, args []interface{}) error {
|
||||
for i, arg := range args {
|
||||
if err := statement.WriteArg(w, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i+1 != len(args) {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
295
vendor/xorm.io/xorm/internal/statements/update.go
generated
vendored
Normal file
295
vendor/xorm.io/xorm/internal/statements/update.go
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
// 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 statements
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) ifAddColUpdate(col *schemas.Column, includeVersion, includeUpdated, includeNil,
|
||||
includeAutoIncr, update bool) (bool, error) {
|
||||
columnMap := statement.ColumnMap
|
||||
omitColumnMap := statement.OmitColumnMap
|
||||
unscoped := statement.unscoped
|
||||
|
||||
if !includeVersion && col.IsVersion {
|
||||
return false, nil
|
||||
}
|
||||
if col.IsCreated && !columnMap.Contain(col.Name) {
|
||||
return false, nil
|
||||
}
|
||||
if !includeUpdated && col.IsUpdated {
|
||||
return false, nil
|
||||
}
|
||||
if !includeAutoIncr && col.IsAutoIncrement {
|
||||
return false, nil
|
||||
}
|
||||
if col.IsDeleted && !unscoped {
|
||||
return false, nil
|
||||
}
|
||||
if omitColumnMap.Contain(col.Name) {
|
||||
return false, nil
|
||||
}
|
||||
if len(columnMap) > 0 && !columnMap.Contain(col.Name) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if col.MapType == schemas.ONLYFROMDB {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if statement.IncrColumns.IsColExist(col.Name) {
|
||||
return false, nil
|
||||
} else if statement.DecrColumns.IsColExist(col.Name) {
|
||||
return false, nil
|
||||
} else if statement.ExprColumns.IsColExist(col.Name) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// BuildUpdates auto generating update columnes and values according a struct
|
||||
func (statement *Statement) BuildUpdates(tableValue reflect.Value,
|
||||
includeVersion, includeUpdated, includeNil,
|
||||
includeAutoIncr, update bool) ([]string, []interface{}, error) {
|
||||
table := statement.RefTable
|
||||
allUseBool := statement.allUseBool
|
||||
useAllCols := statement.useAllCols
|
||||
mustColumnMap := statement.MustColumnMap
|
||||
nullableMap := statement.NullableMap
|
||||
|
||||
var colNames = make([]string, 0)
|
||||
var args = make([]interface{}, 0)
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
ok, err := statement.ifAddColUpdate(col, includeVersion, includeUpdated, includeNil,
|
||||
includeAutoIncr, update)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOfV(&tableValue)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fieldValue := *fieldValuePtr
|
||||
fieldType := reflect.TypeOf(fieldValue.Interface())
|
||||
if fieldType == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
requiredField := useAllCols
|
||||
includeNil := useAllCols
|
||||
|
||||
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
|
||||
if b {
|
||||
requiredField = true
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||
if b, ok := getFlagForColumn(nullableMap, col); ok {
|
||||
if b && col.Nullable && utils.IsZero(fieldValue.Interface()) {
|
||||
var nilValue *int
|
||||
fieldValue = reflect.ValueOf(nilValue)
|
||||
fieldType = reflect.TypeOf(fieldValue.Interface())
|
||||
includeNil = true
|
||||
}
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
|
||||
if fieldValue.CanAddr() {
|
||||
if structConvert, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
||||
data, err := structConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
val = data
|
||||
goto APPEND
|
||||
}
|
||||
}
|
||||
|
||||
if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
||||
data, err := structConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
val = data
|
||||
goto APPEND
|
||||
}
|
||||
|
||||
if fieldType.Kind() == reflect.Ptr {
|
||||
if fieldValue.IsNil() {
|
||||
if includeNil {
|
||||
args = append(args, nil)
|
||||
colNames = append(colNames, fmt.Sprintf("%v=?", statement.quote(col.Name)))
|
||||
}
|
||||
continue
|
||||
} else if !fieldValue.IsValid() {
|
||||
continue
|
||||
} else {
|
||||
// dereference ptr type to instance type
|
||||
fieldValue = fieldValue.Elem()
|
||||
fieldType = reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField = true
|
||||
}
|
||||
}
|
||||
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Bool:
|
||||
if allUseBool || requiredField {
|
||||
val = fieldValue.Interface()
|
||||
} else {
|
||||
// if a bool in a struct, it will not be as a condition because it default is false,
|
||||
// please use Where() instead
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if !requiredField && fieldValue.String() == "" {
|
||||
continue
|
||||
}
|
||||
// for MyString, should convert to string or panic
|
||||
if fieldType.String() != reflect.String.String() {
|
||||
val = fieldValue.String()
|
||||
} else {
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
|
||||
if !requiredField && fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if !requiredField && fieldValue.Float() == 0.0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
|
||||
if !requiredField && fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
t := int64(fieldValue.Uint())
|
||||
val = reflect.ValueOf(&t).Interface()
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(schemas.TimeType) {
|
||||
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
|
||||
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
||||
continue
|
||||
}
|
||||
val = dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
|
||||
} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
val, _ = nulType.Value()
|
||||
if val == nil && !requiredField {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if !col.SQLType.IsJson() {
|
||||
table, err := statement.tagParser.ParseWithCache(fieldValue)
|
||||
if err != nil {
|
||||
val = fieldValue.Interface()
|
||||
} else {
|
||||
if len(table.PrimaryKeys) == 1 {
|
||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||
// fix non-int pk issues
|
||||
if pkField.IsValid() && (!requiredField && !utils.IsZero(pkField.Interface())) {
|
||||
val = pkField.Interface()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
return nil, nil, errors.New("Not supported multiple primary keys")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Blank struct could not be as update data
|
||||
if requiredField || !utils.IsStructZero(fieldValue) {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("mashal %v failed", fieldValue.Interface())
|
||||
}
|
||||
if col.SQLType.IsText() {
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Array, reflect.Slice, reflect.Map:
|
||||
if !requiredField {
|
||||
if fieldValue == reflect.Zero(fieldType) {
|
||||
continue
|
||||
}
|
||||
if fieldType.Kind() == reflect.Array {
|
||||
if utils.IsArrayZero(fieldValue) {
|
||||
continue
|
||||
}
|
||||
} else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
if fieldType.Kind() == reflect.Slice &&
|
||||
fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
if fieldValue.Len() > 0 {
|
||||
val = fieldValue.Bytes()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if fieldType.Kind() == reflect.Array &&
|
||||
fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
val = fieldValue.Slice(0, 0).Interface()
|
||||
} else {
|
||||
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
|
||||
APPEND:
|
||||
args = append(args, val)
|
||||
colNames = append(colNames, fmt.Sprintf("%v = ?", statement.quote(col.Name)))
|
||||
}
|
||||
|
||||
return colNames, args, nil
|
||||
}
|
154
vendor/xorm.io/xorm/internal/statements/values.go
generated
vendored
Normal file
154
vendor/xorm.io/xorm/internal/statements/values.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
// 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 statements
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
nullFloatType = reflect.TypeOf(sql.NullFloat64{})
|
||||
)
|
||||
|
||||
// Value2Interface convert a field value of a struct to interface for puting into database
|
||||
func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue reflect.Value) (interface{}, error) {
|
||||
if fieldValue.CanAddr() {
|
||||
if fieldConvert, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
||||
data, err := fieldConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if col.SQLType.IsBlob() {
|
||||
return data, nil
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
}
|
||||
|
||||
if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
||||
data, err := fieldConvert.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if col.SQLType.IsBlob() {
|
||||
return data, nil
|
||||
}
|
||||
if nil == data {
|
||||
return nil, 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() {
|
||||
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(schemas.TimeType) {
|
||||
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
|
||||
tf := dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
|
||||
return tf, nil
|
||||
} else if fieldType.ConvertibleTo(nullFloatType) {
|
||||
t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
|
||||
if !t.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return t.Float64, nil
|
||||
}
|
||||
|
||||
if !col.SQLType.IsJson() {
|
||||
// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
|
||||
if v, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
return v.Value()
|
||||
}
|
||||
|
||||
fieldTable, err := statement.tagParser.ParseWithCache(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 nil, fmt.Errorf("no primary key for col %v", col.Name)
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return string(bytes), nil
|
||||
} else if col.SQLType.IsBlob() {
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, 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.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return string(bytes), nil
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
if (k == reflect.Slice) &&
|
||||
(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
|
||||
bytes = fieldValue.Bytes()
|
||||
} else {
|
||||
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
return nil, 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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user