gofmt pass
diff --git a/jpath/lexer.go b/jpath/lexer.go index 2d30bb5..0e3af11 100644 --- a/jpath/lexer.go +++ b/jpath/lexer.go
@@ -80,11 +80,11 @@ } func (t token) Int() int { - if result, err := strconv.Atoi(t.val); err != nil { - panic(err) - } else { - return result - } + if result, err := strconv.Atoi(t.val); err != nil { + panic(err) + } else { + return result + } } func (t token) String() string { @@ -291,10 +291,10 @@ return lexString } - if isSpace(next) { + if isSpace(next) { l.next() - l.ignore() - continue + l.ignore() + continue } if isAlphanumeric(next) {
diff --git a/jpath/lexer_test.go b/jpath/lexer_test.go index c553e2a..4402abb 100644 --- a/jpath/lexer_test.go +++ b/jpath/lexer_test.go
@@ -97,4 +97,3 @@ token{Position{1, 12}, tokenEOF, ""}, }) } -
diff --git a/jpath/match.go b/jpath/match.go index 345bbf4..c517157 100644 --- a/jpath/match.go +++ b/jpath/match.go
@@ -1,35 +1,34 @@ package jpath import ( + "fmt" . "github.com/pelletier/go-toml" - "fmt" ) - // base match type matchBase struct { - next PathFn + next PathFn } func (f *matchBase) SetNext(next PathFn) { - f.next = next + f.next = next } // terminating functor - gathers results type terminatingFn struct { - // empty + // empty } func newTerminatingFn() *terminatingFn { - return &terminatingFn{} + return &terminatingFn{} } func (f *terminatingFn) SetNext(next PathFn) { - // do nothing + // do nothing } func (f *terminatingFn) Call(node interface{}, ctx *queryContext) { - ctx.appendResult(node) + ctx.appendResult(node) } // shim to ease functor writing @@ -39,196 +38,196 @@ // match single key type matchKeyFn struct { - matchBase - Name string + matchBase + Name string } func newMatchKeyFn(name string) *matchKeyFn { - return &matchKeyFn{ Name: name } + return &matchKeyFn{Name: name} } func (f *matchKeyFn) Call(node interface{}, ctx *queryContext) { - if tree, ok := node.(*TomlTree); ok { - item := treeValue(tree, f.Name) - if item != nil { - f.next.Call(item, ctx) - } - } + if tree, ok := node.(*TomlTree); ok { + item := treeValue(tree, f.Name) + if item != nil { + f.next.Call(item, ctx) + } + } } // match single index type matchIndexFn struct { - matchBase - Idx int + matchBase + Idx int } func newMatchIndexFn(idx int) *matchIndexFn { - return &matchIndexFn{ Idx: idx } + return &matchIndexFn{Idx: idx} } func (f *matchIndexFn) Call(node interface{}, ctx *queryContext) { - if arr, ok := node.([]interface{}); ok { - if f.Idx < len(arr) && f.Idx >= 0 { - f.next.Call(arr[f.Idx], ctx) - } - } + if arr, ok := node.([]interface{}); ok { + if f.Idx < len(arr) && f.Idx >= 0 { + f.next.Call(arr[f.Idx], ctx) + } + } } // filter by slicing type matchSliceFn struct { - matchBase - Start, End, Step int + matchBase + Start, End, Step int } func newMatchSliceFn(start, end, step int) *matchSliceFn { - return &matchSliceFn{ Start: start, End: end, Step: step } + return &matchSliceFn{Start: start, End: end, Step: step} } func (f *matchSliceFn) Call(node interface{}, ctx *queryContext) { - if arr, ok := node.([]interface{}); ok { - // adjust indexes for negative values, reverse ordering - realStart, realEnd := f.Start, f.End - if realStart < 0 { - realStart = len(arr) + realStart - } - if realEnd < 0 { - realEnd = len(arr) + realEnd - } - if realEnd < realStart { - realEnd, realStart = realStart, realEnd // swap - } - // loop and gather - for idx := realStart; idx < realEnd; idx += f.Step { - f.next.Call(arr[idx], ctx) - } - } + if arr, ok := node.([]interface{}); ok { + // adjust indexes for negative values, reverse ordering + realStart, realEnd := f.Start, f.End + if realStart < 0 { + realStart = len(arr) + realStart + } + if realEnd < 0 { + realEnd = len(arr) + realEnd + } + if realEnd < realStart { + realEnd, realStart = realStart, realEnd // swap + } + // loop and gather + for idx := realStart; idx < realEnd; idx += f.Step { + f.next.Call(arr[idx], ctx) + } + } } // match anything type matchAnyFn struct { - matchBase + matchBase } func newMatchAnyFn() *matchAnyFn { - return &matchAnyFn{} + return &matchAnyFn{} } func (f *matchAnyFn) Call(node interface{}, ctx *queryContext) { - if tree, ok := node.(*TomlTree); ok { - for _, key := range tree.Keys() { - item := treeValue(tree, key) - f.next.Call(item, ctx) - } - } + if tree, ok := node.(*TomlTree); ok { + for _, key := range tree.Keys() { + item := treeValue(tree, key) + f.next.Call(item, ctx) + } + } } // filter through union type matchUnionFn struct { - Union []PathFn + Union []PathFn } func (f *matchUnionFn) SetNext(next PathFn) { - for _, fn := range f.Union { - fn.SetNext(next) - } + for _, fn := range f.Union { + fn.SetNext(next) + } } func (f *matchUnionFn) Call(node interface{}, ctx *queryContext) { - for _, fn := range f.Union { - fn.Call(node, ctx) - } + for _, fn := range f.Union { + fn.Call(node, ctx) + } } // match every single last node in the tree type matchRecursiveFn struct { - matchBase + matchBase } -func newMatchRecursiveFn() *matchRecursiveFn{ - return &matchRecursiveFn{} +func newMatchRecursiveFn() *matchRecursiveFn { + return &matchRecursiveFn{} } func (f *matchRecursiveFn) Call(node interface{}, ctx *queryContext) { - if tree, ok := node.(*TomlTree); ok { - var visit func(tree *TomlTree) - visit = func(tree *TomlTree) { - for _, key := range tree.Keys() { - item := treeValue(tree, key) - f.next.Call(item, ctx) - switch node := item.(type) { - case *TomlTree: - visit(node) - case []*TomlTree: - for _, subtree := range node { - visit(subtree) - } - } - } - } - visit(tree) - } + if tree, ok := node.(*TomlTree); ok { + var visit func(tree *TomlTree) + visit = func(tree *TomlTree) { + for _, key := range tree.Keys() { + item := treeValue(tree, key) + f.next.Call(item, ctx) + switch node := item.(type) { + case *TomlTree: + visit(node) + case []*TomlTree: + for _, subtree := range node { + visit(subtree) + } + } + } + } + visit(tree) + } } // match based on an externally provided functional filter type matchFilterFn struct { - matchBase - Pos Position - Name string + matchBase + Pos Position + Name string } func newMatchFilterFn(name string, pos Position) *matchFilterFn { - return &matchFilterFn{ Name: name, Pos: pos } + return &matchFilterFn{Name: name, Pos: pos} } func (f *matchFilterFn) Call(node interface{}, ctx *queryContext) { - fn, ok := (*ctx.filters)[f.Name] - if !ok { - panic(fmt.Sprintf("%s: query context does not have filter '%s'", - f.Pos, f.Name)) - } - switch castNode := node.(type) { - case *TomlTree: - for _, k := range castNode.Keys() { - v := castNode.GetPath([]string{k}) - if fn(v) { - f.next.Call(v, ctx) - } - } - case []interface{}: - for _, v := range castNode { - if fn(v) { - f.next.Call(v, ctx) - } - } - } + fn, ok := (*ctx.filters)[f.Name] + if !ok { + panic(fmt.Sprintf("%s: query context does not have filter '%s'", + f.Pos, f.Name)) + } + switch castNode := node.(type) { + case *TomlTree: + for _, k := range castNode.Keys() { + v := castNode.GetPath([]string{k}) + if fn(v) { + f.next.Call(v, ctx) + } + } + case []interface{}: + for _, v := range castNode { + if fn(v) { + f.next.Call(v, ctx) + } + } + } } // match based using result of an externally provided functional filter type matchScriptFn struct { - matchBase - Pos Position - Name string + matchBase + Pos Position + Name string } func newMatchScriptFn(name string, pos Position) *matchScriptFn { - return &matchScriptFn{ Name: name, Pos: pos } + return &matchScriptFn{Name: name, Pos: pos} } func (f *matchScriptFn) Call(node interface{}, ctx *queryContext) { - fn, ok := (*ctx.scripts)[f.Name] - if !ok { - panic(fmt.Sprintf("%s: query context does not have script '%s'", - f.Pos, f.Name)) - } - switch result := fn(node).(type) { - case string: - nextMatch := newMatchKeyFn(result) - nextMatch.SetNext(f.next) - nextMatch.Call(node, ctx) - case int: - nextMatch := newMatchIndexFn(result) - nextMatch.SetNext(f.next) - nextMatch.Call(node, ctx) - //TODO: support other return types? - } + fn, ok := (*ctx.scripts)[f.Name] + if !ok { + panic(fmt.Sprintf("%s: query context does not have script '%s'", + f.Pos, f.Name)) + } + switch result := fn(node).(type) { + case string: + nextMatch := newMatchKeyFn(result) + nextMatch.SetNext(f.next) + nextMatch.Call(node, ctx) + case int: + nextMatch := newMatchIndexFn(result) + nextMatch.SetNext(f.next) + nextMatch.Call(node, ctx) + //TODO: support other return types? + } }
diff --git a/jpath/match_test.go b/jpath/match_test.go index 9509ae9..d7da647 100644 --- a/jpath/match_test.go +++ b/jpath/match_test.go
@@ -1,218 +1,218 @@ package jpath import ( + "fmt" . "github.com/pelletier/go-toml" - "fmt" - "math" + "math" "testing" ) // dump path tree to a string func pathString(root PathFn) string { - result := fmt.Sprintf("%T:", root) - switch fn := root.(type) { - case *terminatingFn: - result += "{}" - case *matchKeyFn: - result += fmt.Sprintf("{%s}", fn.Name) - result += pathString(fn.next) - case *matchIndexFn: - result += fmt.Sprintf("{%d}", fn.Idx) - result += pathString(fn.next) - case *matchSliceFn: - result += fmt.Sprintf("{%d:%d:%d}", - fn.Start, fn.End, fn.Step) - result += pathString(fn.next) - case *matchAnyFn: - result += "{}" - result += pathString(fn.next) - case *matchUnionFn: - result += "{[" - for _, v := range fn.Union { - result += pathString(v) + ", " - } - result += "]}" - case *matchRecursiveFn: - result += "{}" - result += pathString(fn.next) - case *matchFilterFn: - result += fmt.Sprintf("{%s}", fn.Name) - result += pathString(fn.next) - case *matchScriptFn: - result += fmt.Sprintf("{%s}", fn.Name) - result += pathString(fn.next) - } - return result + result := fmt.Sprintf("%T:", root) + switch fn := root.(type) { + case *terminatingFn: + result += "{}" + case *matchKeyFn: + result += fmt.Sprintf("{%s}", fn.Name) + result += pathString(fn.next) + case *matchIndexFn: + result += fmt.Sprintf("{%d}", fn.Idx) + result += pathString(fn.next) + case *matchSliceFn: + result += fmt.Sprintf("{%d:%d:%d}", + fn.Start, fn.End, fn.Step) + result += pathString(fn.next) + case *matchAnyFn: + result += "{}" + result += pathString(fn.next) + case *matchUnionFn: + result += "{[" + for _, v := range fn.Union { + result += pathString(v) + ", " + } + result += "]}" + case *matchRecursiveFn: + result += "{}" + result += pathString(fn.next) + case *matchFilterFn: + result += fmt.Sprintf("{%s}", fn.Name) + result += pathString(fn.next) + case *matchScriptFn: + result += fmt.Sprintf("{%s}", fn.Name) + result += pathString(fn.next) + } + return result } func assertPathMatch(t *testing.T, path, ref *Query) bool { - pathStr := pathString(path.root) - refStr := pathString(ref.root) - if pathStr != refStr { - t.Errorf("paths do not match") - t.Log("test:", pathStr) - t.Log("ref: ", refStr) - return false - } - return true + pathStr := pathString(path.root) + refStr := pathString(ref.root) + if pathStr != refStr { + t.Errorf("paths do not match") + t.Log("test:", pathStr) + t.Log("ref: ", refStr) + return false + } + return true } func assertPath(t *testing.T, query string, ref *Query) { _, flow := lex(query) path := parse(flow) - assertPathMatch(t, path, ref) + assertPathMatch(t, path, ref) } -func buildPath(parts... PathFn) *Query { - query := newQuery() - for _, v := range parts { - query.appendPath(v) - } - return query +func buildPath(parts ...PathFn) *Query { + query := newQuery() + for _, v := range parts { + query.appendPath(v) + } + return query } func TestPathRoot(t *testing.T) { assertPath(t, "$", buildPath( - // empty - )) + // empty + )) } func TestPathKey(t *testing.T) { assertPath(t, "$.foo", buildPath( - newMatchKeyFn("foo"), - )) + newMatchKeyFn("foo"), + )) } func TestPathBracketKey(t *testing.T) { assertPath(t, "$[foo]", buildPath( - newMatchKeyFn("foo"), - )) + newMatchKeyFn("foo"), + )) } func TestPathBracketStringKey(t *testing.T) { assertPath(t, "$['foo']", buildPath( - newMatchKeyFn("foo"), - )) + newMatchKeyFn("foo"), + )) } func TestPathIndex(t *testing.T) { assertPath(t, "$[123]", buildPath( - newMatchIndexFn(123), - )) + newMatchIndexFn(123), + )) } func TestPathSliceStart(t *testing.T) { assertPath(t, "$[123:]", buildPath( - newMatchSliceFn(123, math.MaxInt64, 1), - )) + newMatchSliceFn(123, math.MaxInt64, 1), + )) } func TestPathSliceStartEnd(t *testing.T) { assertPath(t, "$[123:456]", buildPath( - newMatchSliceFn(123, 456, 1), - )) + newMatchSliceFn(123, 456, 1), + )) } func TestPathSliceStartEndColon(t *testing.T) { assertPath(t, "$[123:456:]", buildPath( - newMatchSliceFn(123, 456, 1), - )) + newMatchSliceFn(123, 456, 1), + )) } func TestPathSliceStartStep(t *testing.T) { assertPath(t, "$[123::7]", buildPath( - newMatchSliceFn(123, math.MaxInt64, 7), - )) + newMatchSliceFn(123, math.MaxInt64, 7), + )) } func TestPathSliceEndStep(t *testing.T) { assertPath(t, "$[:456:7]", buildPath( - newMatchSliceFn(0, 456, 7), - )) + newMatchSliceFn(0, 456, 7), + )) } func TestPathSliceStep(t *testing.T) { assertPath(t, "$[::7]", buildPath( - newMatchSliceFn(0, math.MaxInt64, 7), - )) + newMatchSliceFn(0, math.MaxInt64, 7), + )) } func TestPathSliceAll(t *testing.T) { assertPath(t, "$[123:456:7]", buildPath( - newMatchSliceFn(123, 456, 7), - )) + newMatchSliceFn(123, 456, 7), + )) } func TestPathAny(t *testing.T) { assertPath(t, "$.*", buildPath( - newMatchAnyFn(), - )) + newMatchAnyFn(), + )) } func TestPathUnion(t *testing.T) { assertPath(t, "$[foo, bar, baz]", buildPath( - &matchUnionFn{ []PathFn { - newMatchKeyFn("foo"), - newMatchKeyFn("bar"), - newMatchKeyFn("baz"), - }}, - )) + &matchUnionFn{[]PathFn{ + newMatchKeyFn("foo"), + newMatchKeyFn("bar"), + newMatchKeyFn("baz"), + }}, + )) } func TestPathRecurse(t *testing.T) { assertPath(t, "$..*", buildPath( - newMatchRecursiveFn(), - )) + newMatchRecursiveFn(), + )) } func TestPathFilterExpr(t *testing.T) { assertPath(t, "$[?('foo'),?(bar)]", buildPath( - &matchUnionFn{ []PathFn { - newMatchFilterFn("foo", Position{}), - newMatchFilterFn("bar", Position{}), - }}, - )) + &matchUnionFn{[]PathFn{ + newMatchFilterFn("foo", Position{}), + newMatchFilterFn("bar", Position{}), + }}, + )) } func TestPathScriptExpr(t *testing.T) { assertPath(t, "$[('foo'),(bar)]", buildPath( - &matchUnionFn{ []PathFn { - newMatchScriptFn("foo", Position{}), - newMatchScriptFn("bar", Position{}), - }}, - )) + &matchUnionFn{[]PathFn{ + newMatchScriptFn("foo", Position{}), + newMatchScriptFn("bar", Position{}), + }}, + )) }
diff --git a/jpath/parser.go b/jpath/parser.go index f59ba0c..8e93457 100644 --- a/jpath/parser.go +++ b/jpath/parser.go
@@ -16,7 +16,7 @@ flow chan token tokensBuffer []token path *Query - union []PathFn + union []PathFn } type parserStateFn func(*parser) parserStateFn @@ -49,25 +49,25 @@ return &tok } -func (p *parser) lookahead(types... tokenType) bool { - result := true - buffer := []token{} +func (p *parser) lookahead(types ...tokenType) bool { + result := true + buffer := []token{} - for _, typ := range types { - tok := p.getToken() - if tok == nil { - result = false - break - } - buffer = append(buffer, *tok) - if tok.typ != typ { - result = false - break - } - } - // add the tokens back to the buffer, and return - p.tokensBuffer = append(p.tokensBuffer, buffer...) - return result + for _, typ := range types { + tok := p.getToken() + if tok == nil { + result = false + break + } + buffer = append(buffer, *tok) + if tok.typ != typ { + result = false + break + } + } + // add the tokens back to the buffer, and return + p.tokensBuffer = append(p.tokensBuffer, buffer...) + return result } func (p *parser) getToken() *token { @@ -102,31 +102,31 @@ tok := p.getToken() switch tok.typ { case tokenDotDot: - p.path.appendPath(&matchRecursiveFn{}) - // nested parse for '..' - tok := p.getToken() - switch tok.typ { - case tokenKey: - p.path.appendPath(newMatchKeyFn(tok.val)) - return parseMatchExpr - case tokenLBracket: - return parseBracketExpr - case tokenStar: - // do nothing - the recursive predicate is enough - return parseMatchExpr - } + p.path.appendPath(&matchRecursiveFn{}) + // nested parse for '..' + tok := p.getToken() + switch tok.typ { + case tokenKey: + p.path.appendPath(newMatchKeyFn(tok.val)) + return parseMatchExpr + case tokenLBracket: + return parseBracketExpr + case tokenStar: + // do nothing - the recursive predicate is enough + return parseMatchExpr + } case tokenDot: - // nested parse for '.' - tok := p.getToken() - switch tok.typ { - case tokenKey: - p.path.appendPath(newMatchKeyFn(tok.val)) - return parseMatchExpr - case tokenStar: - p.path.appendPath(&matchAnyFn{}) - return parseMatchExpr - } + // nested parse for '.' + tok := p.getToken() + switch tok.typ { + case tokenKey: + p.path.appendPath(newMatchKeyFn(tok.val)) + return parseMatchExpr + case tokenStar: + p.path.appendPath(&matchAnyFn{}) + return parseMatchExpr + } case tokenLBracket: return parseBracketExpr @@ -139,38 +139,38 @@ } func parseBracketExpr(p *parser) parserStateFn { - if p.lookahead(tokenInteger, tokenColon) { - return parseSliceExpr - } - if p.peek().typ == tokenColon { - return parseSliceExpr - } + if p.lookahead(tokenInteger, tokenColon) { + return parseSliceExpr + } + if p.peek().typ == tokenColon { + return parseSliceExpr + } return parseUnionExpr } func parseUnionExpr(p *parser) parserStateFn { - var tok *token + var tok *token - // this state can be traversed after some sub-expressions - // so be careful when setting up state in the parser + // this state can be traversed after some sub-expressions + // so be careful when setting up state in the parser if p.union == nil { - p.union = []PathFn{} - } + p.union = []PathFn{} + } loop: // labeled loop for easy breaking - for { - if len(p.union) > 0 { - // parse delimiter or terminator - tok = p.getToken() - switch tok.typ { - case tokenComma: - // do nothing - case tokenRBracket: - break loop - default: - p.raiseError(tok, "expected ',' or ']', not '%s'", tok.val) - } - } + for { + if len(p.union) > 0 { + // parse delimiter or terminator + tok = p.getToken() + switch tok.typ { + case tokenComma: + // do nothing + case tokenRBracket: + break loop + default: + p.raiseError(tok, "expected ',' or ']', not '%s'", tok.val) + } + } // parse sub expression tok = p.getToken() @@ -190,14 +190,14 @@ } } - // if there is only one sub-expression, use that instead - if len(p.union) == 1 { - p.path.appendPath(p.union[0]) - }else { - p.path.appendPath(&matchUnionFn{p.union}) - } + // if there is only one sub-expression, use that instead + if len(p.union) == 1 { + p.path.appendPath(p.union[0]) + } else { + p.path.appendPath(&matchUnionFn{p.union}) + } - p.union = nil // clear out state + p.union = nil // clear out state return parseMatchExpr } @@ -221,11 +221,11 @@ end = tok.Int() tok = p.getToken() } - if tok.typ == tokenRBracket { - p.path.appendPath(newMatchSliceFn(start, end, step)) - return parseMatchExpr - } - if tok.typ != tokenColon { + if tok.typ == tokenRBracket { + p.path.appendPath(newMatchSliceFn(start, end, step)) + return parseMatchExpr + } + if tok.typ != tokenColon { p.raiseError(tok, "expected ']' or ':'") } @@ -247,33 +247,33 @@ } func parseFilterExpr(p *parser) parserStateFn { - tok := p.getToken() - if tok.typ != tokenLParen { - p.raiseError(tok, "expected left-parenthesis for filter expression") - } - tok = p.getToken() - if tok.typ != tokenKey && tok.typ != tokenString { - p.raiseError(tok, "expected key or string for filter funciton name") - } - name := tok.val - tok = p.getToken() - if tok.typ != tokenRParen { - p.raiseError(tok, "expected right-parenthesis for filter expression") - } + tok := p.getToken() + if tok.typ != tokenLParen { + p.raiseError(tok, "expected left-parenthesis for filter expression") + } + tok = p.getToken() + if tok.typ != tokenKey && tok.typ != tokenString { + p.raiseError(tok, "expected key or string for filter funciton name") + } + name := tok.val + tok = p.getToken() + if tok.typ != tokenRParen { + p.raiseError(tok, "expected right-parenthesis for filter expression") + } p.union = append(p.union, newMatchFilterFn(name, tok.Position)) return parseUnionExpr } func parseScriptExpr(p *parser) parserStateFn { - tok := p.getToken() - if tok.typ != tokenKey && tok.typ != tokenString { - p.raiseError(tok, "expected key or string for script funciton name") - } - name := tok.val - tok = p.getToken() - if tok.typ != tokenRParen { - p.raiseError(tok, "expected right-parenthesis for script expression") - } + tok := p.getToken() + if tok.typ != tokenKey && tok.typ != tokenString { + p.raiseError(tok, "expected key or string for script funciton name") + } + name := tok.val + tok = p.getToken() + if tok.typ != tokenRParen { + p.raiseError(tok, "expected right-parenthesis for script expression") + } p.union = append(p.union, newMatchScriptFn(name, tok.Position)) return parseUnionExpr }
diff --git a/jpath/parser_test.go b/jpath/parser_test.go index 6d3c941..ec05f07 100644 --- a/jpath/parser_test.go +++ b/jpath/parser_test.go
@@ -12,8 +12,8 @@ t.Errorf("Non-nil toml parse error: %v", err) return } - results := Compile(query).Execute(tree) - assertValue(t, results, ref, "((" + query + ")) -> ") + results := Compile(query).Execute(tree) + assertValue(t, results, ref, "(("+query+")) -> ") } func assertValue(t *testing.T, result, ref interface{}, location string) { @@ -23,14 +23,14 @@ t.Errorf("{%s} result value not of type %T: %T", location, node, resultNode) } else { - if len(node) != len(resultNode) { - t.Errorf("{%s} lengths do not match: %v vs %v", - location, node, resultNode) - } else { - for i, v := range node { - assertValue(t, resultNode[i], v, fmt.Sprintf("%s[%d]", location, i)) - } - } + if len(node) != len(resultNode) { + t.Errorf("{%s} lengths do not match: %v vs %v", + location, node, resultNode) + } else { + for i, v := range node { + assertValue(t, resultNode[i], v, fmt.Sprintf("%s[%d]", location, i)) + } + } } case map[string]interface{}: if resultNode, ok := result.(*TomlTree); !ok { @@ -79,186 +79,186 @@ } func TestQueryKey(t *testing.T) { - assertQuery(t, - "[foo]\na = 42", - "$.foo.a", + assertQuery(t, + "[foo]\na = 42", + "$.foo.a", []interface{}{ - int64(42), - }) + int64(42), + }) } func TestQueryKeyString(t *testing.T) { - assertQuery(t, - "[foo]\na = 42", - "$.foo['a']", + assertQuery(t, + "[foo]\na = 42", + "$.foo['a']", []interface{}{ - int64(42), - }) + int64(42), + }) } func TestQueryIndex(t *testing.T) { - assertQuery(t, - "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", - "$.foo.a[0]", + assertQuery(t, + "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", + "$.foo.a[0]", []interface{}{ - int64(1), - }) + int64(1), + }) } func TestQuerySliceRange(t *testing.T) { - assertQuery(t, - "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", - "$.foo.a[0:5]", + assertQuery(t, + "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", + "$.foo.a[0:5]", []interface{}{ - int64(1), - int64(2), - int64(3), - int64(4), - int64(5), - }) + int64(1), + int64(2), + int64(3), + int64(4), + int64(5), + }) } func TestQuerySliceStep(t *testing.T) { - assertQuery(t, - "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", - "$.foo.a[0:5:2]", + assertQuery(t, + "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", + "$.foo.a[0:5:2]", []interface{}{ - int64(1), - int64(3), - int64(5), - }) + int64(1), + int64(3), + int64(5), + }) } func TestQueryAny(t *testing.T) { - assertQuery(t, - "[foo.bar]\na=1\nb=2\n[foo.baz]\na=3\nb=4", - "$.foo.*", + assertQuery(t, + "[foo.bar]\na=1\nb=2\n[foo.baz]\na=3\nb=4", + "$.foo.*", []interface{}{ - map[string]interface{}{ - "a": int64(1), - "b": int64(2), - }, - map[string]interface{}{ - "a": int64(3), - "b": int64(4), - }, - }) + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + }) } func TestQueryUnionSimple(t *testing.T) { - assertQuery(t, - "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", - "$.*[bar,foo]", + assertQuery(t, + "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", + "$.*[bar,foo]", []interface{}{ - map[string]interface{}{ - "a": int64(1), - "b": int64(2), - }, - map[string]interface{}{ - "a": int64(3), - "b": int64(4), - }, - map[string]interface{}{ - "a": int64(5), - "b": int64(6), - }, - }) + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, + }) } func TestQueryRecursionAll(t *testing.T) { - assertQuery(t, - "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", - "$..*", + assertQuery(t, + "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", + "$..*", []interface{}{ - map[string]interface{}{ - "bar": map[string]interface{}{ - "a": int64(1), - "b": int64(2), - }, - }, - map[string]interface{}{ - "a": int64(1), - "b": int64(2), - }, - int64(1), - int64(2), - map[string]interface{}{ - "foo": map[string]interface{}{ - "a": int64(3), - "b": int64(4), - }, - }, - map[string]interface{}{ - "a": int64(3), - "b": int64(4), - }, - int64(3), - int64(4), - map[string]interface{}{ - "foo": map[string]interface{}{ - "a": int64(5), - "b": int64(6), - }, - }, - map[string]interface{}{ - "a": int64(5), - "b": int64(6), - }, - int64(5), - int64(6), - }) + map[string]interface{}{ + "bar": map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + }, + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + int64(1), + int64(2), + map[string]interface{}{ + "foo": map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + }, + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + int64(3), + int64(4), + map[string]interface{}{ + "foo": map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, + }, + map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, + int64(5), + int64(6), + }) } func TestQueryRecursionUnionSimple(t *testing.T) { - assertQuery(t, - "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", - "$..['foo','bar']", + assertQuery(t, + "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", + "$..['foo','bar']", []interface{}{ - map[string]interface{}{ - "a": int64(1), - "b": int64(2), - }, - map[string]interface{}{ - "a": int64(3), - "b": int64(4), - }, - map[string]interface{}{ - "a": int64(5), - "b": int64(6), - }, - }) + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, + }) } func TestQueryScriptFnLast(t *testing.T) { - assertQuery(t, - "[foo]\na = [0,1,2,3,4,5,6,7,8,9]", - "$.foo.a[(last)]", + assertQuery(t, + "[foo]\na = [0,1,2,3,4,5,6,7,8,9]", + "$.foo.a[(last)]", []interface{}{ - int64(9), - }) + int64(9), + }) } func TestQueryFilterFnOdd(t *testing.T) { - assertQuery(t, - "[foo]\na = [0,1,2,3,4,5,6,7,8,9]", - "$.foo.a[?(odd)]", + assertQuery(t, + "[foo]\na = [0,1,2,3,4,5,6,7,8,9]", + "$.foo.a[?(odd)]", []interface{}{ - int64(1), - int64(3), - int64(5), - int64(7), - int64(9), - }) + int64(1), + int64(3), + int64(5), + int64(7), + int64(9), + }) } func TestQueryFilterFnEven(t *testing.T) { - assertQuery(t, - "[foo]\na = [0,1,2,3,4,5,6,7,8,9]", - "$.foo.a[?(even)]", + assertQuery(t, + "[foo]\na = [0,1,2,3,4,5,6,7,8,9]", + "$.foo.a[?(even)]", []interface{}{ - int64(0), - int64(2), - int64(4), - int64(6), - int64(8), - }) + int64(0), + int64(2), + int64(4), + int64(6), + int64(8), + }) }
diff --git a/jpath/query.go b/jpath/query.go index 082fa69..3bf306c 100644 --- a/jpath/query.go +++ b/jpath/query.go
@@ -1,7 +1,7 @@ package jpath import ( - _ "github.com/pelletier/go-toml" + _ "github.com/pelletier/go-toml" ) type nodeFilterFn func(node interface{}) bool @@ -9,109 +9,108 @@ // runtime context for executing query paths type queryContext struct { - filters *map[string]nodeFilterFn - scripts *map[string]nodeFn - results []interface{} + filters *map[string]nodeFilterFn + scripts *map[string]nodeFn + results []interface{} } func (c *queryContext) appendResult(value interface{}) { - c.results = append(c.results, value) + c.results = append(c.results, value) } // generic path functor interface type PathFn interface { - SetNext(next PathFn) - Call(node interface{}, ctx *queryContext) + SetNext(next PathFn) + Call(node interface{}, ctx *queryContext) } // encapsulates a query functor chain and script callbacks type Query struct { - root PathFn - tail PathFn - filters *map[string]nodeFilterFn - scripts *map[string]nodeFn + root PathFn + tail PathFn + filters *map[string]nodeFilterFn + scripts *map[string]nodeFn } func newQuery() *Query { - return &Query { - root: nil, - tail: nil, - filters: &defaultFilterFunctions, - scripts: &defaultScriptFunctions, - } + return &Query{ + root: nil, + tail: nil, + filters: &defaultFilterFunctions, + scripts: &defaultScriptFunctions, + } } func (q *Query) appendPath(next PathFn) { - if q.root == nil { - q.root = next - } else { - q.tail.SetNext(next) - } - q.tail = next - next.SetNext(newTerminatingFn()) // init the next functor + if q.root == nil { + q.root = next + } else { + q.tail.SetNext(next) + } + q.tail = next + next.SetNext(newTerminatingFn()) // init the next functor } func Compile(path string) *Query { - _, flow := lex(path) - return parse(flow) + _, flow := lex(path) + return parse(flow) } func (q *Query) Execute(node interface{}) interface{} { - if q.root == nil { - return []interface{}{node} // identity query for no predicates - } - ctx := &queryContext { - filters: q.filters, - scripts: q.scripts, - results: []interface{}{}, - } - q.root.Call(node, ctx) - return ctx.results + if q.root == nil { + return []interface{}{node} // identity query for no predicates + } + ctx := &queryContext{ + filters: q.filters, + scripts: q.scripts, + results: []interface{}{}, + } + q.root.Call(node, ctx) + return ctx.results } func (q *Query) SetFilter(name string, fn nodeFilterFn) { - if q.filters == &defaultFilterFunctions { - // clone the static table - q.filters = &map[string]nodeFilterFn{} - for k, v := range defaultFilterFunctions { - (*q.filters)[k] = v - } - } - (*q.filters)[name] = fn + if q.filters == &defaultFilterFunctions { + // clone the static table + q.filters = &map[string]nodeFilterFn{} + for k, v := range defaultFilterFunctions { + (*q.filters)[k] = v + } + } + (*q.filters)[name] = fn } func (q *Query) SetScript(name string, fn nodeFn) { - if q.scripts == &defaultScriptFunctions { - // clone the static table - q.scripts = &map[string]nodeFn{} - for k, v := range defaultScriptFunctions { - (*q.scripts)[k] = v - } - } - (*q.scripts)[name] = fn + if q.scripts == &defaultScriptFunctions { + // clone the static table + q.scripts = &map[string]nodeFn{} + for k, v := range defaultScriptFunctions { + (*q.scripts)[k] = v + } + } + (*q.scripts)[name] = fn } -var defaultFilterFunctions = map[string]nodeFilterFn { - "odd": func(node interface{}) bool { - if ii, ok := node.(int64); ok { - return (ii & 1) == 1 - } - return false - }, - "even": func(node interface{}) bool { - if ii, ok := node.(int64); ok { - return (ii & 1) == 0 - } - return false - }, +var defaultFilterFunctions = map[string]nodeFilterFn{ + "odd": func(node interface{}) bool { + if ii, ok := node.(int64); ok { + return (ii & 1) == 1 + } + return false + }, + "even": func(node interface{}) bool { + if ii, ok := node.(int64); ok { + return (ii & 1) == 0 + } + return false + }, } -var defaultScriptFunctions = map[string]nodeFn { - "last": func(node interface{}) interface{} { - if arr, ok := node.([]interface{}); ok { - return len(arr)-1 - } - return nil - }, +var defaultScriptFunctions = map[string]nodeFn{ + "last": func(node interface{}) interface{} { + if arr, ok := node.([]interface{}); ok { + return len(arr) - 1 + } + return nil + }, } -