mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-06-23 09:30:50 +00:00
Upgrade xorm to v1.0.0 (#10646)
* Upgrade xorm to v1.0.0 * small nit * Fix tests * Update xorm * Update xorm * fix go.sum * fix test * Fix bug when dump * Fix bug * update xorm to latest * Fix migration test * update xorm to latest * Fix import order * Use xorm tag
This commit is contained in:
parent
dcaa5643d7
commit
c61b902538
154 changed files with 7195 additions and 5962 deletions
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 {
|
||||
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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue