aeson-jsonpath-0.3.0.2: test/spec/QuerySpec.hs
module QuerySpec
( spec )
where
import qualified Data.Vector as V
import qualified Data.Aeson as JSON
import Data.Aeson.QQ.Simple (aesonQQ)
import Data.Aeson (Value)
import Data.Vector (Vector)
import Test.Hspec
import Data.Aeson.JSONPath (queryQQ, jsonPath)
import Prelude
getVector :: Value -> Vector Value
getVector (JSON.Array arr) = arr
getVector _ = V.empty
-- taken from https://serdejsonpath.live/
rootDoc :: Value
rootDoc = [aesonQQ|{
"store": {
"books": [
{
"title": "Guns, Germs, and Steel",
"author": "Jared Diamond",
"category": "reference",
"price": 24.99
},
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
},
{
"title": "Crime and Punishment",
"author": "Fyodor Dostoevsky",
"category": "fiction",
"price": 19.99
}
]
}
}|]
storeDoc :: Value
storeDoc = [aesonQQ|
{
"books": [
{
"title": "Guns, Germs, and Steel",
"author": "Jared Diamond",
"category": "reference",
"price": 24.99
},
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
},
{
"title": "Crime and Punishment",
"author": "Fyodor Dostoevsky",
"category": "fiction",
"price": 19.99
}
]
}|]
booksDoc :: Value
booksDoc = [aesonQQ| [
{
"title": "Guns, Germs, and Steel",
"author": "Jared Diamond",
"category": "reference",
"price": 24.99
},
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
},
{
"title": "Crime and Punishment",
"author": "Fyodor Dostoevsky",
"category": "fiction",
"price": 19.99
}
]|]
books0Doc :: Value
books0Doc = [aesonQQ|[
{
"title": "Guns, Germs, and Steel",
"author": "Jared Diamond",
"category": "reference",
"price": 24.99
}
]|]
books0And2Doc :: Value
books0And2Doc = [aesonQQ|[
{
"title": "Guns, Germs, and Steel",
"author": "Jared Diamond",
"category": "reference",
"price": 24.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
}
]|]
books1To3Doc :: Value
books1To3Doc = [aesonQQ|[
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
}
]|]
books1To3And0And1Doc :: Value
books1To3And0And1Doc = [aesonQQ|[
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
},
{
"title": "Guns, Germs, and Steel",
"author": "Jared Diamond",
"category": "reference",
"price": 24.99
},
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
}
]|]
lessThanPrice20Books :: Value
lessThanPrice20Books = [aesonQQ| [
{
"title": "David Copperfield",
"author": "Charles Dickens",
"category": "fiction",
"price": 12.99
},
{
"title": "Moby Dick",
"author": "Herman Melville",
"category": "fiction",
"price": 8.99
},
{
"title": "Crime and Punishment",
"author": "Fyodor Dostoevsky",
"category": "fiction",
"price": 19.99
}
]|]
alphaArr :: Value
alphaArr = [aesonQQ| ["a","b","c","d","e","f","g"] |]
fgArr :: Value
fgArr = [aesonQQ| ["f","g"] |]
bdArr :: Value
bdArr = [aesonQQ| ["b","d"] |]
fdArr :: Value
fdArr = [aesonQQ| ["f","d"] |]
gfedcbaArr :: Value
gfedcbaArr = [aesonQQ| ["g","f","e","d","c","b","a"] |]
rfcExample1 :: Value
rfcExample1 = [aesonQQ| {
"o": {"j": 1, "k": 2},
"a": [5, 3, [{"j": 4}, {"k": 6}]]
} |]
rfcExample1Desc :: Value
rfcExample1Desc = [aesonQQ| [
[5, 3, [{"j": 4}, {"k": 6}]],
{"j": 1, "k": 2},
5,
3,
[{"j": 4}, {"k": 6}],
{"j": 4},
{"k": 6},
4,
6,
1,
2
]|]
boolsAndNulls :: Value
boolsAndNulls = [aesonQQ| [
{ "a": true },
{ "a": false },
{ "a": null }
]|]
boolsAndNullsA :: Value
boolsAndNullsA = [aesonQQ| [{ "a": true }] |]
boolsAndNullsB :: Value
boolsAndNullsB = [aesonQQ| [{ "a": false }] |]
boolsAndNullsC :: Value
boolsAndNullsC = [aesonQQ| [{ "a": null }] |]
spec :: Spec
spec = do
describe "test query" $ do
it "returns root document when query is $" $
queryQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton rootDoc
it "returns store object when queryQQ is $.store" $
queryQQ [jsonPath|$.store|] rootDoc `shouldBe` V.singleton storeDoc
it "returns store object when queryQQ is $['store']" $
queryQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.singleton storeDoc
it "returns books array when queryQQ is $.store.books" $
queryQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.singleton booksDoc
it "returns 0-index book item when queryQQ is $.store.books[0]" $
queryQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` getVector books0Doc
it "returns 0-index book item when queryQQ is $.store.books[-4]" $
queryQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` getVector books0Doc
it "returns 0,2-index item when queryQQ is $.store.books[0,2]" $
queryQQ [jsonPath|$.store.books[0,2]|] rootDoc `shouldBe` getVector books0And2Doc
it "returns 1To3-index when queryQQ is $.store.books[1:3]" $
queryQQ [jsonPath|$.store.books[1:3]|] rootDoc `shouldBe` getVector books1To3Doc
it "returns 1To3-index and 0,1-index when queryQQ is $.store.books[1:3,0,1]" $
queryQQ [jsonPath|$.store.books[1:3,0,1]|] rootDoc `shouldBe` getVector books1To3And0And1Doc
it "returns slice with queryQQ $[5:]" $
queryQQ [jsonPath|$[5:]|] alphaArr `shouldBe` getVector fgArr
it "returns slice with queryQQ $[1:5:2]" $
queryQQ [jsonPath|$[1:5:2]|] alphaArr `shouldBe` getVector bdArr
it "returns slice with queryQQ $[5:1:-2]" $
queryQQ [jsonPath|$[5:1:-2]|] alphaArr `shouldBe` getVector fdArr
it "returns slice with queryQQ $[::-1]" $
queryQQ [jsonPath|$[::-1]|] alphaArr `shouldBe` getVector gfedcbaArr
it "returns root with queryQQ $.*" $
queryQQ [jsonPath|$.*|] rootDoc `shouldBe` V.singleton storeDoc
it "returns root with queryQQ $[*]" $
queryQQ [jsonPath|$[*]|] rootDoc `shouldBe` V.singleton storeDoc
it "returns descendants with queryQQ $..*" $
queryQQ [jsonPath|$..*|] rfcExample1 `shouldBe` getVector rfcExample1Desc
it "returns descendants with queryQQ $..[*]" $
queryQQ [jsonPath|$..[*]|] rfcExample1 `shouldBe` getVector rfcExample1Desc
it "returns with filtering: number comparison" $
queryQQ [jsonPath|$.store.books[?@.price < 20]|] rootDoc
`shouldBe` getVector lessThanPrice20Books
it "returns with filtering: not operator" $
queryQQ [jsonPath|$.store.books[?!(@.price < 20)]|] rootDoc
`shouldBe` getVector books0Doc
it "returns with filtering: true value" $
queryQQ [jsonPath|$[?@.a == true]|] boolsAndNulls
`shouldBe` getVector boolsAndNullsA
it "returns with filtering: false value" $
queryQQ [jsonPath|$[?@.a == false]|] boolsAndNulls
`shouldBe` getVector boolsAndNullsB
it "returns with filtering: null value" $
queryQQ [jsonPath|$[?@.a == null]|] boolsAndNulls
`shouldBe` getVector boolsAndNullsC
it "returns with filtering: string comparison" $
queryQQ [jsonPath|$.store.books[?@.author == 'Jared Diamond']|] rootDoc
`shouldBe` getVector books0Doc
it "returns with filtering: test expression" $
queryQQ [jsonPath|$.store.books[?@.author]|] rootDoc
`shouldBe` getVector booksDoc
it "returns with filtering with spaced out segments: test expression" $
queryQQ [jsonPath|$ .store .books[?@ .author]|] rootDoc
`shouldBe` getVector booksDoc
it "returns with filtering: test expr gives empty with non-existent key" $
queryQQ [jsonPath|$.store.books[?@.not_here]|] rootDoc
`shouldBe` V.empty