{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module JSONTest where
import Control.Monad.IO.Class (MonadIO)
import Data.Aeson hiding (Key)
import qualified Data.Vector as V (fromList)
import Test.HUnit (assertBool)
import Test.Hspec.Expectations ()
import Database.Persist
import Database.Persist.Postgresql.JSON
import PgInit
share
[mkPersist persistSettings, mkMigrate "jsonTestMigrate"]
[persistLowerCase|
TestValue
json Value
deriving Show
|]
cleanDB
:: (BaseBackend backend ~ SqlBackend, PersistQueryWrite backend, MonadIO m)
=> ReaderT backend m ()
cleanDB = deleteWhere ([] :: [Filter TestValue])
emptyArr :: Value
emptyArr = toJSON ([] :: [Value])
insert'
:: (MonadIO m, PersistStoreWrite backend, BaseBackend backend ~ SqlBackend)
=> Value -> ReaderT backend m (Key TestValue)
insert' = insert . TestValue
matchKeys
:: (Show record, Show (Key record), MonadIO m, Eq (Key record))
=> [Key record] -> [Entity record] -> m ()
matchKeys ys xs = do
msg1 `assertBoolIO` (xLen == yLen)
forM_ ys $ \y -> msg2 y `assertBoolIO` (y `elem` ks)
where
ks = entityKey <$> xs
xLen = length xs
yLen = length ys
msg1 =
mconcat
[ "\nexpected: "
, show yLen
, "\n but got: "
, show xLen
, "\n[xs: "
, show xs
, "]"
, "\n[ys: "
, show ys
, "]"
]
msg2 y =
mconcat
[ "key \""
, show y
, "\" not in result:\n "
, show ks
]
setup :: IO TestKeys
setup = asIO $ runConn_ $ do
void $ runMigrationSilent jsonTestMigrate
testKeys
teardown :: IO ()
teardown = asIO $ runConn_ $ do
cleanDB
shouldBeIO :: (Show a, Eq a, MonadIO m) => a -> a -> m ()
shouldBeIO x y = liftIO $ shouldBe x y
assertBoolIO :: (MonadIO m) => String -> Bool -> m ()
assertBoolIO s b = liftIO $ assertBool s b
testKeys :: (Monad m, MonadIO m) => ReaderT SqlBackend m TestKeys
testKeys = do
nullK <- insert' Null
boolTK <- insert' $ Bool True
boolFK <- insert' $ toJSON False
num0K <- insert' $ Number 0
num1K <- insert' $ Number 1
numBigK <- insert' $ toJSON (1234567890 :: Int)
numFloatK <- insert' $ Number 0.0
numSmallK <- insert' $ Number 0.0000000000000000123
numFloat2K <- insert' $ Number 1.5
-- numBigFloatK will turn into 9876543210.123457 because JSON
numBigFloatK <- insert' $ toJSON (9876543210.123456789 :: Double)
strNullK <- insert' $ String ""
strObjK <- insert' $ String "{}"
strArrK <- insert' $ String "[]"
strAK <- insert' $ String "a"
strTestK <- insert' $ toJSON ("testing" :: Text)
str2K <- insert' $ String "2"
strFloatK <- insert' $ String "0.45876"
arrNullK <- insert' $ Array $ V.fromList []
arrListK <- insert' $ toJSON [emptyArr, emptyArr, toJSON [emptyArr, emptyArr]]
arrList2K <-
insert' $
toJSON
[ emptyArr
, toJSON [Number 3, Bool False]
, toJSON [emptyArr, toJSON [Object mempty]]
]
arrFilledK <-
insert' $
toJSON
[ Null
, Number 4
, String "b"
, Object mempty
, emptyArr
, object ["test" .= [Null], "test2" .= String "yes"]
]
arrList3K <- insert' $ toJSON [toJSON [String "a"], Number 1]
arrList4K <- insert' $ toJSON [String "a", String "b", String "c", String "d"]
objNullK <- insert' $ Object mempty
objTestK <- insert' $ object ["test" .= Null, "test1" .= String "no"]
objDeepK <-
insert' $ object ["c" .= Number 24.986, "foo" .= object ["deep1" .= Bool True]]
objEmptyK <- insert' $ object ["" .= Number 9001]
objFullK <-
insert' $
object
[ "a" .= Number 1
, "b" .= Number 2
, "c" .= Number 3
, "d" .= Number 4
]
return TestKeys{..}
data TestKeys
= TestKeys
{ nullK :: Key TestValue
, boolTK :: Key TestValue
, boolFK :: Key TestValue
, num0K :: Key TestValue
, num1K :: Key TestValue
, numBigK :: Key TestValue
, numFloatK :: Key TestValue
, numSmallK :: Key TestValue
, numFloat2K :: Key TestValue
, numBigFloatK :: Key TestValue
, strNullK :: Key TestValue
, strObjK :: Key TestValue
, strArrK :: Key TestValue
, strAK :: Key TestValue
, strTestK :: Key TestValue
, str2K :: Key TestValue
, strFloatK :: Key TestValue
, arrNullK :: Key TestValue
, arrListK :: Key TestValue
, arrList2K :: Key TestValue
, arrFilledK :: Key TestValue
, objNullK :: Key TestValue
, objTestK :: Key TestValue
, objDeepK :: Key TestValue
, arrList3K :: Key TestValue
, arrList4K :: Key TestValue
, objEmptyK :: Key TestValue
, objFullK :: Key TestValue
}
deriving (Eq, Ord, Show)
specs :: Spec
specs = afterAll_ teardown $ do
beforeAll setup $ do
describe "Testing JSON operators" $ do
describe "@>. object queries" $ do
it "matches an empty Object with any object" $
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. Object mempty] []
[objNullK, objTestK, objDeepK, objEmptyK, objFullK] `matchKeys` vals
it "matches a subset of object properties" $
-- {test: null, test1: no} @>. {test: null} == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. object ["test" .= Null]] []
[objTestK] `matchKeys` vals
it "matches a nested object against an empty object at the same key" $
-- {c: 24.986, foo: {deep1: true}} @>. {foo: {}} == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. object ["foo" .= object []]] []
[objDeepK] `matchKeys` vals
it "doesn't match a nested object against a string at the same key" $
-- {c: 24.986, foo: {deep1: true}} @>. {foo: nope} == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. object ["foo" .= String "nope"]] []
[] `matchKeys` vals
it "matches a nested object when the query object is identical" $
-- {c: 24.986, foo: {deep1: true}} @>. {foo: {deep1: true}} == True
\TestKeys{..} -> runConnAssert $ do
vals <-
selectList [TestValueJson @>. (object ["foo" .= object ["deep1" .= True]])] []
[objDeepK] `matchKeys` vals
it "doesn't match a nested object when queried with that exact object" $
-- {c: 24.986, foo: {deep1: true}} @>. {deep1: true} == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. object ["deep1" .= True]] []
[] `matchKeys` vals
describe "@>. array queries" $ do
it "matches an empty Array with any list" $
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. emptyArr] []
[arrNullK, arrListK, arrList2K, arrFilledK, arrList3K, arrList4K]
`matchKeys` vals
it "matches list when queried with subset (1 item)" $
-- [null, 4, 'b', {}, [], {test: [null], test2: 'yes'}] @>. [4] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [4 :: Int]] []
[arrFilledK] `matchKeys` vals
it "matches list when queried with subset (2 items)" $
-- [null, 4, 'b', {}, [], {test: [null], test2: 'yes'}] @>. [null,'b'] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [Null, String "b"]] []
[arrFilledK] `matchKeys` vals
it "doesn't match list when queried with intersecting list (1 match, 1 diff)" $
-- [null, 4, 'b', {}, [], {test: [null], test2: 'yes'}] @>. [null,'d'] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [emptyArr, String "d"]] []
[] `matchKeys` vals
it "matches list when queried with same list in different order" $
-- [null, 4, 'b', {}, [], {test: [null], test2: 'yes'}] @>.
-- [[],'b',{test: [null],test2: 'yes'},4,null,{}] == True
\TestKeys{..} -> runConnAssert $ do
let
queryList =
toJSON
[ emptyArr
, String "b"
, object ["test" .= [Null], "test2" .= String "yes"]
, Number 4
, Null
, Object mempty
]
vals <- selectList [TestValueJson @>. queryList] []
[arrFilledK] `matchKeys` vals
it "doesn't match list when queried with same list + 1 item" $
-- [null,4,'b',{},[],{test:[null],test2:'yes'}] @>.
-- [null,4,'b',{},[],{test:[null],test2: 'yes'}, false] == False
\TestKeys{..} -> runConnAssert $ do
let
testList =
toJSON
[ Null
, Number 4
, String "b"
, Object mempty
, emptyArr
, object ["test" .= [Null], "test2" .= String "yes"]
, Bool False
]
vals <- selectList [TestValueJson @>. testList] []
[] `matchKeys` vals
it "matches list when it shares an empty object with the query list" $
-- [null,4,'b',{},[],{test: [null],test2: 'yes'}] @>. [{}] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [Object mempty]] []
[arrFilledK] `matchKeys` vals
it "matches list with nested list, when queried with an empty nested list" $
-- [null,4,'b',{},[],{test:[null],test2:'yes'}] @>. [{test:[]}] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [object ["test" .= emptyArr]]] []
[arrFilledK] `matchKeys` vals
it "doesn't match list with nested list, when queried with a diff. nested list" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>.
-- [{"test1":[null]}] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [object ["test1" .= [Null]]]] []
[] `matchKeys` vals
it "matches many nested lists when queried with empty nested list" $
-- [[],[],[[],[]]] @>. [[]] == True
-- [[],[3,false],[[],[{}]]] @>. [[]] == True
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>. [[]] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [emptyArr]] []
[arrListK, arrList2K, arrFilledK, arrList3K] `matchKeys` vals
it "matches nested list when queried with a subset of that list" $
-- [[],[3,false],[[],[{}]]] @>. [[3]] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [[3 :: Int]]] []
[arrList2K] `matchKeys` vals
it "doesn't match nested list againts a partial intersection of that list" $
-- [[],[3,false],[[],[{}]]] @>. [[true,3]] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON [[Bool True, Number 3]]] []
[] `matchKeys` vals
it "matches list when queried with raw number contained in the list" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>. 4 == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. Number 4] []
[arrFilledK] `matchKeys` vals
it "doesn't match list when queried with raw value not contained in the list" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>. 99 == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. Number 99] []
[] `matchKeys` vals
it "matches list when queried with raw string contained in the list" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>. "b" == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "b"] []
[arrFilledK, arrList4K] `matchKeys` vals
it "doesn't match list with empty object when queried with \"{}\" " $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>. "{}" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "{}"] []
[strObjK] `matchKeys` vals
it "doesnt match list with nested object when queried with object (not in list)" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @>.
-- {"test":[null],"test2":"yes"} == False
\TestKeys{..} -> runConnAssert $ do
let
queryObject = object ["test" .= [Null], "test2" .= String "yes"]
vals <- selectList [TestValueJson @>. queryObject] []
[] `matchKeys` vals
describe "@>. string queries" $ do
it "matches identical strings" $
-- "testing" @>. "testing" == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "testing"] []
[strTestK] `matchKeys` vals
it "doesnt match case insensitive" $
-- "testing" @>. "Testing" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "Testing"] []
[] `matchKeys` vals
it "doesn't match substrings" $
-- "testing" @>. "test" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "test"] []
[] `matchKeys` vals
it "doesn't match strings with object keys" $
-- "testing" @>. {"testing":1} == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. object ["testing" .= Number 1]] []
[] `matchKeys` vals
describe "@>. number queries" $ do
it "matches identical numbers" $
-- 1 @>. 1 == True
-- [1] @>. 1 == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON (1 :: Int)] []
[num1K, arrList3K] `matchKeys` vals
it "matches numbers when queried with float" $
-- 0 @>. 0.0 == True
-- 0.0 @>. 0.0 == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON (0.0 :: Double)] []
[num0K, numFloatK] `matchKeys` vals
it "does not match numbers when queried with a substring of that number" $
-- 1234567890 @>. 123456789 == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON (123456789 :: Int)] []
[] `matchKeys` vals
it "does not match number when queried with different number" $
-- 1234567890 @>. 234567890 == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON (234567890 :: Int)] []
[] `matchKeys` vals
it "does not match number when queried with string of that number" $
-- 1 @>. "1" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "1"] []
[] `matchKeys` vals
it "does not match number when queried with list of digits" $
-- 1234567890 @>. [1,2,3,4,5,6,7,8,9,0] == False
\TestKeys{..} -> runConnAssert $ do
vals <-
selectList
[TestValueJson @>. toJSON ([1, 2, 3, 4, 5, 6, 7, 8, 9, 0] :: [Int])]
[]
[] `matchKeys` vals
describe "@>. boolean queries" $ do
it "matches identical booleans (True)" $
-- true @>. true == True
-- false @>. true == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. toJSON True] []
[boolTK] `matchKeys` vals
it "matches identical booleans (False)" $
-- false @>. false == True
-- true @>. false == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. Bool False] []
[boolFK] `matchKeys` vals
it "does not match boolean with string of boolean" $
-- true @>. "true" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "true"] []
[] `matchKeys` vals
describe "@>. null queries" $ do
it "matches nulls" $
-- null @>. null == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. Null] []
[nullK, arrFilledK] `matchKeys` vals
it "does not match null with string of null" $
-- null @>. "null" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson @>. String "null"] []
[] `matchKeys` vals
describe "<@. queries" $ do
it "matches subobject when queried with superobject" $
-- {} <@. {"test":null,"test1":"no","blabla":[]} == True
-- {"test":null,"test1":"no"} <@. {"test":null,"test1":"no","blabla":[]} == True
\TestKeys{..} -> runConnAssert $ do
let
queryObject =
object
[ "test" .= Null
, "test1" .= String "no"
, "blabla" .= emptyArr
]
vals <- selectList [TestValueJson <@. queryObject] []
[objNullK, objTestK] `matchKeys` vals
it "matches raw values and sublists when queried with superlist" $
-- [] <@. [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
-- null <@. [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
-- false <@. [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] <@.
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
\TestKeys{..} -> runConnAssert $ do
let
queryList =
toJSON
[ Null
, Number 4
, String "b"
, Object mempty
, emptyArr
, object ["test" .= [Null], "test2" .= String "yes"]
, Bool False
]
vals <- selectList [TestValueJson <@. queryList] []
[arrNullK, arrFilledK, boolFK, nullK] `matchKeys` vals
it "matches identical strings" $
-- "a" <@. "a" == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson <@. String "a"] []
[strAK] `matchKeys` vals
it "matches identical big floats" $
-- 9876543210.123457 <@ 9876543210.123457 == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson <@. Number 9876543210.123457] []
[numBigFloatK] `matchKeys` vals
it "doesn't match different big floats" $
-- 9876543210.123457 <@. 9876543210.123456789 == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson <@. Number 9876543210.123456789] []
[] `matchKeys` vals
it "matches nulls" $
-- null <@. null == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson <@. Null] []
[nullK] `matchKeys` vals
describe "?. queries" $ do
it "matches top level keys and not the keys of nested objects" $
-- {"test":null,"test1":"no"} ?. "test" == True
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?. "test" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "test"] []
[objTestK] `matchKeys` vals
it "doesn't match nested key" $
-- {"c":24.986,"foo":{"deep1":true"}} ?. "deep1" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "deep1"] []
[] `matchKeys` vals
it "matches \"{}\" but not empty object when queried with \"{}\"" $
-- "{}" ?. "{}" == True
-- {} ?. "{}" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "{}"] []
[strObjK] `matchKeys` vals
it "matches raw empty str and empty str key when queried with \"\"" $
---- {} ?. "" == False
---- "" ?. "" == True
---- {"":9001} ?. "" == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. ""] []
[strNullK, objEmptyK] `matchKeys` vals
it "matches lists containing string value when queried with raw string value" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?. "b" == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "b"] []
[arrFilledK, arrList4K, objFullK] `matchKeys` vals
it "matches lists, objects, and raw values correctly when queried with string" $
-- [["a"]] ?. "a" == False
-- "a" ?. "a" == True
-- ["a","b","c","d"] ?. "a" == True
-- {"a":1,"b":2,"c":3,"d":4} ?. "a" == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "a"] []
[strAK, arrList4K, objFullK] `matchKeys` vals
it "matches string list but not real list when queried with \"[]\"" $
-- "[]" ?. "[]" == True
-- [] ?. "[]" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "[]"] []
[strArrK] `matchKeys` vals
it "does not match null when queried with string null" $
-- null ?. "null" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "null"] []
[] `matchKeys` vals
it "does not match bool whe nqueried with string bool" $
-- true ?. "true" == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?. "true"] []
[] `matchKeys` vals
describe "?|. queries" $ do
it "matches raw vals, lists, objects, and nested objects" $
-- "a" ?|. ["a","b","c"] == True
-- [["a"],1] ?|. ["a","b","c"] == False
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?|. ["a","b","c"] == True
-- ["a","b","c","d"] ?|. ["a","b","c"] == True
-- {"a":1,"b":2,"c":3,"d":4} ?|. ["a","b","c"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. ["a", "b", "c"]] []
[strAK, arrFilledK, objDeepK, arrList4K, objFullK] `matchKeys` vals
it "matches str object but not object when queried with \"{}\"" $
-- "{}" ?|. ["{}"] == True
-- {} ?|. ["{}"] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. ["{}"]] []
[strObjK] `matchKeys` vals
it "doesn't match superstrings when queried with substring" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?|. ["test"] == False
-- "testing" ?|. ["test"] == False
-- {"test":null,"test1":"no"} ?|. ["test"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. ["test"]] []
[objTestK] `matchKeys` vals
it "doesn't match nested keys" $
-- {"c":24.986,"foo":{"deep1":true"}} ?|. ["deep1"] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. ["deep1"]] []
[] `matchKeys` vals
it "doesn't match anything when queried with empty list" $
-- ANYTHING ?|. [] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. []] []
[] `matchKeys` vals
it "doesn't match raw, non-string, values when queried with strings" $
-- true ?|. ["true","null","1"] == False
-- null ?|. ["true","null","1"] == False
-- 1 ?|. ["true","null","1"] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. ["true", "null", "1"]] []
[] `matchKeys` vals
it "matches string array when queried with \"[]\"" $
-- [] ?|. ["[]"] == False
-- "[]" ?|. ["[]"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?|. ["[]"]] []
[strArrK] `matchKeys` vals
describe "?&. queries" $ do
it "matches anything when queried with an empty list" $
-- ANYTHING ?&. [] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. []] []
flip
matchKeys
vals
[ nullK
, boolTK
, boolFK
, num0K
, num1K
, numBigK
, numFloatK
, numSmallK
, numFloat2K
, numBigFloatK
, strNullK
, strObjK
, strArrK
, strAK
, strTestK
, str2K
, strFloatK
, arrNullK
, arrListK
, arrList2K
, arrFilledK
, arrList3K
, arrList4K
, objNullK
, objTestK
, objDeepK
, objEmptyK
, objFullK
]
it "matches raw values, lists, and objects when queried with string" $
-- "a" ?&. ["a"] == True
-- [["a"],1] ?&. ["a"] == False
-- ["a","b","c","d"] ?&. ["a"] == True
-- {"a":1,"b":2,"c":3,"d":4} ?&. ["a"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["a"]] []
[strAK, arrList4K, objFullK] `matchKeys` vals
it "matches raw values, lists, and objects when queried with multiple string" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?&. ["b","c"] == False
-- {"c":24.986,"foo":{"deep1":true"}} ?&. ["b","c"] == False
-- ["a","b","c","d"] ?&. ["b","c"] == True
-- {"a":1,"b":2,"c":3,"d":4} ?&. ["b","c"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["b", "c"]] []
[arrList4K, objFullK] `matchKeys` vals
it "matches object string when queried with \"{}\"" $
-- {} ?&. ["{}"] == False
-- "{}" ?&. ["{}"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["{}"]] []
[strObjK] `matchKeys` vals
it "doesn't match superstrings when queried with substring" $
-- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?&. ["test"] == False
-- "testing" ?&. ["test"] == False
-- {"test":null,"test1":"no"} ?&. ["test"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["test"]] []
[objTestK] `matchKeys` vals
it "doesn't match nested keys" $
-- {"c":24.986,"foo":{"deep1":true"}} ?&. ["deep1"] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["deep1"]] []
[] `matchKeys` vals
it "doesn't match anything when there is a partial match" $
-- "a" ?&. ["a","e"] == False
-- ["a","b","c","d"] ?&. ["a","e"] == False
-- {"a":1,"b":2,"c":3,"d":4} ?&. ["a","e"] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["a", "e"]] []
[] `matchKeys` vals
it "matches string array when queried with \"[]\"" $
-- [] ?&. ["[]"] == False
-- "[]" ?&. ["[]"] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["[]"]] []
[strArrK] `matchKeys` vals
it "doesn't match null when queried with string null" $
-- THIS WILL FAIL IF THE IMPLEMENTATION USES
-- @ '{null}' @
-- INSTEAD OF
-- @ ARRAY['null'] @
-- null ?&. ["null"] == False
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. ["null"]] []
[] `matchKeys` vals
it "doesn't match number when queried with str of that number" $
-- [["a"],1] ?&. ["1"] == False
-- "1" ?&. ["1"] == True
\TestKeys{..} -> runConnAssert $ do
str1 <- insert' $ toJSON $ String "1"
vals <- selectList [TestValueJson ?&. ["1"]] []
[str1] `matchKeys` vals
it "doesn't match empty objs or list when queried with empty string" $
-- {} ?&. [""] == False
-- [] ?&. [""] == False
-- "" ?&. [""] == True
-- {"":9001} ?&. [""] == True
\TestKeys{..} -> runConnAssert $ do
vals <- selectList [TestValueJson ?&. [""]] []
[strNullK, objEmptyK] `matchKeys` vals