d28f005552
Fix limit for databases other than sqlite go mod tidy && go mod vendor Remove unneeded break statements Make everything work with the new xorm version Fix xorm logging Fix lint Fix redis init Fix using id field Fix database init for testing Change default database log level Add xorm logger Use const for postgres go mod tidy Merge branch 'master' into update/xorm # Conflicts: # go.mod # go.sum # vendor/modules.txt go mod vendor Fix loading fixtures for postgres Go mod vendor1 Update xorm to version 1 Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/323
473 lines
11 KiB
Go
473 lines
11 KiB
Go
// Copyright 2017 The Xorm Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package xorm
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
|
|
|
func strconvErr(err error) error {
|
|
if ne, ok := err.(*strconv.NumError); ok {
|
|
return ne.Err
|
|
}
|
|
return err
|
|
}
|
|
|
|
func cloneBytes(b []byte) []byte {
|
|
if b == nil {
|
|
return nil
|
|
} else {
|
|
c := make([]byte, len(b))
|
|
copy(c, b)
|
|
return c
|
|
}
|
|
}
|
|
|
|
func asString(src interface{}) string {
|
|
switch v := src.(type) {
|
|
case string:
|
|
return v
|
|
case []byte:
|
|
return string(v)
|
|
}
|
|
rv := reflect.ValueOf(src)
|
|
switch rv.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return strconv.FormatInt(rv.Int(), 10)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return strconv.FormatUint(rv.Uint(), 10)
|
|
case reflect.Float64:
|
|
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
|
|
case reflect.Float32:
|
|
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
|
|
case reflect.Bool:
|
|
return strconv.FormatBool(rv.Bool())
|
|
}
|
|
return fmt.Sprintf("%v", src)
|
|
}
|
|
|
|
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
|
switch rv.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return strconv.AppendInt(buf, rv.Int(), 10), true
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return strconv.AppendUint(buf, rv.Uint(), 10), true
|
|
case reflect.Float32:
|
|
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
|
|
case reflect.Float64:
|
|
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
|
|
case reflect.Bool:
|
|
return strconv.AppendBool(buf, rv.Bool()), true
|
|
case reflect.String:
|
|
s := rv.String()
|
|
return append(buf, s...), true
|
|
}
|
|
return
|
|
}
|
|
|
|
// convertAssign copies to dest the value in src, converting it if possible.
|
|
// An error is returned if the copy would result in loss of information.
|
|
// dest should be a pointer type.
|
|
func convertAssign(dest, src interface{}) error {
|
|
// Common cases, without reflect.
|
|
switch s := src.(type) {
|
|
case string:
|
|
switch d := dest.(type) {
|
|
case *string:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = s
|
|
return nil
|
|
case *[]byte:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = []byte(s)
|
|
return nil
|
|
}
|
|
case []byte:
|
|
switch d := dest.(type) {
|
|
case *string:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = string(s)
|
|
return nil
|
|
case *interface{}:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = cloneBytes(s)
|
|
return nil
|
|
case *[]byte:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = cloneBytes(s)
|
|
return nil
|
|
}
|
|
|
|
case time.Time:
|
|
switch d := dest.(type) {
|
|
case *string:
|
|
*d = s.Format(time.RFC3339Nano)
|
|
return nil
|
|
case *[]byte:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = []byte(s.Format(time.RFC3339Nano))
|
|
return nil
|
|
}
|
|
case nil:
|
|
switch d := dest.(type) {
|
|
case *interface{}:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = nil
|
|
return nil
|
|
case *[]byte:
|
|
if d == nil {
|
|
return errNilPtr
|
|
}
|
|
*d = nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var sv reflect.Value
|
|
|
|
switch d := dest.(type) {
|
|
case *string:
|
|
sv = reflect.ValueOf(src)
|
|
switch sv.Kind() {
|
|
case reflect.Bool,
|
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
|
reflect.Float32, reflect.Float64:
|
|
*d = asString(src)
|
|
return nil
|
|
}
|
|
case *[]byte:
|
|
sv = reflect.ValueOf(src)
|
|
if b, ok := asBytes(nil, sv); ok {
|
|
*d = b
|
|
return nil
|
|
}
|
|
case *bool:
|
|
bv, err := driver.Bool.ConvertValue(src)
|
|
if err == nil {
|
|
*d = bv.(bool)
|
|
}
|
|
return err
|
|
case *interface{}:
|
|
*d = src
|
|
return nil
|
|
}
|
|
|
|
dpv := reflect.ValueOf(dest)
|
|
if dpv.Kind() != reflect.Ptr {
|
|
return errors.New("destination not a pointer")
|
|
}
|
|
if dpv.IsNil() {
|
|
return errNilPtr
|
|
}
|
|
|
|
if !sv.IsValid() {
|
|
sv = reflect.ValueOf(src)
|
|
}
|
|
|
|
dv := reflect.Indirect(dpv)
|
|
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
|
|
switch b := src.(type) {
|
|
case []byte:
|
|
dv.Set(reflect.ValueOf(cloneBytes(b)))
|
|
default:
|
|
dv.Set(sv)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
|
|
dv.Set(sv.Convert(dv.Type()))
|
|
return nil
|
|
}
|
|
|
|
switch dv.Kind() {
|
|
case reflect.Ptr:
|
|
if src == nil {
|
|
dv.Set(reflect.Zero(dv.Type()))
|
|
return nil
|
|
}
|
|
|
|
dv.Set(reflect.New(dv.Type().Elem()))
|
|
return convertAssign(dv.Interface(), src)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
s := asString(src)
|
|
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
|
if err != nil {
|
|
err = strconvErr(err)
|
|
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
|
}
|
|
dv.SetInt(i64)
|
|
return nil
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
s := asString(src)
|
|
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
|
|
if err != nil {
|
|
err = strconvErr(err)
|
|
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
|
}
|
|
dv.SetUint(u64)
|
|
return nil
|
|
case reflect.Float32, reflect.Float64:
|
|
s := asString(src)
|
|
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
|
|
if err != nil {
|
|
err = strconvErr(err)
|
|
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
|
}
|
|
dv.SetFloat(f64)
|
|
return nil
|
|
case reflect.String:
|
|
dv.SetString(asString(src))
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
|
|
}
|
|
|
|
func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
|
|
switch tp.Kind() {
|
|
case reflect.Int64:
|
|
return vv.Int(), nil
|
|
case reflect.Int:
|
|
return int(vv.Int()), nil
|
|
case reflect.Int32:
|
|
return int32(vv.Int()), nil
|
|
case reflect.Int16:
|
|
return int16(vv.Int()), nil
|
|
case reflect.Int8:
|
|
return int8(vv.Int()), nil
|
|
case reflect.Uint64:
|
|
return vv.Uint(), nil
|
|
case reflect.Uint:
|
|
return uint(vv.Uint()), nil
|
|
case reflect.Uint32:
|
|
return uint32(vv.Uint()), nil
|
|
case reflect.Uint16:
|
|
return uint16(vv.Uint()), nil
|
|
case reflect.Uint8:
|
|
return uint8(vv.Uint()), nil
|
|
case reflect.String:
|
|
return vv.String(), nil
|
|
case reflect.Slice:
|
|
if tp.Elem().Kind() == reflect.Uint8 {
|
|
v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
}
|
|
return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
|
|
}
|
|
|
|
func convertFloat(v interface{}) (float64, error) {
|
|
switch v.(type) {
|
|
case float32:
|
|
return float64(v.(float32)), nil
|
|
case float64:
|
|
return v.(float64), nil
|
|
case string:
|
|
i, err := strconv.ParseFloat(v.(string), 64)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return i, nil
|
|
case []byte:
|
|
i, err := strconv.ParseFloat(string(v.([]byte)), 64)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return i, nil
|
|
}
|
|
return 0, fmt.Errorf("unsupported type: %v", v)
|
|
}
|
|
|
|
func convertInt(v interface{}) (int64, error) {
|
|
switch v.(type) {
|
|
case int:
|
|
return int64(v.(int)), nil
|
|
case int8:
|
|
return int64(v.(int8)), nil
|
|
case int16:
|
|
return int64(v.(int16)), nil
|
|
case int32:
|
|
return int64(v.(int32)), nil
|
|
case int64:
|
|
return v.(int64), nil
|
|
case []byte:
|
|
i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return i, nil
|
|
case string:
|
|
i, err := strconv.ParseInt(v.(string), 10, 64)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return i, nil
|
|
}
|
|
return 0, fmt.Errorf("unsupported type: %v", v)
|
|
}
|
|
|
|
func asBool(bs []byte) (bool, error) {
|
|
if len(bs) == 0 {
|
|
return false, nil
|
|
}
|
|
if bs[0] == 0x00 {
|
|
return false, nil
|
|
} else if bs[0] == 0x01 {
|
|
return true, nil
|
|
}
|
|
return strconv.ParseBool(string(bs))
|
|
}
|
|
|
|
// str2PK convert string value to primary key value according to tp
|
|
func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
|
|
var err error
|
|
var result interface{}
|
|
var defReturn = reflect.Zero(tp)
|
|
|
|
switch tp.Kind() {
|
|
case reflect.Int:
|
|
result, err = strconv.Atoi(s)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
|
|
}
|
|
case reflect.Int8:
|
|
x, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
|
|
}
|
|
result = int8(x)
|
|
case reflect.Int16:
|
|
x, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
|
|
}
|
|
result = int16(x)
|
|
case reflect.Int32:
|
|
x, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
|
|
}
|
|
result = int32(x)
|
|
case reflect.Int64:
|
|
result, err = strconv.ParseInt(s, 10, 64)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
|
|
}
|
|
case reflect.Uint:
|
|
x, err := strconv.ParseUint(s, 10, 64)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
|
|
}
|
|
result = uint(x)
|
|
case reflect.Uint8:
|
|
x, err := strconv.ParseUint(s, 10, 64)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
|
|
}
|
|
result = uint8(x)
|
|
case reflect.Uint16:
|
|
x, err := strconv.ParseUint(s, 10, 64)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
|
|
}
|
|
result = uint16(x)
|
|
case reflect.Uint32:
|
|
x, err := strconv.ParseUint(s, 10, 64)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
|
|
}
|
|
result = uint32(x)
|
|
case reflect.Uint64:
|
|
result, err = strconv.ParseUint(s, 10, 64)
|
|
if err != nil {
|
|
return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
|
|
}
|
|
case reflect.String:
|
|
result = s
|
|
default:
|
|
return defReturn, errors.New("unsupported convert type")
|
|
}
|
|
return reflect.ValueOf(result).Convert(tp), nil
|
|
}
|
|
|
|
func str2PK(s string, tp reflect.Type) (interface{}, error) {
|
|
v, err := str2PKValue(s, tp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return v.Interface(), nil
|
|
}
|
|
|
|
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
|
|
var v interface{}
|
|
kind := tp.Kind()
|
|
|
|
if kind == reflect.Ptr {
|
|
kind = tp.Elem().Kind()
|
|
}
|
|
|
|
switch kind {
|
|
case reflect.Int16:
|
|
temp := int16(id)
|
|
v = &temp
|
|
case reflect.Int32:
|
|
temp := int32(id)
|
|
v = &temp
|
|
case reflect.Int:
|
|
temp := int(id)
|
|
v = &temp
|
|
case reflect.Int64:
|
|
temp := id
|
|
v = &temp
|
|
case reflect.Uint16:
|
|
temp := uint16(id)
|
|
v = &temp
|
|
case reflect.Uint32:
|
|
temp := uint32(id)
|
|
v = &temp
|
|
case reflect.Uint64:
|
|
temp := uint64(id)
|
|
v = &temp
|
|
case reflect.Uint:
|
|
temp := uint(id)
|
|
v = &temp
|
|
}
|
|
|
|
if tp.Kind() == reflect.Ptr {
|
|
return reflect.ValueOf(v).Convert(tp)
|
|
}
|
|
return reflect.ValueOf(v).Elem().Convert(tp)
|
|
}
|
|
|
|
func int64ToInt(id int64, tp reflect.Type) interface{} {
|
|
return int64ToIntValue(id, tp).Interface()
|
|
}
|