Module split

This commit is contained in:
Ian Gulliver
2023-04-20 18:01:36 +00:00
parent e0c92c24fb
commit f50e6e228c
30 changed files with 4293 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
cover.out
cover.html

38
.golangci.yaml Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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})
}