Module split
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
cover.out
|
||||
cover.html
|
||||
38
.golangci.yaml
Normal file
38
.golangci.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
# re-enable when working
|
||||
- rowserrcheck
|
||||
- wastedassign
|
||||
# maybe enable these
|
||||
- wrapcheck
|
||||
# leave these disabled
|
||||
- cyclop
|
||||
- deadcode
|
||||
- dupl
|
||||
- exhaustivestruct
|
||||
- exhaustruct
|
||||
- forbidigo
|
||||
- forcetypeassert
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gocognit
|
||||
- goconst
|
||||
- godox
|
||||
- golint
|
||||
- gomnd
|
||||
- ifshort
|
||||
- interfacer
|
||||
- lll
|
||||
- maintidx
|
||||
- maligned
|
||||
- nilnil
|
||||
- nestif
|
||||
- nlreturn
|
||||
- nolintlint
|
||||
- nosnakecase
|
||||
- scopelint
|
||||
- structcheck
|
||||
- thelper
|
||||
- varcheck
|
||||
- varnamelen
|
||||
20
equal.go
Normal file
20
equal.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package path
|
||||
|
||||
import "time"
|
||||
|
||||
func Equal(obj any, path string, matchStr string) (bool, error) {
|
||||
return op(obj, path, matchStr, equal)
|
||||
}
|
||||
|
||||
func equal(obj, match any, _ string) bool {
|
||||
switch objt := obj.(type) {
|
||||
case time.Time:
|
||||
tm := match.(*timeVal)
|
||||
|
||||
// TODO: Replace Truncate() with a timezone-aware version
|
||||
return tm.time.Equal(objt.Truncate(tm.precision))
|
||||
|
||||
default:
|
||||
return obj == match
|
||||
}
|
||||
}
|
||||
464
equal_test.go
Normal file
464
equal_test.go
Normal file
@@ -0,0 +1,464 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEqualStruct(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType2{
|
||||
Tt1: testType1{
|
||||
Int: 2345,
|
||||
},
|
||||
}, "tt1.int", "2345")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType2{
|
||||
Tt1p: &testType1{
|
||||
Int: 2345,
|
||||
},
|
||||
}, "tt1p.int", "2345")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType2{}, "tt1p.int", "2345")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualPointer(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
TimeP: &tm,
|
||||
}, "timep", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
TimeP: &tm,
|
||||
}, "timep", "2006-01-02T15:04:05+01:00")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualPointers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm1, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
TimesP: []*time.Time{&tm1, nil, &tm2},
|
||||
}, "timesp", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
TimesP: []*time.Time{&tm1, &tm2},
|
||||
}, "timesp", "2006-01-02T15:04:05+01:00")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1234")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1235")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3456")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3457")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4567")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4568")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5678")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5679")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1415")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159265")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "foo")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "bar")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "false")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
|
||||
boolp := true
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
BoolP: &boolp,
|
||||
}, "boolp", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{}, "boolp", "false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
}
|
||||
|
||||
func TestEqualInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "4")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "4")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualUInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "4")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualUInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "4")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualFloat32s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7182")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7183")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualFloat64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7182")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7183")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "foo")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "zig")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualBools(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Bools: []bool{false, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:05+00:00")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:05+01:00")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "1136214245")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "1136214246")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "1136214245000")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "1136214245001")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05.999999999Z", "2006-01-02T15:04:05.500000000Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Time: tm2,
|
||||
}, "time", "1136214245")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
}
|
||||
|
||||
func TestEqualTimes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "1136214245000")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "1136214245001")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d, err := civil.ParseDate("2006-01-01")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestEqualDates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-01")
|
||||
require.NoError(t, err)
|
||||
|
||||
d2, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Equal(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Equal(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
19
go.mod
Normal file
19
go.mod
Normal file
@@ -0,0 +1,19 @@
|
||||
module github.com/gopatchy/path
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.0
|
||||
github.com/gopatchy/jsrest v0.0.0-20230420161234-12a6d6da8b7f
|
||||
github.com/stretchr/testify v1.8.2
|
||||
go.uber.org/goleak v1.2.1
|
||||
golang.org/x/exp v0.0.0-20230420155640-133eef4313cb
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gopatchy/metadata v0.0.0-20230420053349-25837551c11d // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/vfaronov/httpheader v0.1.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
33
go.sum
Normal file
33
go.sum
Normal file
@@ -0,0 +1,33 @@
|
||||
cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
|
||||
cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/gopatchy/jsrest v0.0.0-20230420161234-12a6d6da8b7f h1:1uGPJm9K0Fro1UEcZpuK6FNPU/U1XX3aS3x0/PdFS40=
|
||||
github.com/gopatchy/jsrest v0.0.0-20230420161234-12a6d6da8b7f/go.mod h1:Ryi8LRBLFDhQsMQHuh+6VL7HcFWjBXOEiOy9Ip/Q+Ps=
|
||||
github.com/gopatchy/metadata v0.0.0-20230420053349-25837551c11d h1:chunoM47vkWSanIvLx4uRSkLMG6chDZOy09L2tt/bv8=
|
||||
github.com/gopatchy/metadata v0.0.0-20230420053349-25837551c11d/go.mod h1:VgD33raUShjDePCDBo55aj+eSXFtUEpMzs+Ie39g2zo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 h1:Ha8xCaq6ln1a+R91Km45Oq6lPXj2Mla6CRJYcuV2h1w=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/vfaronov/httpheader v0.1.0 h1:VdzetvOKRoQVHjSrXcIOwCV6JG5BCAW9rjbVbFPBmb0=
|
||||
github.com/vfaronov/httpheader v0.1.0/go.mod h1:ZBxgbYu6nbN5V9Ptd1yYUUan0voD0O8nZLXHyxLgoLE=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
golang.org/x/exp v0.0.0-20230420155640-133eef4313cb h1:rhjz/8Mbfa8xROFiH+MQphmAmgqRM0bOMnytznhWEXk=
|
||||
golang.org/x/exp v0.0.0-20230420155640-133eef4313cb/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
50
greater.go
Normal file
50
greater.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
)
|
||||
|
||||
func Greater(obj any, path string, matchStr string) (bool, error) {
|
||||
return op(obj, path, matchStr, greater)
|
||||
}
|
||||
|
||||
func greater(obj, match any, _ string) bool {
|
||||
switch objt := obj.(type) {
|
||||
case int:
|
||||
return objt > match.(int)
|
||||
|
||||
case int64:
|
||||
return objt > match.(int64)
|
||||
|
||||
case uint:
|
||||
return objt > match.(uint)
|
||||
|
||||
case uint64:
|
||||
return objt > match.(uint64)
|
||||
|
||||
case float32:
|
||||
return objt > match.(float32)
|
||||
|
||||
case float64:
|
||||
return objt > match.(float64)
|
||||
|
||||
case string:
|
||||
return objt > match.(string)
|
||||
|
||||
case bool:
|
||||
return objt && !match.(bool)
|
||||
|
||||
case time.Time:
|
||||
tm := match.(*timeVal)
|
||||
|
||||
return objt.Truncate(tm.precision).After(tm.time)
|
||||
|
||||
case civil.Date:
|
||||
return objt.After(match.(civil.Date))
|
||||
|
||||
default:
|
||||
panic(obj)
|
||||
}
|
||||
}
|
||||
348
greater_test.go
Normal file
348
greater_test.go
Normal file
@@ -0,0 +1,348 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGreaterInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1233")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1235")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3455")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3457")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4566")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4568")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5677")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5679")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159264")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "bar")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "zig")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Bool: false,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterUInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterUInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterFloat32s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterFloat64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "baz")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "zig")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterBools(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:04Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterTimes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-05T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-11T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterDates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-01")
|
||||
require.NoError(t, err)
|
||||
|
||||
d2, err := civil.ParseDate("2006-01-03")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Greater(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Greater(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-04")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
51
greaterequal.go
Normal file
51
greaterequal.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
)
|
||||
|
||||
func GreaterEqual(obj any, path string, matchStr string) (bool, error) {
|
||||
return op(obj, path, matchStr, greaterEqual)
|
||||
}
|
||||
|
||||
func greaterEqual(obj, match any, _ string) bool {
|
||||
switch objt := obj.(type) {
|
||||
case int:
|
||||
return objt >= match.(int)
|
||||
|
||||
case int64:
|
||||
return objt >= match.(int64)
|
||||
|
||||
case uint:
|
||||
return objt >= match.(uint)
|
||||
|
||||
case uint64:
|
||||
return objt >= match.(uint64)
|
||||
|
||||
case float32:
|
||||
return objt >= match.(float32)
|
||||
|
||||
case float64:
|
||||
return objt >= match.(float64)
|
||||
|
||||
case string:
|
||||
return objt >= match.(string)
|
||||
|
||||
case bool:
|
||||
return objt || objt == match.(bool)
|
||||
|
||||
case time.Time:
|
||||
tm := match.(*timeVal)
|
||||
trunc := objt.Truncate(tm.precision)
|
||||
|
||||
return trunc.Equal(tm.time) || trunc.After(tm.time)
|
||||
|
||||
case civil.Date:
|
||||
return objt == match.(civil.Date) || objt.After(match.(civil.Date))
|
||||
|
||||
default:
|
||||
panic(obj)
|
||||
}
|
||||
}
|
||||
468
greaterequal_test.go
Normal file
468
greaterequal_test.go
Normal file
@@ -0,0 +1,468 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGreaterEqualInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1233")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1234")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1235")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3455")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3456")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3457")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4566")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4567")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4568")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5677")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5678")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5679")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1415")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159264")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159265")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "bar")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "foo")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "zig")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Bool: false,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "7")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "7")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualUInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "7")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualUInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "7")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "8")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualFloat32s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "3.1415")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualFloat64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "3.1415")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "baz")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "foo")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "zig")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualBools(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Bools: []bool{false, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:04Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualTimes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-05T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-11T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestGreaterEqualDates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-01")
|
||||
require.NoError(t, err)
|
||||
|
||||
d2, err := civil.ParseDate("2006-01-03")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.GreaterEqual(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.GreaterEqual(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-04")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
54
hasprefix.go
Normal file
54
hasprefix.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
)
|
||||
|
||||
func HasPrefix(obj any, path string, matchStr string) (bool, error) {
|
||||
return op(obj, path, matchStr, hasPrefix)
|
||||
}
|
||||
|
||||
func hasPrefix(obj, match any, matchStr string) bool {
|
||||
var objStr string
|
||||
|
||||
switch objt := obj.(type) {
|
||||
case int:
|
||||
objStr = strconv.FormatInt(int64(objt), 10)
|
||||
|
||||
case int64:
|
||||
objStr = strconv.FormatInt(objt, 10)
|
||||
|
||||
case uint:
|
||||
objStr = strconv.FormatUint(uint64(objt), 10)
|
||||
|
||||
case uint64:
|
||||
objStr = strconv.FormatUint(objt, 10)
|
||||
|
||||
case float32:
|
||||
objStr = strconv.FormatFloat(float64(objt), 'f', -1, 32)
|
||||
|
||||
case float64:
|
||||
objStr = strconv.FormatFloat(objt, 'f', -1, 64)
|
||||
|
||||
case string:
|
||||
objStr = objt
|
||||
|
||||
case bool:
|
||||
objStr = strconv.FormatBool(objt)
|
||||
|
||||
case time.Time:
|
||||
objStr = objt.String()
|
||||
|
||||
case civil.Date:
|
||||
objStr = objt.String()
|
||||
|
||||
default:
|
||||
panic(obj)
|
||||
}
|
||||
|
||||
return strings.HasPrefix(objStr, matchStr)
|
||||
}
|
||||
152
hasprefix_test.go
Normal file
152
hasprefix_test.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHasPrefixInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
Int: -1234,
|
||||
}, "int", "-12")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
Int: -1234,
|
||||
}, "int", "23")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "34")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "45")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "45")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "457")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "567")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "56789")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
Float32: -3.1415,
|
||||
}, "float32", "-3.14")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
Float32: -3.1415,
|
||||
}, "float32", "3.14")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.1415926")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.141592651")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
String: "foobar",
|
||||
}, "string2", "foo")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
String: "foobar",
|
||||
}, "string2", "bar")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "t")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "f")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestHasPrefixStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.HasPrefix(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "f")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.HasPrefix(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
5
in.go
Normal file
5
in.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package path
|
||||
|
||||
func In(obj any, path string, matchStr string) (bool, error) {
|
||||
return opList(obj, path, matchStr, equal)
|
||||
}
|
||||
348
in_test.go
Normal file
348
in_test.go
Normal file
@@ -0,0 +1,348 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1233,1234,1235")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1233,1235")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3455,3456,3457")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3455,3457")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4566,4567,4568")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4566,4568")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5677,5678,5679")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5677,5679")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1414,3.1415,3.1416")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1414,3.1416")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159264,3.14159265,3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159264,3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "zig,foo,bar")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "zig,bar")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "true,false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "false,false")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "3,4,5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "3,5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "3,4,5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "3,5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInUInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "3,4,5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "3,5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInUInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "3,4,5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "3,5")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInFloat32s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7181,2.7182,2.7183")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7181,2.7183")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInFloat64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7181,2.7182,2.7183")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7181,2.7183")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "baz,foo,zig")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "baz,zig")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInBools(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "true,false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Bools: []bool{false, false},
|
||||
}, "bools", "true,true")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:04Z,2006-01-02T15:04:05Z,2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:04Z,2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInTimes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-02T15:04:04Z,2006-01-02T15:04:05Z,2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-02T15:04:04Z,2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01,2006-01-02,2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01,2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestInDates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
d2, err := civil.ParseDate("2006-01-05")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.In(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-01,2006-01-02,2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.In(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-01,2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
18
justfile
Normal file
18
justfile
Normal file
@@ -0,0 +1,18 @@
|
||||
go := env_var_or_default('GOCMD', 'go')
|
||||
|
||||
default: tidy test
|
||||
|
||||
tidy:
|
||||
{{go}} mod tidy
|
||||
goimports -l -w .
|
||||
gofumpt -l -w .
|
||||
{{go}} fmt ./...
|
||||
|
||||
test:
|
||||
{{go}} vet ./...
|
||||
golangci-lint run ./...
|
||||
{{go}} test -race -coverprofile=cover.out -timeout=60s -parallel=10 ./...
|
||||
{{go}} tool cover -html=cover.out -o=cover.html
|
||||
|
||||
todo:
|
||||
-git grep -e TODO --and --not -e ignoretodo
|
||||
50
less.go
Normal file
50
less.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
)
|
||||
|
||||
func Less(obj any, path string, matchStr string) (bool, error) {
|
||||
return op(obj, path, matchStr, less)
|
||||
}
|
||||
|
||||
func less(obj, match any, _ string) bool {
|
||||
switch objt := obj.(type) {
|
||||
case int:
|
||||
return objt < match.(int)
|
||||
|
||||
case int64:
|
||||
return objt < match.(int64)
|
||||
|
||||
case uint:
|
||||
return objt < match.(uint)
|
||||
|
||||
case uint64:
|
||||
return objt < match.(uint64)
|
||||
|
||||
case float32:
|
||||
return objt < match.(float32)
|
||||
|
||||
case float64:
|
||||
return objt < match.(float64)
|
||||
|
||||
case string:
|
||||
return objt < match.(string)
|
||||
|
||||
case bool:
|
||||
return !objt && match.(bool)
|
||||
|
||||
case time.Time:
|
||||
tm := match.(*timeVal)
|
||||
|
||||
return objt.Truncate(tm.precision).Before(tm.time)
|
||||
|
||||
case civil.Date:
|
||||
return objt.Before(match.(civil.Date))
|
||||
|
||||
default:
|
||||
panic(obj)
|
||||
}
|
||||
}
|
||||
348
less_test.go
Normal file
348
less_test.go
Normal file
@@ -0,0 +1,348 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLessInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1235")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1233")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3457")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3455")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4568")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4566")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5679")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5677")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159264")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "zig")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "bar")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Bool: false,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "false")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "3")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "3")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessUInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "3")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessUInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "3")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessFloat32s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessFloat64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "baz")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "adv")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessBools(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "false")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:04Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessTimes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-05T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-01T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessDates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
d2, err := civil.ParseDate("2006-01-04")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.Less(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.Less(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
51
lessequal.go
Normal file
51
lessequal.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
)
|
||||
|
||||
func LessEqual(obj any, path string, matchStr string) (bool, error) {
|
||||
return op(obj, path, matchStr, lessEqual)
|
||||
}
|
||||
|
||||
func lessEqual(obj, match any, _ string) bool {
|
||||
switch objt := obj.(type) {
|
||||
case int:
|
||||
return objt <= match.(int)
|
||||
|
||||
case int64:
|
||||
return objt <= match.(int64)
|
||||
|
||||
case uint:
|
||||
return objt <= match.(uint)
|
||||
|
||||
case uint64:
|
||||
return objt <= match.(uint64)
|
||||
|
||||
case float32:
|
||||
return objt <= match.(float32)
|
||||
|
||||
case float64:
|
||||
return objt <= match.(float64)
|
||||
|
||||
case string:
|
||||
return objt <= match.(string)
|
||||
|
||||
case bool:
|
||||
return !objt || objt == match.(bool)
|
||||
|
||||
case time.Time:
|
||||
tm := match.(*timeVal)
|
||||
trunc := objt.Truncate(tm.precision)
|
||||
|
||||
return trunc.Equal(tm.time) || trunc.Before(tm.time)
|
||||
|
||||
case civil.Date:
|
||||
return objt == match.(civil.Date) || objt.Before(match.(civil.Date))
|
||||
|
||||
default:
|
||||
panic(obj)
|
||||
}
|
||||
}
|
||||
468
lessequal_test.go
Normal file
468
lessequal_test.go
Normal file
@@ -0,0 +1,468 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLessEqualInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1235")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1234")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Int: 1234,
|
||||
}, "int", "1233")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3457")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3456")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Int64: 3456,
|
||||
}, "int64", "3455")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualUInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4568")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4567")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInt: 4567,
|
||||
}, "uint", "4566")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualUInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5679")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5678")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInt64: 5678,
|
||||
}, "uint64", "5677")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1416")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1415")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float32: 3.1415,
|
||||
}, "float32", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159266")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159265")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float64: 3.14159265,
|
||||
}, "float64", "3.14159264")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "zig")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "foo")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
String: "foo",
|
||||
}, "string2", "bar")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Bool: false,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Bool: true,
|
||||
}, "bool2", "false")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "2")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Ints: []int{2, 4, 7},
|
||||
}, "ints", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "2")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Int64s: []int64{2, 4, 7},
|
||||
}, "int64s", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualUInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "2")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInts: []uint{2, 4, 7},
|
||||
}, "uints", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualUInt64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "5")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "2")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
UInt64s: []uint64{2, 4, 7},
|
||||
}, "uint64s", "1")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualFloat32s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7182")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float32s: []float32{3.1415, 2.7182},
|
||||
}, "float32s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualFloat64s(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "3.1414")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7182")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Float64s: []float64{3.1415, 2.7182},
|
||||
}, "float64s", "2.7181")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualStrings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "baz")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "bar")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Strings: []string{"foo", "bar"},
|
||||
}, "strings", "adv")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualBools(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "false")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Bools: []bool{true, false},
|
||||
}, "bools", "true")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Bools: []bool{true, true},
|
||||
}, "bools", "false")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:06Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Time: tm,
|
||||
}, "time", "2006-01-02T15:04:04Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualTimes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tm, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
tm2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-10T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-05T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Times: []time.Time{tm, tm2},
|
||||
}, "times", "2006-01-01T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Date: d,
|
||||
}, "date", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
|
||||
func TestLessEqualDates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
d2, err := civil.ParseDate("2006-01-04")
|
||||
require.NoError(t, err)
|
||||
|
||||
match, err := path.LessEqual(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-03")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-02")
|
||||
require.NoError(t, err)
|
||||
require.True(t, match)
|
||||
|
||||
match, err = path.LessEqual(&testType1{
|
||||
Dates: []civil.Date{d1, d2},
|
||||
}, "dates", "2006-01-01")
|
||||
require.NoError(t, err)
|
||||
require.False(t, match)
|
||||
}
|
||||
88
merge.go
Normal file
88
merge.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func Merge(to, from any) {
|
||||
MergeValue(reflect.ValueOf(to), reflect.ValueOf(from))
|
||||
}
|
||||
|
||||
func MergeValue(to, from reflect.Value) {
|
||||
to = reflect.Indirect(to)
|
||||
from = reflect.Indirect(from)
|
||||
|
||||
for i := 0; i < to.NumField(); i++ {
|
||||
toField := to.Field(i)
|
||||
fromField := from.Field(i)
|
||||
|
||||
if fromField.IsZero() {
|
||||
continue
|
||||
}
|
||||
|
||||
if reflect.Indirect(fromField).Kind() == reflect.Struct {
|
||||
MergeValue(toField, fromField)
|
||||
continue
|
||||
}
|
||||
|
||||
toField.Set(fromField)
|
||||
}
|
||||
}
|
||||
|
||||
func MergeMap(to any, from map[string]any) error {
|
||||
m, err := ToMap(to)
|
||||
if err != nil {
|
||||
// TODO: Wrap error
|
||||
return err
|
||||
}
|
||||
|
||||
MergeMaps(m, from)
|
||||
|
||||
return FromMap(to, m)
|
||||
}
|
||||
|
||||
func MergeMaps(to map[string]any, from map[string]any) {
|
||||
for k, v := range from {
|
||||
if vMap, isMap := v.(map[string]any); isMap {
|
||||
if _, ok := to[k].(map[string]any); !ok {
|
||||
// Either key doesn't exist or it's a different type
|
||||
// If different type, error will happen during json decode
|
||||
to[k] = map[string]any{}
|
||||
}
|
||||
|
||||
MergeMaps(to[k].(map[string]any), vMap)
|
||||
} else {
|
||||
to[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ToMap(from any) (map[string]any, error) {
|
||||
js, err := json.Marshal(from)
|
||||
if err != nil {
|
||||
// TODO: Wrap error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := map[string]any{}
|
||||
|
||||
err = json.Unmarshal(js, &ret)
|
||||
if err != nil {
|
||||
// TODO: Wrap error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func FromMap(to any, from map[string]any) error {
|
||||
js, err := json.Marshal(from)
|
||||
if err != nil {
|
||||
// TODO: Wrap error
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Wrap error
|
||||
return json.Unmarshal(js, to)
|
||||
}
|
||||
137
merge_test.go
Normal file
137
merge_test.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type mergeTestType struct {
|
||||
A string
|
||||
B int
|
||||
C []string
|
||||
D nestedType
|
||||
E *nestedType
|
||||
H int
|
||||
}
|
||||
|
||||
type nestedType struct {
|
||||
F []int
|
||||
G string
|
||||
}
|
||||
|
||||
func TestMergeString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
to := &mergeTestType{
|
||||
A: "foo",
|
||||
B: 42,
|
||||
}
|
||||
|
||||
path.Merge(to, &mergeTestType{
|
||||
A: "bar",
|
||||
})
|
||||
|
||||
require.Equal(t, "bar", to.A)
|
||||
require.Equal(t, 42, to.B)
|
||||
}
|
||||
|
||||
func TestMergeSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
to := &mergeTestType{
|
||||
B: 42,
|
||||
C: []string{"foo", "bar"},
|
||||
}
|
||||
|
||||
path.Merge(to, &mergeTestType{
|
||||
C: []string{"zig", "zag"},
|
||||
})
|
||||
|
||||
require.Equal(t, 42, to.B)
|
||||
require.Equal(t, []string{"zig", "zag"}, to.C)
|
||||
}
|
||||
|
||||
func TestMergeNested(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
to := &mergeTestType{
|
||||
B: 42,
|
||||
D: nestedType{
|
||||
F: []int{42, 43},
|
||||
G: "bar",
|
||||
},
|
||||
}
|
||||
|
||||
path.Merge(to, &mergeTestType{
|
||||
D: nestedType{
|
||||
F: []int{44, 45},
|
||||
},
|
||||
})
|
||||
|
||||
require.Equal(t, 42, to.B)
|
||||
require.Equal(t, []int{44, 45}, to.D.F)
|
||||
require.Equal(t, "bar", to.D.G)
|
||||
}
|
||||
|
||||
func TestMergeNestedPointer(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
to := &mergeTestType{
|
||||
B: 42,
|
||||
E: &nestedType{
|
||||
F: []int{42, 43},
|
||||
G: "bar",
|
||||
},
|
||||
}
|
||||
|
||||
path.Merge(to, &mergeTestType{
|
||||
E: &nestedType{
|
||||
F: []int{49, 50},
|
||||
},
|
||||
})
|
||||
|
||||
require.Equal(t, 42, to.B)
|
||||
require.Equal(t, []int{49, 50}, to.E.F)
|
||||
require.Equal(t, "bar", to.E.G)
|
||||
}
|
||||
|
||||
func TestMergeMap(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
to := &mergeTestType{
|
||||
A: "foo",
|
||||
B: 42,
|
||||
D: nestedType{
|
||||
F: []int{42, 43},
|
||||
G: "bar",
|
||||
},
|
||||
H: 5,
|
||||
}
|
||||
|
||||
from := map[string]any{}
|
||||
|
||||
err := json.Unmarshal(
|
||||
[]byte(`
|
||||
{
|
||||
"B": 45,
|
||||
"D": {
|
||||
"F": [46, 47]
|
||||
},
|
||||
"H": 0
|
||||
}`),
|
||||
&from,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = path.MergeMap(to, from)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "foo", to.A)
|
||||
require.Equal(t, 45, to.B)
|
||||
require.Equal(t, []int{46, 47}, to.D.F)
|
||||
require.Equal(t, "bar", to.D.G)
|
||||
require.Equal(t, 0, to.H)
|
||||
}
|
||||
56
op.go
Normal file
56
op.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func op(obj any, path string, matchStr string, cb func(any, any, string) bool) (bool, error) {
|
||||
objVal, err := Get(obj, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
matchVal, err := parse(matchStr, objVal)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if isSlice(objVal) {
|
||||
return anyTrue(objVal, func(x any, _ int) bool { return cb(x, matchVal, matchStr) }), nil
|
||||
}
|
||||
|
||||
return cb(objVal, matchVal, matchStr), nil
|
||||
}
|
||||
|
||||
func opList(obj any, path string, matchStr string, cb func(any, any, string) bool) (bool, error) {
|
||||
objVal, err := Get(obj, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if objVal == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
matchVal := []any{}
|
||||
matchParts := strings.Split(matchStr, ",")
|
||||
|
||||
for _, matchPart := range matchParts {
|
||||
matchTmp, err := parse(matchPart, objVal)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
matchVal = append(matchVal, matchTmp)
|
||||
}
|
||||
|
||||
return anyTrue(matchVal, func(y any, i int) bool {
|
||||
str := matchParts[i]
|
||||
|
||||
if isSlice(objVal) {
|
||||
return anyTrue(objVal, func(x any, _ int) bool { return cb(x, y, str) })
|
||||
}
|
||||
|
||||
return cb(objVal, y, str)
|
||||
}), nil
|
||||
}
|
||||
153
parse.go
Normal file
153
parse.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/jsrest"
|
||||
)
|
||||
|
||||
type timeVal struct {
|
||||
time time.Time
|
||||
precision time.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
ErrUnsupportedType = errors.New("unsupported type")
|
||||
ErrUnknownTimeFormat = errors.New("unknown time format")
|
||||
)
|
||||
|
||||
func parse(str string, t any) (any, error) {
|
||||
typ := reflect.TypeOf(t)
|
||||
|
||||
if typ.Kind() == reflect.Slice {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
if typ.Kind() == reflect.Pointer {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
// TODO: Consider attempting to convert to string in default case
|
||||
switch typ.Kind() { //nolint:exhaustive
|
||||
case reflect.Int:
|
||||
return parseInt(str)
|
||||
|
||||
case reflect.Int64:
|
||||
return strconv.ParseInt(str, 10, 64)
|
||||
|
||||
case reflect.Uint:
|
||||
return parseUint(str)
|
||||
|
||||
case reflect.Uint64:
|
||||
return strconv.ParseUint(str, 10, 64)
|
||||
|
||||
case reflect.Float32:
|
||||
return parseFloat32(str)
|
||||
|
||||
case reflect.Float64:
|
||||
return strconv.ParseFloat(str, 64)
|
||||
|
||||
case reflect.String:
|
||||
return str, nil
|
||||
|
||||
case reflect.Bool:
|
||||
return strconv.ParseBool(str)
|
||||
|
||||
case reflect.Struct:
|
||||
switch typ {
|
||||
case reflect.TypeOf(time.Time{}):
|
||||
return parseTime(str)
|
||||
|
||||
case reflect.TypeOf(civil.Date{}):
|
||||
return civil.ParseDate(str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, jsrest.Errorf(jsrest.ErrBadRequest, "%T (%w)", t, ErrUnsupportedType)
|
||||
}
|
||||
|
||||
func parseInt(str string) (int, error) {
|
||||
val, err := strconv.ParseInt(str, 10, strconv.IntSize)
|
||||
|
||||
return int(val), err
|
||||
}
|
||||
|
||||
func parseUint(str string) (uint, error) {
|
||||
val, err := strconv.ParseUint(str, 10, strconv.IntSize)
|
||||
|
||||
return uint(val), err
|
||||
}
|
||||
|
||||
func parseFloat32(str string) (float32, error) {
|
||||
val, err := strconv.ParseFloat(str, 32)
|
||||
|
||||
return float32(val), err
|
||||
}
|
||||
|
||||
type timeFormat struct {
|
||||
format string
|
||||
precision time.Duration
|
||||
}
|
||||
|
||||
var timeFormats = []timeFormat{
|
||||
{
|
||||
format: "2006-01-02-07:00",
|
||||
precision: 24 * time.Hour,
|
||||
// TODO: Support field annotation to change start vs end of day
|
||||
// TODO: Support timezone context passed down to allow naked date
|
||||
},
|
||||
{
|
||||
format: "2006-01-02T15:04:05Z",
|
||||
precision: 1 * time.Second,
|
||||
},
|
||||
{
|
||||
format: "2006-01-02T15:04:05-07:00",
|
||||
precision: 1 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
func parseTime(str string) (*timeVal, error) {
|
||||
if strings.ToLower(str) == "now" {
|
||||
return &timeVal{
|
||||
time: time.Now(),
|
||||
precision: 1 * time.Nanosecond,
|
||||
}, nil
|
||||
}
|
||||
|
||||
for _, format := range timeFormats {
|
||||
tm, err := time.Parse(format.format, str)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
return &timeVal{
|
||||
time: tm,
|
||||
precision: format.precision,
|
||||
}, nil
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(str, 10, 64)
|
||||
if err != nil {
|
||||
return nil, jsrest.Errorf(jsrest.ErrBadRequest, "%s (%w)", str, ErrUnknownTimeFormat)
|
||||
}
|
||||
|
||||
// UNIX Seconds: 2969-05-03
|
||||
// UNIX Millis: 1971-01-01
|
||||
// Intended to give us a wide range of useful values in both schemes
|
||||
if i > 31536000000 {
|
||||
return &timeVal{
|
||||
time: time.UnixMilli(i),
|
||||
precision: 1 * time.Millisecond,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &timeVal{
|
||||
time: time.Unix(i, 0),
|
||||
precision: 1 * time.Second,
|
||||
}, nil
|
||||
}
|
||||
42
parse_test.go
Normal file
42
parse_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
//nolint:testpackage
|
||||
package path
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseTimeNow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
now, err := parse("now", time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
end := time.Now()
|
||||
|
||||
require.WithinRange(t, now.(*timeVal).time, start, end)
|
||||
}
|
||||
|
||||
func TestParseTimeDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
parsed, err := parse("2022-11-01-08:00", time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
tv := parsed.(*timeVal)
|
||||
require.Equal(t, tv.precision, 24*time.Hour)
|
||||
}
|
||||
|
||||
func TestParseTimeSecond(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
parsed, err := parse("2022-11-01T05:06:07Z", time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
tv := parsed.(*timeVal)
|
||||
require.Equal(t, tv.precision, 1*time.Second)
|
||||
}
|
||||
259
path.go
Normal file
259
path.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/jsrest"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type WalkCallback func(string, []string, reflect.StructField)
|
||||
|
||||
var (
|
||||
TimeTimeType = reflect.TypeOf(time.Time{})
|
||||
CivilDateType = reflect.TypeOf(civil.Date{})
|
||||
|
||||
ErrNotAStruct = errors.New("not a struct")
|
||||
ErrUnknownFieldName = errors.New("unknown field name")
|
||||
)
|
||||
|
||||
func Get(obj any, path string) (any, error) {
|
||||
v, err := GetValue(reflect.ValueOf(obj), path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return v.Interface(), nil
|
||||
}
|
||||
|
||||
func GetValue(v reflect.Value, path string) (reflect.Value, error) {
|
||||
parts := strings.Split(path, ".")
|
||||
return getRecursive(v, parts, []string{})
|
||||
}
|
||||
|
||||
func getRecursive(v reflect.Value, parts []string, prev []string) (reflect.Value, error) {
|
||||
if v.Kind() == reflect.Pointer {
|
||||
if v.IsNil() {
|
||||
v = reflect.Zero(v.Type().Elem())
|
||||
} else {
|
||||
v = reflect.Indirect(v)
|
||||
}
|
||||
}
|
||||
|
||||
if len(parts) == 0 {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Struct {
|
||||
return reflect.Value{}, jsrest.Errorf(jsrest.ErrBadRequest, "%s (%w)", strings.Join(prev, "."), ErrNotAStruct)
|
||||
}
|
||||
|
||||
part := parts[0]
|
||||
|
||||
sub, found := getField(v, part)
|
||||
if !found {
|
||||
return reflect.Value{}, jsrest.Errorf(jsrest.ErrBadRequest, "%s (%w)", errorPath(prev, part), ErrUnknownFieldName)
|
||||
}
|
||||
|
||||
newPrev := []string{}
|
||||
newPrev = append(newPrev, prev...)
|
||||
newPrev = append(newPrev, part)
|
||||
|
||||
return getRecursive(sub, parts[1:], newPrev)
|
||||
}
|
||||
|
||||
func getField(v reflect.Value, name string) (reflect.Value, bool) {
|
||||
field, found := getStructField(v.Type(), name)
|
||||
if !found {
|
||||
return reflect.Value{}, false
|
||||
}
|
||||
|
||||
return v.FieldByName(field.Name), true
|
||||
}
|
||||
|
||||
func Set(obj any, path string, val string) error {
|
||||
return SetValue(reflect.ValueOf(obj), path, val)
|
||||
}
|
||||
|
||||
func SetValue(v reflect.Value, path string, val string) error {
|
||||
parts := strings.Split(path, ".")
|
||||
return setRecursive(v, parts, []string{}, val)
|
||||
}
|
||||
|
||||
func setRecursive(v reflect.Value, parts []string, prev []string, val string) error {
|
||||
if v.Kind() == reflect.Pointer {
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
|
||||
v = reflect.Indirect(v)
|
||||
}
|
||||
|
||||
if len(parts) == 0 {
|
||||
n, err := parse(val, v.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := n.(*timeVal); ok {
|
||||
n = n.(*timeVal).time
|
||||
}
|
||||
|
||||
v.Set(reflect.ValueOf(n))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Struct {
|
||||
return jsrest.Errorf(jsrest.ErrBadRequest, "%s (%w)", strings.Join(prev, "."), ErrNotAStruct)
|
||||
}
|
||||
|
||||
part := parts[0]
|
||||
|
||||
sub, found := getField(v, part)
|
||||
if !found {
|
||||
return jsrest.Errorf(jsrest.ErrBadRequest, "%s (%w)", errorPath(prev, part), ErrUnknownFieldName)
|
||||
}
|
||||
|
||||
newPrev := []string{}
|
||||
newPrev = append(newPrev, prev...)
|
||||
newPrev = append(newPrev, part)
|
||||
|
||||
return setRecursive(sub, parts[1:], newPrev, val)
|
||||
}
|
||||
|
||||
func List(obj any) []string {
|
||||
return ListType(reflect.TypeOf(obj))
|
||||
}
|
||||
|
||||
func ListType(t reflect.Type) []string {
|
||||
list := []string{}
|
||||
|
||||
WalkType(t, func(path string, _ []string, field reflect.StructField) {
|
||||
t := MaybeIndirectType(field.Type)
|
||||
if t.Kind() == reflect.Struct && t != TimeTimeType && t != CivilDateType {
|
||||
return
|
||||
}
|
||||
|
||||
list = append(list, path)
|
||||
})
|
||||
|
||||
sort.Strings(list)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func GetFieldType(t reflect.Type, path string) reflect.Type {
|
||||
parts := strings.Split(path, ".")
|
||||
|
||||
for _, part := range parts {
|
||||
field, found := getStructField(MaybeIndirectType(t), part)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
t = field.Type
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func FindTagValueType(t reflect.Type, key, value string) (string, bool) {
|
||||
ret := ""
|
||||
|
||||
WalkType(t, func(path string, _ []string, field reflect.StructField) {
|
||||
tag, found := field.Tag.Lookup(key)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.Split(tag, ",")
|
||||
|
||||
if slices.Contains(parts, value) {
|
||||
ret = path
|
||||
}
|
||||
})
|
||||
|
||||
return ret, ret != ""
|
||||
}
|
||||
|
||||
func Walk(obj any, cb WalkCallback) {
|
||||
WalkType(reflect.TypeOf(obj), cb)
|
||||
}
|
||||
|
||||
func WalkType(t reflect.Type, cb WalkCallback) {
|
||||
walkRecursive(MaybeIndirectType(t), cb, []string{})
|
||||
}
|
||||
|
||||
func walkRecursive(t reflect.Type, cb WalkCallback, prev []string) {
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
sub := t.Field(i)
|
||||
|
||||
newPrev := []string{}
|
||||
newPrev = append(newPrev, prev...)
|
||||
|
||||
if !sub.Anonymous {
|
||||
newPrev = append(newPrev, FieldName(sub))
|
||||
}
|
||||
|
||||
t := MaybeIndirectType(sub.Type)
|
||||
|
||||
if len(newPrev) > 0 {
|
||||
cb(strings.Join(newPrev, "."), newPrev, sub)
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Struct && t != TimeTimeType && t != CivilDateType {
|
||||
walkRecursive(t, cb, newPrev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getStructField(t reflect.Type, name string) (reflect.StructField, bool) {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
return t.FieldByNameFunc(func(iterName string) bool {
|
||||
iterField, iterOK := t.FieldByName(iterName)
|
||||
if !iterOK {
|
||||
panic(iterName)
|
||||
}
|
||||
|
||||
return strings.ToLower(FieldName(iterField)) == name
|
||||
})
|
||||
}
|
||||
|
||||
func errorPath(prev []string, part string) string {
|
||||
if len(prev) == 0 {
|
||||
return part
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s.%s", strings.Join(prev, "."), part)
|
||||
}
|
||||
|
||||
func FieldName(field reflect.StructField) string {
|
||||
tag := field.Tag.Get("json")
|
||||
if tag != "" {
|
||||
if tag == "-" {
|
||||
return ""
|
||||
}
|
||||
|
||||
parts := strings.SplitN(tag, ",", 2)
|
||||
|
||||
return parts[0]
|
||||
}
|
||||
|
||||
return field.Name
|
||||
}
|
||||
|
||||
func MaybeIndirectType(t reflect.Type) reflect.Type {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
return t.Elem()
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
141
path_test.go
Normal file
141
path_test.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testType1 struct {
|
||||
Int int
|
||||
Int64 int64
|
||||
UInt uint
|
||||
UInt64 uint64
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
String string `json:"string2,omitempty"`
|
||||
Bool bool `json:"bool2"`
|
||||
BoolP *bool
|
||||
|
||||
Ints []int
|
||||
Int64s []int64
|
||||
UInts []uint
|
||||
UInt64s []uint64
|
||||
Float32s []float32
|
||||
Float64s []float64
|
||||
Strings []string
|
||||
Bools []bool
|
||||
|
||||
Time time.Time
|
||||
Times []time.Time
|
||||
Date civil.Date
|
||||
Dates []civil.Date
|
||||
|
||||
TimeP *time.Time
|
||||
TimesP []*time.Time
|
||||
}
|
||||
|
||||
type testType2 struct {
|
||||
Tt1 testType1
|
||||
Tt1p *testType1
|
||||
}
|
||||
|
||||
type testType3 struct {
|
||||
testType1
|
||||
}
|
||||
|
||||
type testType4 struct {
|
||||
Foo *testType5 `json:"foo"`
|
||||
testType5
|
||||
}
|
||||
|
||||
type testType5 struct {
|
||||
String string `json:"string2,omitempty"`
|
||||
Bool bool `json:"bool2"`
|
||||
UInt uint `xtest:"foo,bar,zig"`
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tt1 := &testType1{}
|
||||
err := path.Set(tt1, "int64", "1234")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1234), tt1.Int64)
|
||||
|
||||
get, err := path.Get(tt1, "int64")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1234), get)
|
||||
|
||||
err = path.Set(tt1, "time", "2022-11-01-08:00")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1667289600), tt1.Time.Unix())
|
||||
|
||||
tt2 := &testType2{}
|
||||
err = path.Set(tt2, "tt1p.bool2", "true")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, tt2.Tt1p.Bool)
|
||||
|
||||
err = path.Set(tt2, "tt1p.string2", "foo")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "foo", tt2.Tt1p.String)
|
||||
|
||||
err = path.Set(tt2, "tt1.boolp", "true")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, *tt2.Tt1.BoolP)
|
||||
}
|
||||
|
||||
func TestEmbed(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tt3 := &testType3{}
|
||||
err := path.Set(tt3, "int", "1234")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1234, tt3.Int)
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
list := path.List(&testType4{})
|
||||
require.Equal(t, []string{
|
||||
"UInt",
|
||||
"bool2",
|
||||
"foo.UInt",
|
||||
"foo.bool2",
|
||||
"foo.string2",
|
||||
"string2",
|
||||
}, list)
|
||||
}
|
||||
|
||||
func TestGetFieldType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
typ := reflect.TypeOf(&testType4{})
|
||||
|
||||
typ2 := path.GetFieldType(typ, "bool2")
|
||||
require.NotNil(t, typ2)
|
||||
require.Equal(t, reflect.TypeOf(true), typ2)
|
||||
|
||||
typ2 = path.GetFieldType(typ, "foo.UInt")
|
||||
require.NotNil(t, typ2)
|
||||
require.Equal(t, reflect.TypeOf(uint(1)), typ2)
|
||||
}
|
||||
|
||||
func TestFindTagValueType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
typ := reflect.TypeOf(&testType4{})
|
||||
|
||||
p, ok := path.FindTagValueType(typ, "xtest", "foo")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "UInt", p)
|
||||
|
||||
p, ok = path.FindTagValueType(typ, "xtest", "zag")
|
||||
require.False(t, ok)
|
||||
require.Empty(t, p)
|
||||
}
|
||||
11
pkg_test.go
Normal file
11
pkg_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.uber.org/goleak"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
goleak.VerifyTestMain(m)
|
||||
}
|
||||
27
slice.go
Normal file
27
slice.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package path
|
||||
|
||||
import "reflect"
|
||||
|
||||
func isSlice(v any) bool {
|
||||
return reflect.TypeOf(v).Kind() == reflect.Slice
|
||||
}
|
||||
|
||||
func anyTrue(v any, cb func(any, int) bool) bool {
|
||||
val := reflect.ValueOf(v)
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
sub := val.Index(i)
|
||||
|
||||
if sub.Kind() == reflect.Pointer && sub.IsNil() {
|
||||
continue
|
||||
}
|
||||
|
||||
sub = reflect.Indirect(sub)
|
||||
|
||||
if cb(sub.Interface(), i) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
110
sort.go
Normal file
110
sort.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/jsrest"
|
||||
)
|
||||
|
||||
func Sort(objs any, path string) error {
|
||||
as := newAnySlice(objs, path)
|
||||
sort.Stable(as)
|
||||
|
||||
return as.err
|
||||
}
|
||||
|
||||
func SortReverse(objs any, path string) error {
|
||||
as := newAnySlice(objs, path)
|
||||
sort.Stable(sort.Reverse(as))
|
||||
|
||||
return as.err
|
||||
}
|
||||
|
||||
type anySlice struct {
|
||||
path string
|
||||
slice reflect.Value
|
||||
swapper func(i, j int)
|
||||
err error
|
||||
}
|
||||
|
||||
var ErrUnsupportedSortType = errors.New("unsupported _sort type")
|
||||
|
||||
func newAnySlice(objs any, path string) *anySlice {
|
||||
return &anySlice{
|
||||
path: path,
|
||||
slice: reflect.ValueOf(objs),
|
||||
swapper: reflect.Swapper(objs),
|
||||
}
|
||||
}
|
||||
|
||||
func (as *anySlice) Len() int {
|
||||
return as.slice.Len()
|
||||
}
|
||||
|
||||
func (as *anySlice) Less(i, j int) bool {
|
||||
v1, err := Get(as.slice.Index(i).Interface(), as.path)
|
||||
if err != nil {
|
||||
as.err = err
|
||||
// We have to obey the Less() contract even in error cases
|
||||
return i < j
|
||||
}
|
||||
|
||||
v2, err := Get(as.slice.Index(j).Interface(), as.path)
|
||||
if err != nil {
|
||||
as.err = err
|
||||
return i < j
|
||||
}
|
||||
|
||||
switch {
|
||||
case v1 == nil && v2 == nil:
|
||||
return false
|
||||
case v1 == nil:
|
||||
return true
|
||||
case v2 == nil:
|
||||
return false
|
||||
}
|
||||
|
||||
switch t1 := v1.(type) {
|
||||
case int:
|
||||
return t1 < v2.(int)
|
||||
|
||||
case int64:
|
||||
return t1 < v2.(int64)
|
||||
|
||||
case uint:
|
||||
return t1 < v2.(uint)
|
||||
|
||||
case uint64:
|
||||
return t1 < v2.(uint64)
|
||||
|
||||
case float32:
|
||||
return t1 < v2.(float32)
|
||||
|
||||
case float64:
|
||||
return t1 < v2.(float64)
|
||||
|
||||
case string:
|
||||
return t1 < v2.(string)
|
||||
|
||||
case bool:
|
||||
return !t1 && v2.(bool)
|
||||
|
||||
case time.Time:
|
||||
return t1.Before(v2.(time.Time))
|
||||
|
||||
case civil.Date:
|
||||
return t1.Before(v2.(civil.Date))
|
||||
|
||||
default:
|
||||
as.err = jsrest.Errorf(jsrest.ErrBadRequest, "%s: %T (%w)", as.path, t1, ErrUnsupportedSortType)
|
||||
return i < j
|
||||
}
|
||||
}
|
||||
|
||||
func (as *anySlice) Swap(i, j int) {
|
||||
as.swapper(i, j)
|
||||
}
|
||||
282
sort_test.go
Normal file
282
sort_test.go
Normal file
@@ -0,0 +1,282 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/civil"
|
||||
"github.com/gopatchy/path"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSortStruct(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType2{
|
||||
{
|
||||
Tt1: testType1{
|
||||
Int: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
Tt1: testType1{
|
||||
Int: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Tt1: testType1{
|
||||
Int: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "tt1.int")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []int{1, 2, 3}, []int{objs[0].Tt1.Int, objs[1].Tt1.Int, objs[2].Tt1.Int})
|
||||
}
|
||||
|
||||
func TestSortReverse(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Int: 3,
|
||||
},
|
||||
{
|
||||
Int: 1,
|
||||
},
|
||||
{
|
||||
Int: 2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.SortReverse(objs, "int")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []int{3, 2, 1}, []int{objs[0].Int, objs[1].Int, objs[2].Int})
|
||||
}
|
||||
|
||||
func TestSortInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Int: 3,
|
||||
},
|
||||
{
|
||||
Int: 1,
|
||||
},
|
||||
{
|
||||
Int: 2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "int")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []int{1, 2, 3}, []int{objs[0].Int, objs[1].Int, objs[2].Int})
|
||||
}
|
||||
|
||||
func TestSortInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Int64: 3,
|
||||
},
|
||||
{
|
||||
Int64: 1,
|
||||
},
|
||||
{
|
||||
Int64: 2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "int64")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []int64{1, 2, 3}, []int64{objs[0].Int64, objs[1].Int64, objs[2].Int64})
|
||||
}
|
||||
|
||||
func TestSortUint(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
UInt: 3,
|
||||
},
|
||||
{
|
||||
UInt: 1,
|
||||
},
|
||||
{
|
||||
UInt: 2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "uint")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []uint{1, 2, 3}, []uint{objs[0].UInt, objs[1].UInt, objs[2].UInt})
|
||||
}
|
||||
|
||||
func TestSortUint64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
UInt64: 3,
|
||||
},
|
||||
{
|
||||
UInt64: 1,
|
||||
},
|
||||
{
|
||||
UInt64: 2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "uint64")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []uint64{1, 2, 3}, []uint64{objs[0].UInt64, objs[1].UInt64, objs[2].UInt64})
|
||||
}
|
||||
|
||||
func TestSortFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Float32: 3.3,
|
||||
},
|
||||
{
|
||||
Float32: 1.1,
|
||||
},
|
||||
{
|
||||
Float32: 2.2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "float32")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []float32{1.1, 2.2, 3.3}, []float32{objs[0].Float32, objs[1].Float32, objs[2].Float32})
|
||||
}
|
||||
|
||||
func TestSortFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Float64: 3.3,
|
||||
},
|
||||
{
|
||||
Float64: 1.1,
|
||||
},
|
||||
{
|
||||
Float64: 2.2,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "float64")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []float64{1.1, 2.2, 3.3}, []float64{objs[0].Float64, objs[1].Float64, objs[2].Float64})
|
||||
}
|
||||
|
||||
func TestSortString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
String: "zig",
|
||||
},
|
||||
{
|
||||
String: "bar",
|
||||
},
|
||||
{
|
||||
String: "foo",
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "string2")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []string{"bar", "foo", "zig"}, []string{objs[0].String, objs[1].String, objs[2].String})
|
||||
}
|
||||
|
||||
func TestSortBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Bool: true,
|
||||
},
|
||||
{
|
||||
Bool: false,
|
||||
},
|
||||
{
|
||||
Bool: true,
|
||||
},
|
||||
}
|
||||
|
||||
err := path.Sort(objs, "bool2")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []bool{false, true, true}, []bool{objs[0].Bool, objs[1].Bool, objs[2].Bool})
|
||||
}
|
||||
|
||||
func TestSortTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t1, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-01T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
t2, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
t3, err := time.Parse("2006-01-02T15:04:05Z", "2006-01-03T15:04:05Z")
|
||||
require.NoError(t, err)
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Time: t3,
|
||||
},
|
||||
{
|
||||
Time: t1,
|
||||
},
|
||||
{
|
||||
Time: t2,
|
||||
},
|
||||
}
|
||||
|
||||
err = path.Sort(objs, "time")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []time.Time{t1, t2, t3}, []time.Time{objs[0].Time, objs[1].Time, objs[2].Time})
|
||||
}
|
||||
|
||||
func TestSortDate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
d1, err := civil.ParseDate("2006-01-01")
|
||||
require.NoError(t, err)
|
||||
d2, err := civil.ParseDate("2006-01-02")
|
||||
require.NoError(t, err)
|
||||
d3, err := civil.ParseDate("2006-01-03")
|
||||
require.NoError(t, err)
|
||||
|
||||
objs := []*testType1{
|
||||
{
|
||||
Date: d3,
|
||||
},
|
||||
{
|
||||
Date: d1,
|
||||
},
|
||||
{
|
||||
Date: d2,
|
||||
},
|
||||
}
|
||||
|
||||
err = path.Sort(objs, "date")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, objs, 3)
|
||||
require.Equal(t, []civil.Date{d1, d2, d3}, []civil.Date{objs[0].Date, objs[1].Date, objs[2].Date})
|
||||
}
|
||||
Reference in New Issue
Block a user