revised matching strategy
diff --git a/jpath/match.go b/jpath/match.go index 6e165c9..cae83f3 100644 --- a/jpath/match.go +++ b/jpath/match.go
@@ -4,38 +4,41 @@ . "github.com/pelletier/go-toml" ) -type PathFn func(context interface{}) []interface{} +type QueryPath []PathFn + +type PathFn func(context interface{}, next QueryPath) + +func (path QueryPath) Fn(context interface{}) { + path[0](context, path[1:]) +} func treeValue(tree *TomlTree, key string) interface{} { return tree.GetPath([]string{key}) } func matchKeyFn(name string) PathFn { - return func(context interface{}) []interface{} { + return func(context interface{}, next QueryPath) { if tree, ok := context.(*TomlTree); ok { item := treeValue(tree, name) if item != nil { - return []interface{}{ item } + next.Fn(item) } } - return []interface{}{} } } func matchIndexFn(idx int) PathFn { - return func(context interface{}) []interface{} { + return func(context interface{}, next QueryPath) { if arr, ok := context.([]interface{}); ok { if idx < len(arr) && idx >= 0 { - return arr[idx:idx+1] + next.Fn(arr[idx]) } } - return []interface{}{} } } func matchSliceFn(start, end, step int) PathFn { - return func(context interface{}) []interface{} { - result := []interface{}{} + return func(context interface{}, next QueryPath) { if arr, ok := context.([]interface{}); ok { // adjust indexes for negative values, reverse ordering realStart, realEnd := start, end @@ -50,46 +53,39 @@ } // loop and gather for idx := realStart; idx < realEnd; idx += step { - result = append(result, arr[idx]) + next.Fn(arr[idx]) } } - return result } } func matchAnyFn() PathFn { - return func(context interface{}) []interface{} { - result := []interface{}{} + return func(context interface{}, next QueryPath) { if tree, ok := context.(*TomlTree); ok { for _, key := range tree.Keys() { item := treeValue(tree, key) - result = append(result, item) + next.Fn(item) } } - return result } } -func matchUnionFn(union []PathFn) PathFn { - return func(context interface{}) []interface{} { - result := []interface{}{} +func matchUnionFn(union QueryPath) PathFn { + return func(context interface{}, next QueryPath) { for _, fn := range union { - result = append(result, fn(context)...) + fn(context, next) } - return result } } func matchRecurseFn() PathFn { - return func(context interface{}) []interface{} { - result := []interface{}{ context } - + return func(context interface{}, next QueryPath) { if tree, ok := context.(*TomlTree); ok { var visit func(tree *TomlTree) visit = func(tree *TomlTree) { for _, key := range tree.Keys() { item := treeValue(tree, key) - result = append(result, item) + next.Fn(item) switch node := item.(type) { case *TomlTree: visit(node) @@ -102,21 +98,18 @@ } visit(tree) } - return result } } -func processPath(path []PathFn, context interface{}) []interface{} { - result := []interface{}{ context } // start with the root - for _, fn := range path { - next := []interface{}{} - for _, ctx := range result { - next = append(next, fn(ctx)...) - } - if len(next) == 0 { - return next // exit if there is nothing more to search - } - result = next // prep the next iteration - } + +func processPath(path QueryPath, context interface{}) []interface{} { + // terminate the path with a collection funciton + result := []interface{}{} + newPath := append(path, func(context interface{}, next QueryPath) { + result = append(result, context) + }) + + // execute the path + newPath.Fn(context) return result }