From cacedf2a05af729921568a0eb9f9d04322df8409 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Wed, 26 Apr 2023 11:25:04 +0800 Subject: [PATCH] doc: add document for compare package --- README.md | 45 +++-- README_zh-CN.md | 45 +++-- compare/compare.go | 58 ++++++ compare/compare_example_test.go | 170 +++++++++++++++++ compare/compare_internal.go | 323 +++++++++++++++++++++++++++++++ compare/compare_test.go | 134 +++++++++++++ docs/compare.md | 326 ++++++++++++++++++++++++++++++++ docs/compare_zh-CN.md | 326 ++++++++++++++++++++++++++++++++ 8 files changed, 1397 insertions(+), 30 deletions(-) create mode 100644 compare/compare.go create mode 100644 compare/compare_example_test.go create mode 100644 compare/compare_internal.go create mode 100644 compare/compare_test.go create mode 100644 docs/compare.md create mode 100644 docs/compare_zh-CN.md diff --git a/README.md b/README.md index 5ae5691..8fd19cb 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ English | [简体中文](./README_zh-CN.md) ## Feature - 👏 Comprehensive, efficient and reusable. -- 💪 300+ go util functions, support string, slice, datetime, net, crypt... +- 💪 400+ go util functions, support string, slice, datetime, net, crypt... - 💅 Only depend on the go standard library. - 🌍 Unit test for every exported function. @@ -63,7 +63,22 @@ func main() { ## API Documentation -### 1. Convertor package contains some functions for data convertion. +### 1. Compare package provides a lightweight comparison function on any type. + +```go +import "github.com/duke-git/lancet/compare" +``` + +#### Function list: + +- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#Equal) +- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#EqualValue) +- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#LessThan) +- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#GreaterThan) +- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#LessOrEqual) +- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#GreaterOrEqual) + +### 2. Convertor package contains some functions for data convertion. ```go import "github.com/duke-git/lancet/convertor" @@ -86,7 +101,7 @@ import "github.com/duke-git/lancet/convertor" - [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DeepClone) - [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#CopyProperties) -### 2. Cryptor package is for data encryption and decryption. +### 3. Cryptor package is for data encryption and decryption. ```go import "github.com/duke-git/lancet/cryptor" @@ -127,7 +142,7 @@ import "github.com/duke-git/lancet/cryptor" - [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaEncrypt) - [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaDecrypt) -### 3. Datetime package supports date and time format and compare. +### 4. Datetime package supports date and time format and compare. ```go import "github.com/duke-git/lancet/datetime" @@ -166,7 +181,7 @@ import "github.com/duke-git/lancet/datetime" - [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormatForTpl) - [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToIso8601) -### 4. Fileutil package implements some basic functions for file operations. +### 5. Fileutil package implements some basic functions for file operations. ```go import "github.com/duke-git/lancet/fileutil" @@ -196,7 +211,7 @@ import "github.com/duke-git/lancet/fileutil" - [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Sha) - [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadCsvFile) -### 5. Formatter contains some functions for data formatting. +### 6. Formatter contains some functions for data formatting. ```go import "github.com/duke-git/lancet/formatter" @@ -212,7 +227,7 @@ import "github.com/duke-git/lancet/formatter" - [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#ParseDecimalBytes) - [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#ParseBinaryBytes) -### Function package can control the flow of function execution and support part of functional programming +### 7. Function package can control the flow of function execution and support part of functional programming ```go import "github.com/duke-git/lancet/function" @@ -230,7 +245,7 @@ import "github.com/duke-git/lancet/function" - [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Schedule) - [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Watcher) -### 6. Mathutil package implements some functions for math calculation. +### 8. Mathutil package implements some functions for math calculation. ```go import "github.com/duke-git/lancet/mathutil" @@ -250,7 +265,7 @@ import "github.com/duke-git/lancet/mathutil" - [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#PointDistance) - [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#IsPrime) -### 7. Netutil package contains functions to get net information and send http request. +### 9. Netutil package contains functions to get net information and send http request. ```go import "github.com/duke-git/lancet/netutil" @@ -278,7 +293,7 @@ import "github.com/duke-git/lancet/netutil" - [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsPingConnected) - [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsTelnetConnected) -### 8. Random package implements some basic functions to generate random int and string. +### 10. Random package implements some basic functions to generate random int and string. ```go import "github.com/duke-git/lancet/random" @@ -295,7 +310,7 @@ import "github.com/duke-git/lancet/random" - [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeralOrLetter) - [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4) -### 9. Retry package is for executing a function repeatedly until it was successful or canceled by the context. +### 11. Retry package is for executing a function repeatedly until it was successful or canceled by the context. ```go import "github.com/duke-git/lancet/retry" @@ -309,7 +324,7 @@ import "github.com/duke-git/lancet/retry" - [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryDuration) - [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryTimes) -### 10. Slice contains some functions to manipulate slice. +### 12. Slice contains some functions to manipulate slice. ```go import "github.com/duke-git/lancet/slice" @@ -358,7 +373,7 @@ import "github.com/duke-git/lancet/slice" - [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#UpdateByIndex) - [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Without) -### 11. Strutil package contains some functions to manipulate string. +### 13. Strutil package contains some functions to manipulate string. ```go import "github.com/duke-git/lancet/strutil" @@ -396,7 +411,7 @@ import "github.com/duke-git/lancet/strutil" - [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasSuffixAny) - [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IndexOffset) -### 12. System package contain some functions about os, runtime, shell command. +### 14. System package contain some functions about os, runtime, shell command. ```go import "github.com/duke-git/lancet/system" @@ -414,7 +429,7 @@ import "github.com/duke-git/lancet/system" - [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system.md#ExecCommand) - [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system.md#GetOsBits) -### 13. Validator package contains some functions for data validation. +### 15. Validator package contains some functions for data validation. ```go import "github.com/duke-git/lancet/validator" diff --git a/README_zh-CN.md b/README_zh-CN.md index d0717ac..638662f 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -23,7 +23,7 @@ ## 特性 - 👏 全面、高效、可复用 -- 💪 300+常用 go 工具函数,支持 string、slice、datetime、net、crypt... +- 💪 400+常用 go 工具函数,支持 string、slice、datetime、net、crypt... - 💅 只依赖 go 标准库 - 🌍 所有导出函数单元测试覆盖率 100% @@ -62,7 +62,22 @@ func main() { ## API 文档 -### 1. convertor 转换器包支持一些常见的数据类型转换。 + +### 1. compare包提供几个轻量级的类型比较函数。 +```go +import "github.com/duke-git/lancet/compare" +``` + +#### Function list: + +- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#Equal) +- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#EqualValue) +- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessThan) +- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterThan) +- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessOrEqual) +- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterOrEqual) + +### 2. convertor转换器包支持一些常见的数据类型转换。 ```go import "github.com/duke-git/lancet/convertor" @@ -85,7 +100,7 @@ import "github.com/duke-git/lancet/convertor" - [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone) - [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#CopyProperties) -### 2. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 +### 3. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 ```go import "github.com/duke-git/lancet/cryptor" @@ -126,7 +141,7 @@ import "github.com/duke-git/lancet/cryptor" - [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncrypt) - [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecrypt) -### 3. datetime 日期时间处理包,格式化日期,比较日期。 +### 4. datetime 日期时间处理包,格式化日期,比较日期。 ```go import "github.com/duke-git/lancet/datetime" @@ -165,7 +180,7 @@ import "github.com/duke-git/lancet/datetime" - [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormatForTpl) - [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToIso8601) -### 4. fileutil 包支持文件基本操作。 +### 5. fileutil 包支持文件基本操作。 ```go import "github.com/duke-git/lancet/fileutil" @@ -195,7 +210,7 @@ import "github.com/duke-git/lancet/fileutil" - [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha) - [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadCsvFile) -### 5. formatter 格式化器包含一些数据格式化处理方法。 +### 6. formatter 格式化器包含一些数据格式化处理方法。 ```go import "github.com/duke-git/lancet/formatter" @@ -211,7 +226,7 @@ import "github.com/duke-git/lancet/formatter" - [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseDecimalBytes) - [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseBinaryBytes) -### function 函数包控制函数执行流程,包含部分函数式编程。 +### 7. function 函数包控制函数执行流程,包含部分函数式编程。 ```go import "github.com/duke-git/lancet/function" @@ -229,7 +244,7 @@ import "github.com/duke-git/lancet/function" - [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Schedule) - [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Watcher) -### 6. mathutil 包实现了一些数学计算的函数。 +### 8. mathutil 包实现了一些数学计算的函数。 ```go import "github.com/duke-git/lancet/mathutil" @@ -249,7 +264,7 @@ import "github.com/duke-git/lancet/mathutil" - [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#PointDistance) - [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#IsPrime) -### 7. netutil 网络包支持获取 ip 地址,发送 http 请求。 +### 9. netutil 网络包支持获取 ip 地址,发送 http 请求。 ```go import "github.com/duke-git/lancet/netutil" @@ -277,7 +292,7 @@ import "github.com/duke-git/lancet/netutil" - [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPingConnected) - [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsTelnetConnected) -### 8. random 随机数生成器包,可以生成随机[]bytes, int, string。 +### 10. random 随机数生成器包,可以生成随机[]bytes, int, string。 ```go import "github.com/duke-git/lancet/random" @@ -294,7 +309,7 @@ import "github.com/duke-git/lancet/random" - [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeralOrLetter) - [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4) -### 9. retry 重试执行函数直到函数运行成功或被 context cancel。 +### 11. retry 重试执行函数直到函数运行成功或被 context cancel。 ```go import "github.com/duke-git/lancet/retry" @@ -308,7 +323,7 @@ import "github.com/duke-git/lancet/retry" - [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryDuration) - [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryTimes) -### 10. slice 包包含操作切片的方法集合。 +### 12. slice 包包含操作切片的方法集合。 ```go import "github.com/duke-git/lancet/slice" @@ -357,7 +372,7 @@ import "github.com/duke-git/lancet/slice" - [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UpdateByIndex) - [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Without) -### 12. strutil 包含处理字符串的相关函数。 +### 13. strutil 包含处理字符串的相关函数。 ```go import "github.com/duke-git/lancet/strutil" @@ -395,7 +410,7 @@ import "github.com/duke-git/lancet/strutil" - [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasSuffixAny) - [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IndexOffset) -### 13. system 包含 os, runtime, shell command 相关函数。 +### 14. system 包含 os, runtime, shell command 相关函数。 ```go import "github.com/duke-git/lancet/system" @@ -413,7 +428,7 @@ import "github.com/duke-git/lancet/system" - [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#ExecCommand) - [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsBits) -### 14. validator 验证器包,包含常用字符串格式验证函数。 +### 15. validator 验证器包,包含常用字符串格式验证函数。 ```go import "github.com/duke-git/lancet/validator" diff --git a/compare/compare.go b/compare/compare.go new file mode 100644 index 0000000..9043b85 --- /dev/null +++ b/compare/compare.go @@ -0,0 +1,58 @@ +// Copyright 2023 dudaodong@gmail.com. All rights resulterved. +// Use of this source code is governed by MIT license + +// Package compare provides a lightweight comparison function on interface{} type. +// reference: https://github.com/stretchr/testify +package compare + +import ( + "reflect" + "time" + + "github.com/duke-git/lancet/convertor" +) + +// operator type +const ( + equal = "eq" + lessThan = "lt" + greaterThan = "gt" + lessOrEqual = "le" + greaterOrEqual = "ge" +) + +var ( + timeType = reflect.TypeOf(time.Time{}) + bytesType = reflect.TypeOf([]byte{}) +) + +// Equal checks if two values are equal or not. (check both type and value) +func Equal(left, right interface{}) bool { + return compareValue(equal, left, right) +} + +// EqualValue checks if two values are equal or not. (check value only) +func EqualValue(left, right interface{}) bool { + ls, rs := convertor.ToString(left), convertor.ToString(right) + return ls == rs +} + +// LessThan checks if value `left` less than value `right`. +func LessThan(left, right interface{}) bool { + return compareValue(lessThan, left, right) +} + +// GreaterThan checks if value `left` greater than value `right`. +func GreaterThan(left, right interface{}) bool { + return compareValue(greaterThan, left, right) +} + +// LessOrEqual checks if value `left` less than or equal to value `right`. +func LessOrEqual(left, right interface{}) bool { + return compareValue(lessOrEqual, left, right) +} + +// GreaterOrEqual checks if value `left` greater than or equal to value `right`. +func GreaterOrEqual(left, right interface{}) bool { + return compareValue(greaterOrEqual, left, right) +} diff --git a/compare/compare_example_test.go b/compare/compare_example_test.go new file mode 100644 index 0000000..73fbada --- /dev/null +++ b/compare/compare_example_test.go @@ -0,0 +1,170 @@ +package compare + +import ( + "fmt" + "time" +) + +func ExampleEqual() { + result1 := Equal(1, 1) + result2 := Equal("1", "1") + result3 := Equal([]int{1, 2, 3}, []int{1, 2, 3}) + result4 := Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}) + + result5 := Equal(1, "1") + result6 := Equal(1, int64(1)) + result7 := Equal([]int{1, 2}, []int{1, 2, 3}) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} + +func ExampleEqualValue() { + result1 := EqualValue(1, 1) + result2 := EqualValue(int(1), int64(1)) + result3 := EqualValue(1, "1") + result4 := EqualValue(1, "2") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + + // Output: + // true + // true + // true + // false +} + +func ExampleLessThan() { + result1 := LessThan(1, 2) + result2 := LessThan(1.1, 2.2) + result3 := LessThan("a", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := LessThan(time1, time2) + + result5 := LessThan(2, 1) + result6 := LessThan(1, int64(2)) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + + // Output: + // true + // true + // true + // true + // false + // false +} + +func ExampleGreaterThan() { + result1 := GreaterThan(2, 1) + result2 := GreaterThan(2.2, 1.1) + result3 := GreaterThan("b", "a") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := GreaterThan(time2, time1) + + result5 := GreaterThan(1, 2) + result6 := GreaterThan(int64(2), 1) + result7 := GreaterThan("b", "c") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} + +func ExampleLessOrEqual() { + result1 := LessOrEqual(1, 1) + result2 := LessOrEqual(1.1, 2.2) + result3 := LessOrEqual("a", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := LessOrEqual(time1, time2) + + result5 := LessOrEqual(2, 1) + result6 := LessOrEqual(1, int64(2)) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + + // Output: + // true + // true + // true + // true + // false + // false +} + +func ExampleGreaterOrEqual() { + result1 := GreaterOrEqual(1, 1) + result2 := GreaterOrEqual(2.2, 1.1) + result3 := GreaterOrEqual("b", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := GreaterOrEqual(time2, time1) + + result5 := GreaterOrEqual(1, 2) + result6 := GreaterOrEqual(int64(2), 1) + result7 := GreaterOrEqual("b", "c") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} diff --git a/compare/compare_internal.go b/compare/compare_internal.go new file mode 100644 index 0000000..562072d --- /dev/null +++ b/compare/compare_internal.go @@ -0,0 +1,323 @@ +package compare + +import ( + "bytes" + "encoding/json" + "reflect" + "time" + + "github.com/duke-git/lancet/convertor" +) + +func compareValue(operator string, left, right interface{}) 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 interface{}, 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 interface{}) 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 +} diff --git a/compare/compare_test.go b/compare/compare_test.go new file mode 100644 index 0000000..61f26f0 --- /dev/null +++ b/compare/compare_test.go @@ -0,0 +1,134 @@ +package compare + +import ( + "testing" + "time" + + "github.com/duke-git/lancet/internal" +) + +func TestEqual(t *testing.T) { + assert := internal.NewAssert(t, "TestEqual") + + assert.Equal(true, Equal(1, 1)) + assert.Equal(true, Equal(int64(1), int64(1))) + assert.Equal(true, Equal("a", "a")) + assert.Equal(true, Equal(true, true)) + assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3})) + assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})) + + assert.Equal(false, Equal(1, 2)) + assert.Equal(false, Equal(1, int64(1))) + assert.Equal(false, Equal("a", "b")) + assert.Equal(false, Equal(true, false)) + assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3})) + assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"})) + + time1 := time.Now() + time2 := time1.Add(time.Second) + time3 := time1.Add(time.Second) + + assert.Equal(false, Equal(time1, time2)) + assert.Equal(true, Equal(time2, time3)) + + st1 := struct { + A string + B string + }{ + A: "a", + B: "b", + } + + st2 := struct { + A string + B string + }{ + A: "a", + B: "b", + } + + st3 := struct { + A string + B string + }{ + A: "a1", + B: "b", + } + + assert.Equal(true, Equal(st1, st2)) + assert.Equal(false, Equal(st1, st3)) +} + +func TestEqualValue(t *testing.T) { + assert := internal.NewAssert(t, "TestEqualValue") + + assert.Equal(true, EqualValue(1, 1)) + assert.Equal(true, EqualValue(int(1), int64(1))) + assert.Equal(true, EqualValue(1, "1")) + + assert.Equal(false, EqualValue(1, "2")) +} + +func TestLessThan(t *testing.T) { + assert := internal.NewAssert(t, "TestLessThan") + + assert.Equal(true, LessThan(1, 2)) + assert.Equal(true, LessThan(1.1, 2.2)) + assert.Equal(true, LessThan("a", "b")) + + time1 := time.Now() + time2 := time1.Add(time.Second) + assert.Equal(true, LessThan(time1, time2)) + + assert.Equal(false, LessThan(1, 1)) + assert.Equal(false, LessThan(1, int64(1))) +} + +func TestGreaterThan(t *testing.T) { + assert := internal.NewAssert(t, "TestGreaterThan") + + assert.Equal(true, GreaterThan(2, 1)) + assert.Equal(true, GreaterThan(2.2, 1.1)) + assert.Equal(true, GreaterThan("b", "a")) + + time1 := time.Now() + time2 := time1.Add(time.Second) + assert.Equal(true, GreaterThan(time2, time1)) + + assert.Equal(false, GreaterThan(1, 2)) + assert.Equal(false, GreaterThan(int64(2), 1)) + assert.Equal(false, GreaterThan("b", "c")) +} + +func TestLessOrEqual(t *testing.T) { + assert := internal.NewAssert(t, "TestLessOrEqual") + + assert.Equal(true, LessOrEqual(1, 2)) + assert.Equal(true, LessOrEqual(1, 1)) + assert.Equal(true, LessOrEqual(1.1, 2.2)) + assert.Equal(true, LessOrEqual("a", "b")) + + time1 := time.Now() + time2 := time1.Add(time.Second) + assert.Equal(true, LessOrEqual(time1, time2)) + + assert.Equal(false, LessOrEqual(2, 1)) + assert.Equal(false, LessOrEqual(1, int64(2))) +} + +func TestGreaterOrEqual(t *testing.T) { + assert := internal.NewAssert(t, "TestGreaterThan") + + assert.Equal(true, GreaterOrEqual(2, 1)) + assert.Equal(true, GreaterOrEqual(1, 1)) + assert.Equal(true, GreaterOrEqual(2.2, 1.1)) + assert.Equal(true, GreaterOrEqual("b", "b")) + + time1 := time.Now() + time2 := time1.Add(time.Second) + assert.Equal(true, GreaterOrEqual(time2, time1)) + + assert.Equal(false, GreaterOrEqual(1, 2)) + assert.Equal(false, GreaterOrEqual(int64(2), 1)) + assert.Equal(false, GreaterOrEqual("b", "c")) +} diff --git a/docs/compare.md b/docs/compare.md new file mode 100644 index 0000000..d0aefaf --- /dev/null +++ b/docs/compare.md @@ -0,0 +1,326 @@ +# Compare + +Package compare provides a lightweight comparison function on any type. + +
+ +## Source: + +- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go) + +- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go) + +
+ +## Usage: + +```go +import ( + "github.com/duke-git/lancet/condition" +) +``` + +
+ +## Index + +- [Equal](#Equal) +- [EqualValue](#EqualValue) +- [LessThan](#LessThan) +- [GreaterThan](#GreaterThan) +- [LessOrEqual](#LessOrEqual) +- [GreaterOrEqual](#GreaterOrEqual) + +
+ +## Documentation + +### Equal + +

Checks if two values are equal or not. (check both type and value)

+ +Signature: + +```go +func Equal(left, right any) bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.Equal(1, 1) + result2 := compare.Equal("1", "1") + result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3}) + result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}) + + result5 := compare.Equal(1, "1") + result6 := compare.Equal(1, int64(1)) + result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3}) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} +``` + +### EqualValue + +

Checks if two values are equal or not. (check value only)

+ +Signature: + +```go +func EqualValue(left, right any) bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.EqualValue(1, 1) + result2 := compare.EqualValue(int(1), int64(1)) + result3 := compare.EqualValue(1, "1") + result4 := compare.EqualValue(1, "2") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + + // Output: + // true + // true + // true + // false +} +``` + +### LessThan + +

Checks if value `left` less than value `right`.

+ +Signature: + +```go +func LessThan(left, right any) bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.LessThan(1, 2) + result2 := compare.LessThan(1.1, 2.2) + result3 := compare.LessThan("a", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.LessThan(time1, time2) + + result5 := compare.LessThan(2, 1) + result6 := compare.LessThan(1, int64(2)) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + + // Output: + // true + // true + // true + // true + // false + // false +} +``` + +### GreaterThan + +

Checks if value `left` greater than value `right`.

+ +Signature: + +```go +func GreaterThan(left, right any) bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.GreaterThan(2, 1) + result2 := compare.GreaterThan(2.2, 1.1) + result3 := compare.GreaterThan("b", "a") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.GreaterThan(time2, time1) + + result5 := compare.GreaterThan(1, 2) + result6 := compare.GreaterThan(int64(2), 1) + result7 := compare.GreaterThan("b", "c") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} +``` + +### LessOrEqual + +

Checks if value `left` less than or equal than value `right`.

+ +Signature: + +```go +func LessOrEqual(left, right any) bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.LessOrEqual(1, 1) + result2 := compare.LessOrEqual(1.1, 2.2) + result3 := compare.LessOrEqual("a", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.LessOrEqual(time1, time2) + + result5 := compare.LessOrEqual(2, 1) + result6 := compare.LessOrEqual(1, int64(2)) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + + // Output: + // true + // true + // true + // true + // false + // false +} +``` + +### GreaterOrEqual + +

Checks if value `left` less greater or equal than value `right`.

+ +Signature: + +```go +func GreaterOrEqual(left, right any) bool +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.GreaterOrEqual(1, 1) + result2 := compare.GreaterOrEqual(2.2, 1.1) + result3 := compare.GreaterOrEqual("b", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.GreaterOrEqual(time2, time1) + + result5 := compare.GreaterOrEqual(1, 2) + result6 := compare.GreaterOrEqual(int64(2), 1) + result7 := compare.GreaterOrEqual("b", "c") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} +``` diff --git a/docs/compare_zh-CN.md b/docs/compare_zh-CN.md new file mode 100644 index 0000000..8693d21 --- /dev/null +++ b/docs/compare_zh-CN.md @@ -0,0 +1,326 @@ +# Compare + +compare包提供几个轻量级的类型比较函数。 + +
+ +## 源码: + +- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go) + +- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go) + +
+ +## 用法: + +```go +import ( + "github.com/duke-git/lancet/condition" +) +``` + +
+ +## 目录 + +- [Equal](#Equal) +- [EqualValue](#EqualValue) +- [LessThan](#LessThan) +- [GreaterThan](#GreaterThan) +- [LessOrEqual](#LessOrEqual) +- [GreaterOrEqual](#GreaterOrEqual) + +
+ +## Documentation + +### Equal + +

检查两个值是否相等(检查类型和值)

+ +函数签名: + +```go +func Equal(left, right any) bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.Equal(1, 1) + result2 := compare.Equal("1", "1") + result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3}) + result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}) + + result5 := compare.Equal(1, "1") + result6 := compare.Equal(1, int64(1)) + result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3}) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} +``` + +### EqualValue + +

检查两个值是否相等(只检查值)

+ +函数签名: + +```go +func EqualValue(left, right any) bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.EqualValue(1, 1) + result2 := compare.EqualValue(int(1), int64(1)) + result3 := compare.EqualValue(1, "1") + result4 := compare.EqualValue(1, "2") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + + // Output: + // true + // true + // true + // false +} +``` + +### LessThan + +

验证参数`left`的值是否小于参数`right`的值。

+ +函数签名: + +```go +func LessThan(left, right any) bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.LessThan(1, 2) + result2 := compare.LessThan(1.1, 2.2) + result3 := compare.LessThan("a", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.LessThan(time1, time2) + + result5 := compare.LessThan(2, 1) + result6 := compare.LessThan(1, int64(2)) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + + // Output: + // true + // true + // true + // true + // false + // false +} +``` + +### GreaterThan + +

验证参数`left`的值是否大于参数`right`的值。

+ +函数签名: + +```go +func GreaterThan(left, right any) bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.GreaterThan(2, 1) + result2 := compare.GreaterThan(2.2, 1.1) + result3 := compare.GreaterThan("b", "a") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.GreaterThan(time2, time1) + + result5 := compare.GreaterThan(1, 2) + result6 := compare.GreaterThan(int64(2), 1) + result7 := compare.GreaterThan("b", "c") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} +``` + +### LessOrEqual + +

验证参数`left`的值是否小于或等于参数`right`的值。

+ +函数签名: + +```go +func LessOrEqual(left, right any) bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.LessOrEqual(1, 1) + result2 := compare.LessOrEqual(1.1, 2.2) + result3 := compare.LessOrEqual("a", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.LessOrEqual(time1, time2) + + result5 := compare.LessOrEqual(2, 1) + result6 := compare.LessOrEqual(1, int64(2)) + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + + // Output: + // true + // true + // true + // true + // false + // false +} +``` + +### GreaterOrEqual + +

验证参数`left`的值是否大于或参数`right`的值。

+ +函数签名: + +```go +func GreaterOrEqual(left, right any) bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/compare" +) + +func main() { + result1 := compare.GreaterOrEqual(1, 1) + result2 := compare.GreaterOrEqual(2.2, 1.1) + result3 := compare.GreaterOrEqual("b", "b") + + time1 := time.Now() + time2 := time1.Add(time.Second) + result4 := compare.GreaterOrEqual(time2, time1) + + result5 := compare.GreaterOrEqual(1, 2) + result6 := compare.GreaterOrEqual(int64(2), 1) + result7 := compare.GreaterOrEqual("b", "c") + + fmt.Println(result1) + fmt.Println(result2) + fmt.Println(result3) + fmt.Println(result4) + fmt.Println(result5) + fmt.Println(result6) + fmt.Println(result7) + + // Output: + // true + // true + // true + // true + // false + // false + // false +} +```