mirror of
https://github.com/duke-git/lancet.git
synced 2025-10-22 15:09:31 +08:00
324 lines
6.6 KiB
Go
324 lines
6.6 KiB
Go
package compare
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/duke-git/lancet/v2/convertor"
|
|
)
|
|
|
|
func compareValue(operator string, left, right any) bool {
|
|
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
|
|
|
|
if leftType.Kind() != rightType.Kind() {
|
|
return false
|
|
}
|
|
|
|
switch leftType.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
|
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
|
|
return compareBasicValue(operator, left, right)
|
|
|
|
case reflect.Struct, reflect.Slice, reflect.Map:
|
|
return compareRefValue(operator, left, right, leftType.Kind())
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind) bool {
|
|
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
|
|
|
|
switch kind {
|
|
case reflect.Struct:
|
|
|
|
// compare time
|
|
if leftVal.CanConvert(timeType) {
|
|
timeObj1, ok := leftObj.(time.Time)
|
|
if !ok {
|
|
timeObj1 = leftVal.Convert(timeType).Interface().(time.Time)
|
|
}
|
|
|
|
timeObj2, ok := rightObj.(time.Time)
|
|
if !ok {
|
|
timeObj2 = rightVal.Convert(timeType).Interface().(time.Time)
|
|
}
|
|
|
|
return compareBasicValue(operator, timeObj1.UnixNano(), timeObj2.UnixNano())
|
|
}
|
|
|
|
// for other struct type, only process equal operator
|
|
switch operator {
|
|
case equal:
|
|
return objectsAreEqualValues(leftObj, rightObj)
|
|
}
|
|
|
|
case reflect.Slice:
|
|
// compare []byte
|
|
if leftVal.CanConvert(bytesType) {
|
|
bytesObj1, ok := leftObj.([]byte)
|
|
if !ok {
|
|
bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte)
|
|
}
|
|
bytesObj2, ok := rightObj.([]byte)
|
|
if !ok {
|
|
bytesObj2 = rightVal.Convert(bytesType).Interface().([]byte)
|
|
}
|
|
|
|
switch operator {
|
|
case equal:
|
|
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
|
|
return true
|
|
}
|
|
case lessThan:
|
|
if bytes.Compare(bytesObj1, bytesObj2) == -1 {
|
|
return true
|
|
}
|
|
case greaterThan:
|
|
if bytes.Compare(bytesObj1, bytesObj2) == 1 {
|
|
return true
|
|
}
|
|
case lessOrEqual:
|
|
if bytes.Compare(bytesObj1, bytesObj2) <= 0 {
|
|
return true
|
|
}
|
|
case greaterOrEqual:
|
|
if bytes.Compare(bytesObj1, bytesObj2) >= 0 {
|
|
return true
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// for other type slice, only process equal operator
|
|
switch operator {
|
|
case equal:
|
|
return reflect.DeepEqual(leftObj, rightObj)
|
|
}
|
|
|
|
case reflect.Map:
|
|
// only process equal operator
|
|
switch operator {
|
|
case equal:
|
|
return reflect.DeepEqual(leftObj, rightObj)
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func objectsAreEqualValues(expected, actual interface{}) bool {
|
|
if objectsAreEqual(expected, actual) {
|
|
return true
|
|
}
|
|
|
|
actualType := reflect.TypeOf(actual)
|
|
if actualType == nil {
|
|
return false
|
|
}
|
|
expectedValue := reflect.ValueOf(expected)
|
|
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
|
|
// Attempt comparison after type conversion
|
|
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func objectsAreEqual(expected, actual interface{}) bool {
|
|
if expected == nil || actual == nil {
|
|
return expected == actual
|
|
}
|
|
|
|
exp, ok := expected.([]byte)
|
|
if !ok {
|
|
return reflect.DeepEqual(expected, actual)
|
|
}
|
|
|
|
act, ok := actual.([]byte)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if exp == nil || act == nil {
|
|
return exp == nil && act == nil
|
|
}
|
|
return bytes.Equal(exp, act)
|
|
}
|
|
|
|
// compareBasic compare basic value: integer, float, string, bool
|
|
func compareBasicValue(operator string, leftValue, rightValue any) bool {
|
|
if leftValue == nil && rightValue == nil && operator == equal {
|
|
return true
|
|
}
|
|
|
|
switch leftVal := leftValue.(type) {
|
|
case json.Number:
|
|
if left, err := leftVal.Float64(); err == nil {
|
|
switch rightVal := rightValue.(type) {
|
|
case json.Number:
|
|
if right, err := rightVal.Float64(); err == nil {
|
|
switch operator {
|
|
case equal:
|
|
if left == right {
|
|
return true
|
|
}
|
|
case lessThan:
|
|
if left < right {
|
|
return true
|
|
}
|
|
case greaterThan:
|
|
if left > right {
|
|
return true
|
|
}
|
|
case lessOrEqual:
|
|
if left <= right {
|
|
return true
|
|
}
|
|
case greaterOrEqual:
|
|
if left >= right {
|
|
return true
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
|
right, err := convertor.ToFloat(rightValue)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
switch operator {
|
|
case equal:
|
|
if left == right {
|
|
return true
|
|
}
|
|
case lessThan:
|
|
if left < right {
|
|
return true
|
|
}
|
|
case greaterThan:
|
|
if left > right {
|
|
return true
|
|
}
|
|
case lessOrEqual:
|
|
if left <= right {
|
|
return true
|
|
}
|
|
case greaterOrEqual:
|
|
if left >= right {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
|
left, err := convertor.ToFloat(leftValue)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
switch rightVal := rightValue.(type) {
|
|
case json.Number:
|
|
if right, err := rightVal.Float64(); err == nil {
|
|
switch operator {
|
|
case equal:
|
|
if left == right {
|
|
return true
|
|
}
|
|
case lessThan:
|
|
if left < right {
|
|
return true
|
|
}
|
|
case greaterThan:
|
|
if left > right {
|
|
return true
|
|
}
|
|
case lessOrEqual:
|
|
if left <= right {
|
|
return true
|
|
}
|
|
case greaterOrEqual:
|
|
if left >= right {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
|
right, err := convertor.ToFloat(rightValue)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
switch operator {
|
|
case equal:
|
|
if left == right {
|
|
return true
|
|
}
|
|
case lessThan:
|
|
if left < right {
|
|
return true
|
|
}
|
|
case greaterThan:
|
|
if left > right {
|
|
return true
|
|
}
|
|
case lessOrEqual:
|
|
if left <= right {
|
|
return true
|
|
}
|
|
case greaterOrEqual:
|
|
if left >= right {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
case string:
|
|
left := leftVal
|
|
switch right := rightValue.(type) {
|
|
case string:
|
|
switch operator {
|
|
case equal:
|
|
if left == right {
|
|
return true
|
|
}
|
|
case lessThan:
|
|
if left < right {
|
|
return true
|
|
}
|
|
case greaterThan:
|
|
if left > right {
|
|
return true
|
|
}
|
|
case lessOrEqual:
|
|
if left <= right {
|
|
return true
|
|
}
|
|
case greaterOrEqual:
|
|
if left >= right {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
case bool:
|
|
left := leftVal
|
|
switch right := rightValue.(type) {
|
|
case bool:
|
|
switch operator {
|
|
case equal:
|
|
if left == right {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
}
|