summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-xorm/xorm/helpers.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-xorm/xorm/helpers.go')
-rw-r--r--vendor/github.com/go-xorm/xorm/helpers.go580
1 files changed, 580 insertions, 0 deletions
diff --git a/vendor/github.com/go-xorm/xorm/helpers.go b/vendor/github.com/go-xorm/xorm/helpers.go
new file mode 100644
index 0000000000..f59db48b1d
--- /dev/null
+++ b/vendor/github.com/go-xorm/xorm/helpers.go
@@ -0,0 +1,580 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/go-xorm/core"
+)
+
+// str2PK convert string value to primary key value according to tp
+func str2PK(s string, tp reflect.Type) (interface{}, error) {
+ var err error
+ var result interface{}
+ switch tp.Kind() {
+ case reflect.Int:
+ result, err = strconv.Atoi(s)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as int: " + err.Error())
+ }
+ case reflect.Int8:
+ x, err := strconv.Atoi(s)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as int16: " + err.Error())
+ }
+ result = int8(x)
+ case reflect.Int16:
+ x, err := strconv.Atoi(s)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as int16: " + err.Error())
+ }
+ result = int16(x)
+ case reflect.Int32:
+ x, err := strconv.Atoi(s)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as int32: " + err.Error())
+ }
+ result = int32(x)
+ case reflect.Int64:
+ result, err = strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as int64: " + err.Error())
+ }
+ case reflect.Uint:
+ x, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as uint: " + err.Error())
+ }
+ result = uint(x)
+ case reflect.Uint8:
+ x, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as uint8: " + err.Error())
+ }
+ result = uint8(x)
+ case reflect.Uint16:
+ x, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as uint16: " + err.Error())
+ }
+ result = uint16(x)
+ case reflect.Uint32:
+ x, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as uint32: " + err.Error())
+ }
+ result = uint32(x)
+ case reflect.Uint64:
+ result, err = strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, errors.New("convert " + s + " as uint64: " + err.Error())
+ }
+ case reflect.String:
+ result = s
+ default:
+ panic("unsupported convert type")
+ }
+ result = reflect.ValueOf(result).Convert(tp).Interface()
+ return result, nil
+}
+
+func splitTag(tag string) (tags []string) {
+ tag = strings.TrimSpace(tag)
+ var hasQuote = false
+ var lastIdx = 0
+ for i, t := range tag {
+ if t == '\'' {
+ hasQuote = !hasQuote
+ } else if t == ' ' {
+ if lastIdx < i && !hasQuote {
+ tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
+ lastIdx = i + 1
+ }
+ }
+ }
+ if lastIdx < len(tag) {
+ tags = append(tags, strings.TrimSpace(tag[lastIdx:len(tag)]))
+ }
+ return
+}
+
+type zeroable interface {
+ IsZero() bool
+}
+
+func isZero(k interface{}) bool {
+ switch k.(type) {
+ case int:
+ return k.(int) == 0
+ case int8:
+ return k.(int8) == 0
+ case int16:
+ return k.(int16) == 0
+ case int32:
+ return k.(int32) == 0
+ case int64:
+ return k.(int64) == 0
+ case uint:
+ return k.(uint) == 0
+ case uint8:
+ return k.(uint8) == 0
+ case uint16:
+ return k.(uint16) == 0
+ case uint32:
+ return k.(uint32) == 0
+ case uint64:
+ return k.(uint64) == 0
+ case float32:
+ return k.(float32) == 0
+ case float64:
+ return k.(float64) == 0
+ case bool:
+ return k.(bool) == false
+ case string:
+ return k.(string) == ""
+ case zeroable:
+ return k.(zeroable).IsZero()
+ }
+ return false
+}
+
+func isStructZero(v reflect.Value) bool {
+ if !v.IsValid() {
+ return true
+ }
+
+ for i := 0; i < v.NumField(); i++ {
+ field := v.Field(i)
+ switch field.Kind() {
+ case reflect.Ptr:
+ field = field.Elem()
+ fallthrough
+ case reflect.Struct:
+ if !isStructZero(field) {
+ return false
+ }
+ default:
+ if field.CanInterface() && !isZero(field.Interface()) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
+ var v interface{}
+ switch tp.Kind() {
+ case reflect.Int16:
+ v = int16(id)
+ case reflect.Int32:
+ v = int32(id)
+ case reflect.Int:
+ v = int(id)
+ case reflect.Int64:
+ v = id
+ case reflect.Uint16:
+ v = uint16(id)
+ case reflect.Uint32:
+ v = uint32(id)
+ case reflect.Uint64:
+ v = uint64(id)
+ case reflect.Uint:
+ v = uint(id)
+ }
+ return reflect.ValueOf(v).Convert(tp)
+}
+
+func int64ToInt(id int64, tp reflect.Type) interface{} {
+ return int64ToIntValue(id, tp).Interface()
+}
+
+func isPKZero(pk core.PK) bool {
+ for _, k := range pk {
+ if isZero(k) {
+ return true
+ }
+ }
+ return false
+}
+
+func indexNoCase(s, sep string) int {
+ return strings.Index(strings.ToLower(s), strings.ToLower(sep))
+}
+
+func splitNoCase(s, sep string) []string {
+ idx := indexNoCase(s, sep)
+ if idx < 0 {
+ return []string{s}
+ }
+ return strings.Split(s, s[idx:idx+len(sep)])
+}
+
+func splitNNoCase(s, sep string, n int) []string {
+ idx := indexNoCase(s, sep)
+ if idx < 0 {
+ return []string{s}
+ }
+ return strings.SplitN(s, s[idx:idx+len(sep)], n)
+}
+
+func makeArray(elem string, count int) []string {
+ res := make([]string, count)
+ for i := 0; i < count; i++ {
+ res[i] = elem
+ }
+ return res
+}
+
+func rValue(bean interface{}) reflect.Value {
+ return reflect.Indirect(reflect.ValueOf(bean))
+}
+
+func rType(bean interface{}) reflect.Type {
+ sliceValue := reflect.Indirect(reflect.ValueOf(bean))
+ //return reflect.TypeOf(sliceValue.Interface())
+ return sliceValue.Type()
+}
+
+func structName(v reflect.Type) string {
+ for v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+ return v.Name()
+}
+
+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
+}
+
+func sliceEq(left, right []string) bool {
+ if len(left) != len(right) {
+ return false
+ }
+ sort.Sort(sort.StringSlice(left))
+ sort.Sort(sort.StringSlice(right))
+ for i := 0; i < len(left); i++ {
+ if left[i] != right[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func reflect2value(rawValue *reflect.Value) (str string, err error) {
+ aa := reflect.TypeOf((*rawValue).Interface())
+ vv := reflect.ValueOf((*rawValue).Interface())
+ switch aa.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ str = strconv.FormatInt(vv.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ str = strconv.FormatUint(vv.Uint(), 10)
+ case reflect.Float32, reflect.Float64:
+ str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
+ case reflect.String:
+ str = vv.String()
+ case reflect.Array, reflect.Slice:
+ switch aa.Elem().Kind() {
+ case reflect.Uint8:
+ data := rawValue.Interface().([]byte)
+ str = string(data)
+ default:
+ err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+ }
+ // time type
+ case reflect.Struct:
+ if aa.ConvertibleTo(core.TimeType) {
+ str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
+ } else {
+ err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+ }
+ case reflect.Bool:
+ str = strconv.FormatBool(vv.Bool())
+ case reflect.Complex128, reflect.Complex64:
+ str = fmt.Sprintf("%v", vv.Complex())
+ /* TODO: unsupported types below
+ case reflect.Map:
+ case reflect.Ptr:
+ case reflect.Uintptr:
+ case reflect.UnsafePointer:
+ case reflect.Chan, reflect.Func, reflect.Interface:
+ */
+ default:
+ err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+ }
+ return
+}
+
+func value2Bytes(rawValue *reflect.Value) (data []byte, err error) {
+ var str string
+ str, err = reflect2value(rawValue)
+ if err != nil {
+ return
+ }
+ data = []byte(str)
+ return
+}
+
+func value2String(rawValue *reflect.Value) (data string, err error) {
+ data, err = reflect2value(rawValue)
+ if err != nil {
+ return
+ }
+ return
+}
+
+func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
+ fields, err := rows.Columns()
+ if err != nil {
+ return nil, err
+ }
+ for rows.Next() {
+ result, err := row2mapStr(rows, fields)
+ if err != nil {
+ return nil, err
+ }
+ resultsSlice = append(resultsSlice, result)
+ }
+
+ return resultsSlice, nil
+}
+
+func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
+ fields, err := rows.Columns()
+ if err != nil {
+ return nil, err
+ }
+ for rows.Next() {
+ result, err := row2map(rows, fields)
+ if err != nil {
+ return nil, err
+ }
+ resultsSlice = append(resultsSlice, result)
+ }
+
+ return resultsSlice, nil
+}
+
+func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
+ result := make(map[string][]byte)
+ scanResultContainers := make([]interface{}, len(fields))
+ for i := 0; i < len(fields); i++ {
+ var scanResultContainer interface{}
+ scanResultContainers[i] = &scanResultContainer
+ }
+ if err := rows.Scan(scanResultContainers...); err != nil {
+ return nil, err
+ }
+
+ for ii, key := range fields {
+ rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+ //if row is null then ignore
+ if rawValue.Interface() == nil {
+ //fmt.Println("ignore ...", key, rawValue)
+ continue
+ }
+
+ if data, err := value2Bytes(&rawValue); err == nil {
+ result[key] = data
+ } else {
+ return nil, err // !nashtsai! REVIEW, should return err or just error log?
+ }
+ }
+ return result, nil
+}
+
+func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
+ result := make(map[string]string)
+ scanResultContainers := make([]interface{}, len(fields))
+ for i := 0; i < len(fields); i++ {
+ var scanResultContainer interface{}
+ scanResultContainers[i] = &scanResultContainer
+ }
+ if err := rows.Scan(scanResultContainers...); err != nil {
+ return nil, err
+ }
+
+ for ii, key := range fields {
+ rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+ //if row is null then ignore
+ if rawValue.Interface() == nil {
+ //fmt.Println("ignore ...", key, rawValue)
+ continue
+ }
+
+ if data, err := value2String(&rawValue); err == nil {
+ result[key] = data
+ } else {
+ return nil, err // !nashtsai! REVIEW, should return err or just error log?
+ }
+ }
+ return result, nil
+}
+
+func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) {
+ rows, err := tx.Query(sqlStr, params...)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ return rows2Strings(rows)
+}
+
+func query2(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) {
+ s, err := db.Prepare(sqlStr)
+ if err != nil {
+ return nil, err
+ }
+ defer s.Close()
+ rows, err := s.Query(params...)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ return rows2Strings(rows)
+}
+
+func setColumnInt(bean interface{}, col *core.Column, t int64) {
+ v, err := col.ValueOf(bean)
+ if err != nil {
+ return
+ }
+ if v.CanSet() {
+ switch v.Type().Kind() {
+ case reflect.Int, reflect.Int64, reflect.Int32:
+ v.SetInt(t)
+ case reflect.Uint, reflect.Uint64, reflect.Uint32:
+ v.SetUint(uint64(t))
+ }
+ }
+}
+
+func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
+ v, err := col.ValueOf(bean)
+ if err != nil {
+ return
+ }
+ if v.CanSet() {
+ switch v.Type().Kind() {
+ case reflect.Struct:
+ v.Set(reflect.ValueOf(t).Convert(v.Type()))
+ case reflect.Int, reflect.Int64, reflect.Int32:
+ v.SetInt(t.Unix())
+ case reflect.Uint, reflect.Uint64, reflect.Uint32:
+ v.SetUint(uint64(t.Unix()))
+ }
+ }
+}
+
+func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
+ colNames := make([]string, 0, len(table.ColumnsSeq()))
+ args := make([]interface{}, 0, len(table.ColumnsSeq()))
+
+ for _, col := range table.Columns() {
+ lColName := strings.ToLower(col.Name)
+ if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
+ if _, ok := session.Statement.columnMap[lColName]; !ok {
+ continue
+ }
+ }
+ if col.MapType == core.ONLYFROMDB {
+ continue
+ }
+
+ fieldValuePtr, err := col.ValueOf(bean)
+ if err != nil {
+ return nil, nil, err
+ }
+ fieldValue := *fieldValuePtr
+
+ if col.IsAutoIncrement {
+ switch fieldValue.Type().Kind() {
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
+ if fieldValue.Int() == 0 {
+ continue
+ }
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
+ if fieldValue.Uint() == 0 {
+ continue
+ }
+ case reflect.String:
+ if len(fieldValue.String()) == 0 {
+ continue
+ }
+ }
+ }
+
+ if col.IsDeleted {
+ continue
+ }
+
+ if session.Statement.ColumnStr != "" {
+ if _, ok := session.Statement.columnMap[lColName]; !ok {
+ continue
+ }
+ }
+ if session.Statement.OmitStr != "" {
+ if _, ok := session.Statement.columnMap[lColName]; ok {
+ continue
+ }
+ }
+
+ // !evalphobia! set fieldValue as nil when column is nullable and zero-value
+ if _, ok := session.Statement.nullableMap[lColName]; ok {
+ if col.Nullable && isZero(fieldValue.Interface()) {
+ var nilValue *int
+ fieldValue = reflect.ValueOf(nilValue)
+ }
+ }
+
+ if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
+ // if time is non-empty, then set to auto time
+ val, t := session.Engine.NowTime2(col.SQLType.Name)
+ args = append(args, val)
+
+ var colName = col.Name
+ session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+ col := table.GetColumn(colName)
+ setColumnTime(bean, col, t)
+ })
+ } else if col.IsVersion && session.Statement.checkVersion {
+ args = append(args, 1)
+ } else {
+ arg, err := session.value2Interface(col, fieldValue)
+ if err != nil {
+ return colNames, args, err
+ }
+ args = append(args, arg)
+ }
+
+ if includeQuote {
+ colNames = append(colNames, session.Engine.Quote(col.Name)+" = ?")
+ } else {
+ colNames = append(colNames, col.Name)
+ }
+ }
+ return colNames, args, nil
+}
+
+func indexName(tableName, idxName string) string {
+ return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
+}