Move zero functions to a standalone package #1548
|
@ -12,6 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
|
"xorm.io/xorm/internal/utils"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -169,7 +170,7 @@ func (engine *Engine) buildConds(table *schemas.Table, bean interface{},
|
||||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||||
// fix non-int pk issues
|
// fix non-int pk issues
|
||||||
//if pkField.Int() != 0 {
|
//if pkField.Int() != 0 {
|
||||||
if pkField.IsValid() && !isZero(pkField.Interface()) {
|
if pkField.IsValid() && !utils.IsZero(pkField.Interface()) {
|
||||||
val = pkField.Interface()
|
val = pkField.Interface()
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
|
|
100
helpers.go
100
helpers.go
|
@ -11,8 +11,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"xorm.io/xorm/schemas"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// str2PK convert string value to primary key value according to tp
|
// str2PK convert string value to primary key value according to tp
|
||||||
|
@ -95,95 +93,6 @@ func str2PK(s string, tp reflect.Type) (interface{}, error) {
|
||||||
return v.Interface(), nil
|
return v.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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 isZeroValue(v reflect.Value) bool {
|
|
||||||
if isZero(v.Interface()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
|
||||||
return v.IsNil()
|
|
||||||
}
|
|
||||||
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 isArrayValueZero(v reflect.Value) bool {
|
|
||||||
if !v.IsValid() || v.Len() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
if !isZero(v.Index(i).Interface()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
|
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
|
||||||
var v interface{}
|
var v interface{}
|
||||||
kind := tp.Kind()
|
kind := tp.Kind()
|
||||||
|
@ -229,15 +138,6 @@ func int64ToInt(id int64, tp reflect.Type) interface{} {
|
||||||
return int64ToIntValue(id, tp).Interface()
|
return int64ToIntValue(id, tp).Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPKZero(pk schemas.PK) bool {
|
|
||||||
for _, k := range pk {
|
|
||||||
if isZero(k) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func indexNoCase(s, sep string) int {
|
func indexNoCase(s, sep string) int {
|
||||||
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
|
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
|
||||||
}
|
}
|
||||||
|
|
98
internal/utils/zero.go
Normal file
98
internal/utils/zero.go
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
// 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 utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 IsValueZero(v reflect.Value) bool {
|
||||||
|
if IsZero(v.Interface()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||||
|
return v.IsNil()
|
||||||
|
}
|
||||||
|
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 IsArrayZero(v reflect.Value) bool {
|
||||||
|
if !v.IsValid() || v.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
if !IsZero(v.Index(i).Interface()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ package schemas
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
|
||||||
|
"xorm.io/xorm/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PK []interface{}
|
type PK []interface{}
|
||||||
|
@ -16,6 +18,15 @@ func NewPK(pks ...interface{}) *PK {
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PK) IsZero() bool {
|
||||||
|
for _, k := range *p {
|
||||||
|
if utils.IsZero(k) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PK) ToString() (string, error) {
|
func (p *PK) ToString() (string, error) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
enc := gob.NewEncoder(buf)
|
enc := gob.NewEncoder(buf)
|
||||||
|
|
|
@ -703,7 +703,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
if !pk.IsZero() {
|
||||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||||
// property to be fetched lazily
|
// property to be fetched lazily
|
||||||
|
|
|
@ -224,7 +224,7 @@ func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Val
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
if !pk.IsZero() {
|
||||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||||
// property to be fetched lazily
|
// property to be fetched lazily
|
||||||
|
@ -506,7 +506,7 @@ func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Val
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
if !pk.IsZero() {
|
||||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
||||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
||||||
// property to be fetched lazily
|
// property to be fetched lazily
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
|
"xorm.io/xorm/internal/utils"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -153,7 +154,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
fieldValue := *ptrFieldValue
|
fieldValue := *ptrFieldValue
|
||||||
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
|
if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if col.MapType == schemas.ONLYFROMDB {
|
if col.MapType == schemas.ONLYFROMDB {
|
||||||
|
@ -204,7 +205,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
}
|
}
|
||||||
fieldValue := *ptrFieldValue
|
fieldValue := *ptrFieldValue
|
||||||
|
|
||||||
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
|
if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if col.MapType == schemas.ONLYFROMDB {
|
if col.MapType == schemas.ONLYFROMDB {
|
||||||
|
@ -679,7 +680,7 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
|
||||||
|
|
||||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||||
if col.Nullable && isZeroValue(fieldValue) {
|
if col.Nullable && utils.IsValueZero(fieldValue) {
|
||||||
var nilValue *int
|
var nilValue *int
|
||||||
fieldValue = reflect.ValueOf(nilValue)
|
fieldValue = reflect.ValueOf(nilValue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
"xorm.io/xorm/caches"
|
"xorm.io/xorm/caches"
|
||||||
|
"xorm.io/xorm/internal/utils"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -518,7 +519,7 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
|
||||||
|
|
||||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||||
if col.Nullable && isZeroValue(fieldValue) {
|
if col.Nullable && utils.IsValueZero(fieldValue) {
|
||||||
var nilValue *int
|
var nilValue *int
|
||||||
fieldValue = reflect.ValueOf(nilValue)
|
fieldValue = reflect.ValueOf(nilValue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
"xorm.io/xorm/dialects"
|
"xorm.io/xorm/dialects"
|
||||||
|
"xorm.io/xorm/internal/utils"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -304,7 +305,7 @@ func (statement *Statement) buildUpdates(bean interface{},
|
||||||
|
|
||||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||||
if b, ok := getFlagForColumn(nullableMap, col); ok {
|
if b, ok := getFlagForColumn(nullableMap, col); ok {
|
||||||
if b && col.Nullable && isZero(fieldValue.Interface()) {
|
if b && col.Nullable && utils.IsZero(fieldValue.Interface()) {
|
||||||
var nilValue *int
|
var nilValue *int
|
||||||
fieldValue = reflect.ValueOf(nilValue)
|
fieldValue = reflect.ValueOf(nilValue)
|
||||||
fieldType = reflect.TypeOf(fieldValue.Interface())
|
fieldType = reflect.TypeOf(fieldValue.Interface())
|
||||||
|
@ -404,7 +405,7 @@ func (statement *Statement) buildUpdates(bean interface{},
|
||||||
if len(table.PrimaryKeys) == 1 {
|
if len(table.PrimaryKeys) == 1 {
|
||||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||||
// fix non-int pk issues
|
// fix non-int pk issues
|
||||||
if pkField.IsValid() && (!requiredField && !isZero(pkField.Interface())) {
|
if pkField.IsValid() && (!requiredField && !utils.IsZero(pkField.Interface())) {
|
||||||
val = pkField.Interface()
|
val = pkField.Interface()
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
|
@ -418,7 +419,7 @@ func (statement *Statement) buildUpdates(bean interface{},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Blank struct could not be as update data
|
// Blank struct could not be as update data
|
||||||
if requiredField || !isStructZero(fieldValue) {
|
if requiredField || !utils.IsStructZero(fieldValue) {
|
||||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface()))
|
panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface()))
|
||||||
|
@ -439,7 +440,7 @@ func (statement *Statement) buildUpdates(bean interface{},
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if fieldType.Kind() == reflect.Array {
|
if fieldType.Kind() == reflect.Array {
|
||||||
if isArrayValueZero(fieldValue) {
|
if utils.IsArrayZero(fieldValue) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
} else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user