module ParserSpec
( spec )
where
import qualified Text.ParserCombinators.Parsec as P
import Data.Aeson.JSONPath.Parser (pQuery)
import Data.Either (isLeft)
import Data.Aeson.JSONPath.Query.Types
import Test.Hspec
import Prelude
spec :: Spec
spec = do
describe "Parse query string" $ do
it "parses query: $" $
P.parse pQuery "" "$"
`shouldBe`
Right (Query{queryType=Root,querySegments=[]})
it "parses query: $.store" $
P.parse pQuery "" "$.store"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}]
}
it "parses query: $['store']" $
P.parse pQuery "" "$['store']"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [Name "store"]
}]
}
it "parses query: $.store.books" $
P.parse pQuery "" "$.store.books"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}]
}
it "parses query: $.store.books[0]" $
P.parse pQuery "" "$.store.books[0]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Index 0]
}]
}
it "parses query: $.store.books[0,2]" $
P.parse pQuery "" "$.store.books[0,2]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Index 0, Index 2]
}]
}
it "parses query: $.store.books[1:3]" $
P.parse pQuery "" "$.store.books[1:3]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [ArraySlice (Just 1, Just 3, 1)]
}]
}
it "parses query: $.store.books[1:4:2]" $
P.parse pQuery "" "$.store.books[1:4:2]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [ArraySlice (Just 1, Just 4, 2)]
}]
}
it "parses query: $.store.books[-1:-4:-2]" $
P.parse pQuery "" "$.store.books[-1:-4:-2]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [ArraySlice (Just (-1), Just (-4), (-2))]
}]
}
it "parses query: $.store.books[1:3, 0, 1]" $
P.parse pQuery "" "$.store.books[1:3, 0, 1]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [ArraySlice (Just 1, Just 3, 1), Index 0, Index 1]
}]
}
it "parses query: $.*" $
P.parse pQuery "" "$.*"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = WildcardSegment
}]
}
it "parses query: $[*]" $
P.parse pQuery "" "$[*]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [WildcardSelector]
}]
}
it "parses query: $..*" $
P.parse pQuery "" "$..*"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Descendant,
segment = WildcardSegment
}]
}
it "parses query: $..[*]" $
P.parse pQuery "" "$..[*]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Descendant,
segment = Bracketed [WildcardSelector]
}]
}
it "fails with $.1startsWithNum" $
P.parse pQuery "" "$.1startsWithNum"
`shouldSatisfy` isLeft
it "parses query $.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ" $
P.parse pQuery "" "$.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"
}]
}
it "parses query: $._" $
P.parse pQuery "" "$._"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "_"
}]
}
it "parses query: $.underscore_key" $
P.parse pQuery "" "$.underscore_key"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "underscore_key"
}]
}
it "parses query: $[0,TAB/LINEFEED/RETURN/SPACE1]" $
P.parse pQuery "" "$[0,\n\t\r 1]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [Index 0, Index 1]
}]
}
describe "parses JSPFilter Query" $ do
it "$[?@.category == 'reference']" $
P.parse pQuery "" "$[?@.category == 'reference']"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "category"]
}) Equal (CompLitString "reference"))]])]
}]
}
it "test expr: $..books[?@.price].title" $
P.parse pQuery "" "$..books[?@.price].title"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Descendant,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test Query {
queryType = Current,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "price"
}]
}]])]
}, QuerySegment {
segmentType = Child,
segment = Dotted "title"
}]
}
it "and expr: $[?@.price < 20 && @.price > 10]" $
P.parse pQuery "" "$[?@.price < 20 && @.price > 10]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Less (CompLitNum 20.0)), Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Greater (CompLitNum 10.0))]])]
}]
}
it "or expr: $[?@.price < 20 || @.price > 10]" $
P.parse pQuery "" "$[?@.price < 20 || @.price > 10]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Less (CompLitNum 20.0))], LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Greater (CompLitNum 10.0))]])]
}]
}
it "root filter: $..books[?$.price].title" $
P.parse pQuery "" "$..books[?$.price].title"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Descendant,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "price"
}]
}]])]
}, QuerySegment {
segmentType = Child,
segment = Dotted "title"
}]
}
it "not expr: $[?!(@.price < 20 && @.price > 10)]" $
P.parse pQuery "" "$[?!(@.price < 20 && @.price > 10)]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [NotParen (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Less (CompLitNum 20.0)), Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Greater (CompLitNum 10.0))]])]])]
}]
}
it "scientific: $.store.books[?@.price < -1e20]" $
P.parse pQuery "" "$.store.books[?@['price'] < -1e20]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Less (CompLitNum (-1.0e20)))]])]
}]
}
it "double: $.store.books[?@.price < 0.01]" $
P.parse pQuery "" "$.store.books[?@['price'] < 0.01]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "price"]
}) Less (CompLitNum (1.0e-2)))]])]
}]
}
it "bool: $.store.books[?@.is_available == true]" $
P.parse pQuery "" "$.store.books[?@.is_available == true]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "is_available"]
}) Equal (CompLitBool True))]])]
}]
}
it "null: $.store.books[?@.is_available == null]" $
P.parse pQuery "" "$.store.books[?@.is_available == null]"
`shouldBe`
Right Query {
queryType = Root,
querySegments = [QuerySegment {
segmentType = Child,
segment = Dotted "store"
}, QuerySegment {
segmentType = Child,
segment = Dotted "books"
}, QuerySegment {
segmentType = Child,
segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
singularQueryType = CurrentSQ,
singularQuerySegments = [NameSQSeg "is_available"]
}) Equal CompLitNull)]])]
}]
}