diff --git a/cover.html b/cover.html
deleted file mode 100644
index dd3bf7e..0000000
--- a/cover.html
+++ /dev/null
@@ -1,1136 +0,0 @@
-
-
-
-
-
-
-
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
- }
-}
-
-
-
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)
- }
-}
-
-
-
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)
- }
-}
-
-
-
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)
-}
-
-
-
package path
-
-func In(obj any, path string, matchStr string) (bool, error) {
- return opList(obj, path, matchStr, equal)
-}
-
-
-
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)
- }
-}
-
-
-
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)
- }
-}
-
-
-
package path
-
-import (
- "encoding/json"
- "reflect"
-
- "github.com/gopatchy/jsrest"
-)
-
-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 {
- return jsrest.Errorf(jsrest.ErrInternalServerError, "converting to map failed (%w)", 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 {
- return nil, jsrest.Errorf(jsrest.ErrInternalServerError, "json marshal failed (%w)", err)
- }
-
- ret := map[string]any{}
-
- err = json.Unmarshal(js, &ret)
- if err != nil {
- return nil, jsrest.Errorf(jsrest.ErrInternalServerError, "json unmarshal failed (%w)", err)
- }
-
- return ret, nil
-}
-
-func FromMap(to any, from map[string]any) error {
- js, err := json.Marshal(from)
- if err != nil {
- return jsrest.Errorf(jsrest.ErrInternalServerError, "json marshal failed (%w)", err)
- }
-
- err = json.Unmarshal(js, to)
- if err != nil {
- return jsrest.Errorf(jsrest.ErrInternalServerError, "json unmarshal failed (%w)", err)
- }
-
- return nil
-}
-
-
-
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
-}
-
-
-
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
-}
-
-
-
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
-}
-
-
-
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
-}
-
-
-
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)
-}
-
-
-
-
-
-
diff --git a/cover.out b/cover.out
deleted file mode 100644
index 6523a5c..0000000
--- a/cover.out
+++ /dev/null
@@ -1,258 +0,0 @@
-mode: atomic
-github.com/gopatchy/path/equal.go:5.65,7.2 1 55
-github.com/gopatchy/path/equal.go:9.43,10.28 1 203
-github.com/gopatchy/path/equal.go:11.17,15.52 2 28
-github.com/gopatchy/path/equal.go:17.10,18.22 1 175
-github.com/gopatchy/path/greater.go:9.67,11.2 1 40
-github.com/gopatchy/path/greater.go:13.45,14.28 1 64
-github.com/gopatchy/path/greater.go:15.11,16.28 1 8
-github.com/gopatchy/path/greater.go:18.13,19.30 1 8
-github.com/gopatchy/path/greater.go:21.12,22.29 1 8
-github.com/gopatchy/path/greater.go:24.14,25.31 1 8
-github.com/gopatchy/path/greater.go:27.15,28.32 1 5
-github.com/gopatchy/path/greater.go:30.15,31.32 1 5
-github.com/gopatchy/path/greater.go:33.14,34.31 1 5
-github.com/gopatchy/path/greater.go:36.12,37.31 1 5
-github.com/gopatchy/path/greater.go:39.17,42.52 2 6
-github.com/gopatchy/path/greater.go:44.18,45.40 1 6
-github.com/gopatchy/path/greater.go:47.10,48.13 1 0
-github.com/gopatchy/path/greaterequal.go:9.72,11.2 1 60
-github.com/gopatchy/path/greaterequal.go:13.50,14.28 1 94
-github.com/gopatchy/path/greaterequal.go:15.11,16.29 1 12
-github.com/gopatchy/path/greaterequal.go:18.13,19.31 1 12
-github.com/gopatchy/path/greaterequal.go:21.12,22.30 1 12
-github.com/gopatchy/path/greaterequal.go:24.14,25.32 1 12
-github.com/gopatchy/path/greaterequal.go:27.15,28.33 1 7
-github.com/gopatchy/path/greaterequal.go:30.15,31.33 1 7
-github.com/gopatchy/path/greaterequal.go:33.14,34.32 1 7
-github.com/gopatchy/path/greaterequal.go:36.12,37.38 1 7
-github.com/gopatchy/path/greaterequal.go:39.17,43.54 3 9
-github.com/gopatchy/path/greaterequal.go:45.18,46.70 1 9
-github.com/gopatchy/path/greaterequal.go:48.10,49.13 1 0
-github.com/gopatchy/path/hasprefix.go:11.69,13.2 1 18
-github.com/gopatchy/path/hasprefix.go:15.54,18.28 2 19
-github.com/gopatchy/path/hasprefix.go:19.11,20.46 1 2
-github.com/gopatchy/path/hasprefix.go:22.13,23.39 1 2
-github.com/gopatchy/path/hasprefix.go:25.12,26.48 1 2
-github.com/gopatchy/path/hasprefix.go:28.14,29.40 1 2
-github.com/gopatchy/path/hasprefix.go:31.15,32.59 1 2
-github.com/gopatchy/path/hasprefix.go:34.15,35.50 1 2
-github.com/gopatchy/path/hasprefix.go:37.14,38.16 1 5
-github.com/gopatchy/path/hasprefix.go:40.12,41.36 1 2
-github.com/gopatchy/path/hasprefix.go:43.17,44.25 1 0
-github.com/gopatchy/path/hasprefix.go:46.18,47.25 1 0
-github.com/gopatchy/path/hasprefix.go:49.10,50.13 1 0
-github.com/gopatchy/path/hasprefix.go:53.2,53.44 1 19
-github.com/gopatchy/path/in.go:3.62,5.2 1 40
-github.com/gopatchy/path/less.go:9.64,11.2 1 40
-github.com/gopatchy/path/less.go:13.42,14.28 1 58
-github.com/gopatchy/path/less.go:15.11,16.28 1 6
-github.com/gopatchy/path/less.go:18.13,19.30 1 6
-github.com/gopatchy/path/less.go:21.12,22.29 1 6
-github.com/gopatchy/path/less.go:24.14,25.31 1 6
-github.com/gopatchy/path/less.go:27.15,28.32 1 6
-github.com/gopatchy/path/less.go:30.15,31.32 1 6
-github.com/gopatchy/path/less.go:33.14,34.31 1 6
-github.com/gopatchy/path/less.go:36.12,37.31 1 6
-github.com/gopatchy/path/less.go:39.17,42.53 2 5
-github.com/gopatchy/path/less.go:44.18,45.41 1 5
-github.com/gopatchy/path/less.go:47.10,48.13 1 0
-github.com/gopatchy/path/lessequal.go:9.69,11.2 1 60
-github.com/gopatchy/path/lessequal.go:13.47,14.28 1 81
-github.com/gopatchy/path/lessequal.go:15.11,16.29 1 8
-github.com/gopatchy/path/lessequal.go:18.13,19.31 1 8
-github.com/gopatchy/path/lessequal.go:21.12,22.30 1 8
-github.com/gopatchy/path/lessequal.go:24.14,25.32 1 8
-github.com/gopatchy/path/lessequal.go:27.15,28.33 1 9
-github.com/gopatchy/path/lessequal.go:30.15,31.33 1 9
-github.com/gopatchy/path/lessequal.go:33.14,34.32 1 9
-github.com/gopatchy/path/lessequal.go:36.12,37.39 1 8
-github.com/gopatchy/path/lessequal.go:39.17,43.55 3 7
-github.com/gopatchy/path/lessequal.go:45.18,46.71 1 7
-github.com/gopatchy/path/lessequal.go:48.10,49.13 1 0
-github.com/gopatchy/path/merge.go:10.26,12.2 1 4
-github.com/gopatchy/path/merge.go:14.41,18.37 3 6
-github.com/gopatchy/path/merge.go:18.37,22.25 3 28
-github.com/gopatchy/path/merge.go:22.25,23.12 1 22
-github.com/gopatchy/path/merge.go:26.3,26.59 1 6
-github.com/gopatchy/path/merge.go:26.59,28.12 2 2
-github.com/gopatchy/path/merge.go:31.3,31.25 1 4
-github.com/gopatchy/path/merge.go:35.50,37.16 2 1
-github.com/gopatchy/path/merge.go:37.16,39.3 1 0
-github.com/gopatchy/path/merge.go:41.2,43.23 2 1
-github.com/gopatchy/path/merge.go:46.56,47.25 1 2
-github.com/gopatchy/path/merge.go:47.25,48.47 1 4
-github.com/gopatchy/path/merge.go:48.47,49.44 1 1
-github.com/gopatchy/path/merge.go:49.44,53.5 1 0
-github.com/gopatchy/path/merge.go:55.4,55.43 1 1
-github.com/gopatchy/path/merge.go:56.9,58.4 1 3
-github.com/gopatchy/path/merge.go:62.46,64.16 2 1
-github.com/gopatchy/path/merge.go:64.16,66.3 1 0
-github.com/gopatchy/path/merge.go:68.2,71.16 3 1
-github.com/gopatchy/path/merge.go:71.16,73.3 1 0
-github.com/gopatchy/path/merge.go:75.2,75.17 1 1
-github.com/gopatchy/path/merge.go:78.49,80.16 2 1
-github.com/gopatchy/path/merge.go:80.16,82.3 1 0
-github.com/gopatchy/path/merge.go:84.2,85.16 2 1
-github.com/gopatchy/path/merge.go:85.16,87.3 1 0
-github.com/gopatchy/path/merge.go:89.2,89.12 1 1
-github.com/gopatchy/path/op.go:7.94,9.16 2 273
-github.com/gopatchy/path/op.go:9.16,11.3 1 0
-github.com/gopatchy/path/op.go:13.2,14.16 2 273
-github.com/gopatchy/path/op.go:14.16,16.3 1 0
-github.com/gopatchy/path/op.go:18.2,18.21 1 273
-github.com/gopatchy/path/op.go:18.21,19.50 1 124
-github.com/gopatchy/path/op.go:19.50,19.86 1 245
-github.com/gopatchy/path/op.go:22.2,22.44 1 149
-github.com/gopatchy/path/op.go:25.98,27.16 2 40
-github.com/gopatchy/path/op.go:27.16,29.3 1 0
-github.com/gopatchy/path/op.go:31.2,31.19 1 40
-github.com/gopatchy/path/op.go:31.19,33.3 1 0
-github.com/gopatchy/path/op.go:35.2,38.39 3 40
-github.com/gopatchy/path/op.go:38.39,40.17 2 98
-github.com/gopatchy/path/op.go:40.17,42.4 1 0
-github.com/gopatchy/path/op.go:44.3,44.40 1 98
-github.com/gopatchy/path/op.go:47.2,47.51 1 40
-github.com/gopatchy/path/op.go:47.51,50.22 2 78
-github.com/gopatchy/path/op.go:50.22,51.51 1 39
-github.com/gopatchy/path/op.go:51.51,51.75 1 86
-github.com/gopatchy/path/op.go:54.3,54.28 1 39
-github.com/gopatchy/path/parse.go:24.44,27.33 2 380
-github.com/gopatchy/path/parse.go:27.33,29.3 1 173
-github.com/gopatchy/path/parse.go:31.2,31.35 1 380
-github.com/gopatchy/path/parse.go:31.35,33.3 1 2
-github.com/gopatchy/path/parse.go:36.2,36.20 1 380
-github.com/gopatchy/path/parse.go:37.19,38.23 1 40
-github.com/gopatchy/path/parse.go:40.21,41.39 1 37
-github.com/gopatchy/path/parse.go:43.20,44.24 1 36
-github.com/gopatchy/path/parse.go:46.22,47.40 1 36
-github.com/gopatchy/path/parse.go:49.23,50.27 1 36
-github.com/gopatchy/path/parse.go:52.23,53.37 1 36
-github.com/gopatchy/path/parse.go:55.22,56.18 1 39
-github.com/gopatchy/path/parse.go:58.20,59.32 1 38
-github.com/gopatchy/path/parse.go:61.22,62.14 1 82
-github.com/gopatchy/path/parse.go:63.36,64.25 1 48
-github.com/gopatchy/path/parse.go:66.37,67.31 1 34
-github.com/gopatchy/path/parse.go:71.2,71.83 1 0
-github.com/gopatchy/path/parse.go:74.40,78.2 2 40
-github.com/gopatchy/path/parse.go:80.42,84.2 2 36
-github.com/gopatchy/path/parse.go:86.48,90.2 2 36
-github.com/gopatchy/path/parse.go:114.46,115.35 1 48
-github.com/gopatchy/path/parse.go:115.35,120.3 1 1
-github.com/gopatchy/path/parse.go:122.2,122.37 1 47
-github.com/gopatchy/path/parse.go:122.37,124.17 2 103
-github.com/gopatchy/path/parse.go:124.17,125.12 1 63
-github.com/gopatchy/path/parse.go:128.3,131.9 1 40
-github.com/gopatchy/path/parse.go:134.2,135.16 2 7
-github.com/gopatchy/path/parse.go:135.16,137.3 1 0
-github.com/gopatchy/path/parse.go:142.2,142.21 1 7
-github.com/gopatchy/path/parse.go:142.21,147.3 1 4
-github.com/gopatchy/path/parse.go:149.2,152.8 1 3
-github.com/gopatchy/path/path.go:26.45,28.16 2 382
-github.com/gopatchy/path/path.go:28.16,30.3 1 0
-github.com/gopatchy/path/path.go:32.2,32.27 1 382
-github.com/gopatchy/path/path.go:35.68,38.2 2 382
-github.com/gopatchy/path/path.go:40.90,41.33 1 771
-github.com/gopatchy/path/path.go:41.33,42.16 1 388
-github.com/gopatchy/path/path.go:42.16,44.4 1 2
-github.com/gopatchy/path/path.go:44.9,46.4 1 386
-github.com/gopatchy/path/path.go:49.2,49.21 1 771
-github.com/gopatchy/path/path.go:49.21,51.3 1 382
-github.com/gopatchy/path/path.go:53.2,53.32 1 389
-github.com/gopatchy/path/path.go:53.32,55.3 1 0
-github.com/gopatchy/path/path.go:57.2,60.12 3 389
-github.com/gopatchy/path/path.go:60.12,62.3 1 0
-github.com/gopatchy/path/path.go:64.2,68.46 4 389
-github.com/gopatchy/path/path.go:71.67,73.12 2 398
-github.com/gopatchy/path/path.go:73.12,75.3 1 0
-github.com/gopatchy/path/path.go:77.2,77.40 1 398
-github.com/gopatchy/path/path.go:80.50,82.2 1 6
-github.com/gopatchy/path/path.go:84.63,87.2 2 6
-github.com/gopatchy/path/path.go:89.85,90.33 1 15
-github.com/gopatchy/path/path.go:90.33,91.16 1 9
-github.com/gopatchy/path/path.go:91.16,93.4 1 2
-github.com/gopatchy/path/path.go:95.3,95.26 1 9
-github.com/gopatchy/path/path.go:98.2,98.21 1 15
-github.com/gopatchy/path/path.go:98.21,100.17 2 6
-github.com/gopatchy/path/path.go:100.17,102.4 1 0
-github.com/gopatchy/path/path.go:104.3,104.32 1 6
-github.com/gopatchy/path/path.go:104.32,106.4 1 1
-github.com/gopatchy/path/path.go:108.3,110.13 2 6
-github.com/gopatchy/path/path.go:113.2,113.32 1 9
-github.com/gopatchy/path/path.go:113.32,115.3 1 0
-github.com/gopatchy/path/path.go:117.2,120.12 3 9
-github.com/gopatchy/path/path.go:120.12,122.3 1 0
-github.com/gopatchy/path/path.go:124.2,128.51 4 9
-github.com/gopatchy/path/path.go:131.29,133.2 1 1
-github.com/gopatchy/path/path.go:135.40,138.71 2 1
-github.com/gopatchy/path/path.go:138.71,140.76 2 7
-github.com/gopatchy/path/path.go:140.76,142.4 1 1
-github.com/gopatchy/path/path.go:144.3,144.28 1 6
-github.com/gopatchy/path/path.go:147.2,149.13 2 1
-github.com/gopatchy/path/path.go:152.61,155.29 2 2
-github.com/gopatchy/path/path.go:155.29,157.13 2 3
-github.com/gopatchy/path/path.go:157.13,159.4 1 0
-github.com/gopatchy/path/path.go:161.3,161.17 1 3
-github.com/gopatchy/path/path.go:164.2,164.10 1 2
-github.com/gopatchy/path/path.go:167.73,170.71 2 2
-github.com/gopatchy/path/path.go:170.71,172.13 2 14
-github.com/gopatchy/path/path.go:172.13,174.4 1 10
-github.com/gopatchy/path/path.go:176.3,178.36 2 4
-github.com/gopatchy/path/path.go:178.36,180.4 1 2
-github.com/gopatchy/path/path.go:183.2,183.23 1 2
-github.com/gopatchy/path/path.go:186.37,188.2 1 0
-github.com/gopatchy/path/path.go:190.48,192.2 1 3
-github.com/gopatchy/path/path.go:194.68,195.36 1 9
-github.com/gopatchy/path/path.go:195.36,201.21 4 24
-github.com/gopatchy/path/path.go:201.21,203.4 1 21
-github.com/gopatchy/path/path.go:205.3,207.23 2 24
-github.com/gopatchy/path/path.go:207.23,209.4 1 21
-github.com/gopatchy/path/path.go:211.3,211.76 1 24
-github.com/gopatchy/path/path.go:211.76,213.4 1 6
-github.com/gopatchy/path/path.go:217.78,220.54 2 401
-github.com/gopatchy/path/path.go:220.54,222.14 2 8955
-github.com/gopatchy/path/path.go:222.14,223.19 1 0
-github.com/gopatchy/path/path.go:226.3,226.55 1 8955
-github.com/gopatchy/path/path.go:230.51,231.20 1 0
-github.com/gopatchy/path/path.go:231.20,233.3 1 0
-github.com/gopatchy/path/path.go:235.2,235.60 1 0
-github.com/gopatchy/path/path.go:238.50,240.15 2 8976
-github.com/gopatchy/path/path.go:240.15,241.17 1 797
-github.com/gopatchy/path/path.go:241.17,243.4 1 0
-github.com/gopatchy/path/path.go:245.3,247.18 2 797
-github.com/gopatchy/path/path.go:250.2,250.19 1 8179
-github.com/gopatchy/path/path.go:253.53,254.33 1 37
-github.com/gopatchy/path/path.go:254.33,256.3 1 10
-github.com/gopatchy/path/path.go:258.2,258.10 1 27
-github.com/gopatchy/path/slice.go:5.26,7.2 1 351
-github.com/gopatchy/path/slice.go:9.50,12.33 2 203
-github.com/gopatchy/path/slice.go:12.33,15.51 2 410
-github.com/gopatchy/path/slice.go:15.51,16.12 1 1
-github.com/gopatchy/path/slice.go:19.3,21.29 2 409
-github.com/gopatchy/path/slice.go:21.29,23.4 1 102
-github.com/gopatchy/path/slice.go:26.2,26.14 1 101
-github.com/gopatchy/path/sort.go:13.40,18.2 3 11
-github.com/gopatchy/path/sort.go:20.47,25.2 3 1
-github.com/gopatchy/path/sort.go:36.51,42.2 1 12
-github.com/gopatchy/path/sort.go:44.31,46.2 1 12
-github.com/gopatchy/path/sort.go:48.41,50.16 2 34
-github.com/gopatchy/path/sort.go:50.16,54.3 2 0
-github.com/gopatchy/path/sort.go:56.2,57.16 2 34
-github.com/gopatchy/path/sort.go:57.16,60.3 2 0
-github.com/gopatchy/path/sort.go:62.2,62.9 1 34
-github.com/gopatchy/path/sort.go:63.30,64.15 1 0
-github.com/gopatchy/path/sort.go:65.17,66.14 1 0
-github.com/gopatchy/path/sort.go:67.17,68.15 1 0
-github.com/gopatchy/path/sort.go:71.2,71.25 1 34
-github.com/gopatchy/path/sort.go:72.11,73.23 1 8
-github.com/gopatchy/path/sort.go:75.13,76.25 1 3
-github.com/gopatchy/path/sort.go:78.12,79.24 1 3
-github.com/gopatchy/path/sort.go:81.14,82.26 1 3
-github.com/gopatchy/path/sort.go:84.15,85.27 1 3
-github.com/gopatchy/path/sort.go:87.15,88.27 1 3
-github.com/gopatchy/path/sort.go:90.14,91.26 1 3
-github.com/gopatchy/path/sort.go:93.12,94.26 1 2
-github.com/gopatchy/path/sort.go:96.17,97.35 1 3
-github.com/gopatchy/path/sort.go:99.18,100.36 1 3
-github.com/gopatchy/path/sort.go:102.10,104.15 2 0
-github.com/gopatchy/path/sort.go:108.36,110.2 1 21
diff --git a/go.mod b/go.mod
index acb1ccf..13e4fb1 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.19
require (
cloud.google.com/go v0.110.2
- github.com/gopatchy/jsrest v0.0.0-20230516044821-deb630cd744b
+ github.com/gopatchy/jsrest v0.0.0-20230516044950-1c6d15dad16a
github.com/stretchr/testify v1.8.2
go.uber.org/goleak v1.2.1
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea
@@ -13,7 +13,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
- github.com/gopatchy/metadata v0.0.0-20230516041300-fc49e5f775fe // indirect
+ github.com/gopatchy/metadata v0.0.0-20230516044939-eed23a0903d5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/vfaronov/httpheader v0.1.0 // indirect
golang.org/x/net v0.10.0 // indirect
diff --git a/go.sum b/go.sum
index d44b86c..5da4c5d 100644
--- a/go.sum
+++ b/go.sum
@@ -10,10 +10,14 @@ github.com/gopatchy/jsrest v0.0.0-20230511133808-abcf8276d1ad h1:UKIRgnQNkQ7qkMD
github.com/gopatchy/jsrest v0.0.0-20230511133808-abcf8276d1ad/go.mod h1:77Kp7hFjygVlnDH48qO917da0gyKNR2XG8mZtaAEL9w=
github.com/gopatchy/jsrest v0.0.0-20230516044821-deb630cd744b h1:fnoLhs0kk7rc/hdk1vn8lzJ9uiq1ANr3klSUwbze1ys=
github.com/gopatchy/jsrest v0.0.0-20230516044821-deb630cd744b/go.mod h1:MQBtK0M/Uota4CpW5NbsjDqWuoQyYjS70PJSxWf3nLE=
+github.com/gopatchy/jsrest v0.0.0-20230516044950-1c6d15dad16a h1:ehV4YITvldTIuTMAq7kk0RcrBE7m3WQKFzFl/jOqh7w=
+github.com/gopatchy/jsrest v0.0.0-20230516044950-1c6d15dad16a/go.mod h1:TVfwj+gk7iCGJRrVYR+0ovXhOc90UXPrBCOGPLE8Fsw=
github.com/gopatchy/metadata v0.0.0-20230424223338-33e58fee42bf h1:HKCbhVEpC3++ydeapSJN2DGs9KGWMvOLpcZrwKkrXQs=
github.com/gopatchy/metadata v0.0.0-20230424223338-33e58fee42bf/go.mod h1:VgD33raUShjDePCDBo55aj+eSXFtUEpMzs+Ie39g2zo=
github.com/gopatchy/metadata v0.0.0-20230516041300-fc49e5f775fe h1:xPnlis/qCAYoxHx9tow1P4pO17c8JH/Hs/lHDmZej/Q=
github.com/gopatchy/metadata v0.0.0-20230516041300-fc49e5f775fe/go.mod h1:VgD33raUShjDePCDBo55aj+eSXFtUEpMzs+Ie39g2zo=
+github.com/gopatchy/metadata v0.0.0-20230516044939-eed23a0903d5 h1:b66b4DOGTqDuw4hbxHSp0WbhXr/xAMaiFkU6iCi4nDg=
+github.com/gopatchy/metadata v0.0.0-20230516044939-eed23a0903d5/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=