Move zero functions to a standalone package #1548

Merged
lunny merged 2 commits from lunny/zero into master 2020-02-26 12:45:15 +00:00
9 changed files with 125 additions and 112 deletions
Showing only changes of commit 5027038e64 - Show all commits

View File

@ -12,6 +12,7 @@ import (
"time"
"xorm.io/builder"
"xorm.io/xorm/internal/utils"
"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)
// fix non-int pk issues
//if pkField.Int() != 0 {
if pkField.IsValid() && !isZero(pkField.Interface()) {
if pkField.IsValid() && !utils.IsZero(pkField.Interface()) {
val = pkField.Interface()
} else {
continue

View File

@ -11,8 +11,6 @@ import (
"sort"
"strconv"
"strings"
"xorm.io/xorm/schemas"
)
// 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
}
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 {
var v interface{}
kind := tp.Kind()
@ -229,15 +138,6 @@ func int64ToInt(id int64, tp reflect.Type) 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 {
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
}

98
internal/utils/zero.go Normal file
View 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
}

View File

@ -7,6 +7,8 @@ package schemas
import (
"bytes"
"encoding/gob"
"xorm.io/xorm/internal/utils"
)
type PK []interface{}
@ -16,6 +18,15 @@ func NewPK(pks ...interface{}) *PK {
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) {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)

View File

@ -703,7 +703,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
return nil, err
}
if !isPKZero(pk) {
if !pk.IsZero() {
// !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
// property to be fetched lazily

View File

@ -224,7 +224,7 @@ func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Val
return err
}
if !isPKZero(pk) {
if !pk.IsZero() {
// !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
// property to be fetched lazily
@ -506,7 +506,7 @@ func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Val
return err
}
if !isPKZero(pk) {
if !pk.IsZero() {
// !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
// property to be fetched lazily

View File

@ -13,6 +13,7 @@ import (
"strings"
"xorm.io/builder"
"xorm.io/xorm/internal/utils"
"xorm.io/xorm/schemas"
)
@ -153,7 +154,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
return 0, err
}
fieldValue := *ptrFieldValue
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) {
continue
}
if col.MapType == schemas.ONLYFROMDB {
@ -204,7 +205,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
}
fieldValue := *ptrFieldValue
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) {
continue
}
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
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
if col.Nullable && isZeroValue(fieldValue) {
if col.Nullable && utils.IsValueZero(fieldValue) {
var nilValue *int
fieldValue = reflect.ValueOf(nilValue)
}

View File

@ -13,6 +13,7 @@ import (
"xorm.io/builder"
"xorm.io/xorm/caches"
"xorm.io/xorm/internal/utils"
"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
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
if col.Nullable && isZeroValue(fieldValue) {
if col.Nullable && utils.IsValueZero(fieldValue) {
var nilValue *int
fieldValue = reflect.ValueOf(nilValue)
}

View File

@ -13,6 +13,7 @@ import (
"xorm.io/builder"
"xorm.io/xorm/dialects"
"xorm.io/xorm/internal/utils"
"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
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
fieldValue = reflect.ValueOf(nilValue)
fieldType = reflect.TypeOf(fieldValue.Interface())
@ -404,7 +405,7 @@ func (statement *Statement) buildUpdates(bean interface{},
if len(table.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
// fix non-int pk issues
if pkField.IsValid() && (!requiredField && !isZero(pkField.Interface())) {
if pkField.IsValid() && (!requiredField && !utils.IsZero(pkField.Interface())) {
val = pkField.Interface()
} else {
continue
@ -418,7 +419,7 @@ func (statement *Statement) buildUpdates(bean interface{},
}
} else {
// Blank struct could not be as update data
if requiredField || !isStructZero(fieldValue) {
if requiredField || !utils.IsStructZero(fieldValue) {
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
if err != nil {
panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface()))
@ -439,7 +440,7 @@ func (statement *Statement) buildUpdates(bean interface{},
continue
}
if fieldType.Kind() == reflect.Array {
if isArrayValueZero(fieldValue) {
if utils.IsArrayZero(fieldValue) {
continue
}
} else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {