123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- {-# LANGUAGE ExistentialQuantification #-}
- {-# LANGUAGE FlexibleContexts #-}
- {-# LANGUAGE FlexibleInstances #-}
- {-# LANGUAGE MultiParamTypeClasses #-}
- {-# LANGUAGE OverloadedStrings #-}
- {-# LANGUAGE QuasiQuotes #-}
- {-# LANGUAGE TemplateHaskell #-}
- {-# LANGUAGE TypeFamilies #-}
- {-# LANGUAGE UndecidableInstances #-} -- FIXME
- module JSONTest where
- import Control.Monad.IO.Class (MonadIO)
- import Data.Aeson
- 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
- (=@=) :: MonadIO m => String -> Bool -> m ()
- s =@= b = liftIO $ assertBool s b
- matchKeys :: (Show record, Show (Key record), MonadIO m, Eq (Key record))
- => String -> [Key record] -> [Entity record] -> m ()
- matchKeys s ys xs = do
- msg1 =@= (xLen == yLen)
- forM_ ys $ \y -> msg2 y =@= (y `elem` ks)
- where ks = entityKey <$> xs
- xLen = length xs
- yLen = length ys
- msg1 = mconcat
- [ s, "\nexpected: ", show yLen
- , "\n but got: ", show xLen
- , "\n[xs: ", show xs
- , ", ys: ", show ys, "]"
- ]
- msg2 y = mconcat
- [ s, ": "
- , "key \"", show y
- , "\" not in result:\n ", show ks
- ]
- specs :: Spec
- specs = describe "postgresql's JSON operators behave" $ do
- it "migrate, clean table, insert values and check queries" $ asIO $ runConn $ do
- runMigration jsonTestMigrate
- cleanDB
- liftIO $ putStrLn "\n- - - - - Inserting JSON values - - - - -\n"
- 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"]]
- objNullK <- insert' $ Object mempty
- objTestK <- insert' $ object ["test" .= Null, "test1" .= String "no"]
- objDeepK <- insert' $ object ["c" .= Number 24.986, "foo" .= object ["deep1" .= Bool True]]
- ----------------------------------------------------------------------------------------
- liftIO $ putStrLn "\n- - - - - Starting @> tests - - - - -\n"
- -- An empty Object matches any object
- selectList [TestValueJson @>. Object mempty] []
- >>= matchKeys "1" [objNullK,objTestK,objDeepK]
- -- {"test":null,"test1":"no"} @> {"test":null} == True
- selectList [TestValueJson @>. object ["test" .= Null]] []
- >>= matchKeys "2" [objTestK]
- -- {"c":24.986,"foo":{"deep1":true"}} @> {"foo":{}} == True
- selectList [TestValueJson @>. object ["foo" .= object []]] []
- >>= matchKeys "3" [objDeepK]
- -- {"c":24.986,"foo":{"deep1":true"}} @> {"foo":"nope"} == False
- selectList [TestValueJson @>. object ["foo" .= String "nope"]] []
- >>= matchKeys "4" []
- -- {"c":24.986,"foo":{"deep1":true"}} @> {"foo":{"deep1":true}} == True
- selectList [TestValueJson @>. (object ["foo" .= object ["deep1" .= True]])] []
- >>= matchKeys "5" [objDeepK]
- -- {"c":24.986,"foo":{"deep1":true"}} @> {"deep1":true} == False
- selectList [TestValueJson @>. object ["deep1" .= True]] []
- >>= matchKeys "6" []
- -- An empty Array matches any array
- selectList [TestValueJson @>. emptyArr] []
- >>= matchKeys "7" [arrNullK,arrListK,arrList2K,arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [4] == True
- selectList [TestValueJson @>. toJSON [4 :: Int]] []
- >>= matchKeys "8" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [null,"b"] == True
- selectList [TestValueJson @>. toJSON [Null, String "b"]] []
- >>= matchKeys "9" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [null,"d"] == False
- selectList [TestValueJson @>. toJSON [emptyArr, String "d"]] []
- >>= matchKeys "10" []
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [[],"b",{"test":[null],"test2":"yes"},4,null,{}] == True
- selectList [TestValueJson @>. toJSON [emptyArr, String "b", object [ "test" .= [Null], "test2" .= String "yes"], Number 4, Null, Object mempty]] []
- >>= matchKeys "11" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == False
- selectList [TestValueJson @>. toJSON [Null, Number 4, String "b", Object mempty, emptyArr, object [ "test" .= [Null], "test2" .= String "yes"], Bool False]] []
- >>= matchKeys "12" []
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [{}] == True
- selectList [TestValueJson @>. toJSON [Object mempty]] []
- >>= matchKeys "13" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [{"test":[]}] == True
- selectList [TestValueJson @>. toJSON [object ["test" .= emptyArr]]] []
- >>= matchKeys "14" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [{"test1":[null]}] == False
- selectList [TestValueJson @>. toJSON [object ["test1" .= [Null]]]] []
- >>= matchKeys "15" []
- -- [[],[],[[],[]]] @> [[]] == True
- -- [[],[3,false],[[],[{}]]] @> [[]] == True
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [[]] == True
- selectList [TestValueJson @>. toJSON [emptyArr]] []
- >>= matchKeys "16" [arrListK,arrList2K,arrFilledK]
- -- [[],[3,false],[[],[{}]]] @> [[3]] == True
- selectList [TestValueJson @>. toJSON [[3 :: Int]]] []
- >>= matchKeys "17" [arrList2K]
- -- [[],[3,false],[[],[{}]]] @> [[true,3]] == False
- selectList [TestValueJson @>. toJSON [[Bool True, Number 3]]] []
- >>= matchKeys "18" []
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> 4 == True
- selectList [TestValueJson @>. Number 4] []
- >>= matchKeys "19" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> 4 == True
- selectList [TestValueJson @>. Number 99] []
- >>= matchKeys "20" []
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> "b" == True
- selectList [TestValueJson @>. String "b"] []
- >>= matchKeys "21" [arrFilledK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> "{}" == False
- selectList [TestValueJson @>. String "{}"] []
- >>= matchKeys "22" [strObjK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> {"test":[null],"test2":"yes"} == False
- selectList [TestValueJson @>. object [ "test" .= [Null], "test2" .= String "yes"]] []
- >>= matchKeys "23" []
- -- "testing" @> "testing" == True
- selectList [TestValueJson @>. String "testing"] []
- >>= matchKeys "24" [strTestK]
- -- "testing" @> "Testing" == False
- selectList [TestValueJson @>. String "Testing"] []
- >>= matchKeys "25" []
- -- "testing" @> "test" == False
- selectList [TestValueJson @>. String "test"] []
- >>= matchKeys "26" []
- -- "testing" @> {"testing":1} == False
- selectList [TestValueJson @>. object ["testing" .= Number 1]] []
- >>= matchKeys "27" []
- -- 1 @> 1 == True
- selectList [TestValueJson @>. toJSON (1 :: Int)] []
- >>= matchKeys "28" [num1K]
- -- 0 @> 0.0 == True
- -- 0.0 @> 0.0 == True
- selectList [TestValueJson @>. toJSON (0.0 :: Double)] []
- >>= matchKeys "29" [num0K,numFloatK]
- -- 1234567890 @> 123456789 == False
- selectList [TestValueJson @>. toJSON (123456789 :: Int)] []
- >>= matchKeys "30" []
- -- 1234567890 @> 234567890 == False
- selectList [TestValueJson @>. toJSON (234567890 :: Int)] []
- >>= matchKeys "31" []
- -- 1 @> "1" == False
- selectList [TestValueJson @>. String "1"] []
- >>= matchKeys "32" []
- -- 1234567890 @> [1,2,3,4,5,6,7,8,9,0] == False
- selectList [TestValueJson @>. toJSON ([1,2,3,4,5,6,7,8,9,0] :: [Int])] []
- >>= matchKeys "33" []
- -- true @> true == True
- -- false @> true == False
- selectList [TestValueJson @>. toJSON True] []
- >>= matchKeys "34" [boolTK]
- -- false @> false == True
- -- true @> false == False
- selectList [TestValueJson @>. Bool False] []
- >>= matchKeys "35" [boolFK]
- -- true @> "true" == False
- selectList [TestValueJson @>. String "true"] []
- >>= matchKeys "36" []
- -- null @> null == True
- selectList [TestValueJson @>. Null] []
- >>= matchKeys "37" [nullK,arrFilledK]
- -- null @> "null" == False
- selectList [TestValueJson @>. String "null"] []
- >>= matchKeys "38" []
- ----------------------------------------------------------------------------------------
- liftIO $ putStrLn "\n- - - - - Starting <@ tests - - - - -\n"
- -- {} <@ {"test":null,"test1":"no","blabla":[]} == True
- -- {"test":null,"test1":"no"} <@ {"test":null,"test1":"no","blabla":[]} == True
- selectList [TestValueJson <@. object ["test" .= Null, "test1" .= String "no", "blabla" .= emptyArr]] []
- >>= matchKeys "39" [objNullK,objTestK]
- -- [] <@ [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
- selectList [TestValueJson <@. toJSON [Null, Number 4, String "b", Object mempty, emptyArr, object [ "test" .= [Null], "test2" .= String "yes"], Bool False]] []
- >>= matchKeys "40" [arrNullK,arrFilledK,boolFK,nullK]
- -- "a" <@ "a" == True
- selectList [TestValueJson <@. String "a"] []
- >>= matchKeys "41" [strAK]
- -- 9876543210.123457 <@ 9876543210.123457 == False
- selectList [TestValueJson <@. Number 9876543210.123457] []
- >>= matchKeys "42" [numBigFloatK]
- -- 9876543210.123457 <@ 9876543210.123456789 == False
- selectList [TestValueJson <@. Number 9876543210.123456789] []
- >>= matchKeys "43" []
- -- null <@ null == True
- selectList [TestValueJson <@. Null] []
- >>= matchKeys "44" [nullK]
- ----------------------------------------------------------------------------------------
- liftIO $ putStrLn "\n- - - - - Starting ? tests - - - - -\n"
- arrList3K <- insert' $ toJSON [toJSON [String "a"], Number 1]
- arrList4K <- insert' $ toJSON [String "a", String "b", String "c", String "d"]
- objEmptyK <- insert' $ object ["" .= Number 9001]
- objFullK <- insert' $ object ["a" .= Number 1, "b" .= Number 2, "c" .= Number 3, "d" .= Number 4]
- -- {"test":null,"test1":"no"} ? "test" == True
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ? "test" == False
- selectList [TestValueJson ?. "test"] []
- >>= matchKeys "45" [objTestK]
- -- {"c":24.986,"foo":{"deep1":true"}} ? "deep1" == False
- selectList [TestValueJson ?. "deep1"] []
- >>= matchKeys "46" []
- -- "{}" ? "{}" == True
- -- {} ? "{}" == False
- selectList [TestValueJson ?. "{}"] []
- >>= matchKeys "47" [strObjK]
- -- {} ? "" == False
- -- "" ? "" == True
- -- {"":9001} ? "" == True
- selectList [TestValueJson ?. ""] []
- >>= matchKeys "48" [strNullK,objEmptyK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ? "b" == True
- selectList [TestValueJson ?. "b"] []
- >>= matchKeys "49" [arrFilledK,arrList4K,objFullK]
- -- [["a"]] ? "a" == False
- -- "a" ? "a" == True
- -- ["a","b","c","d"] ? "a" == True
- -- {"a":1,"b":2,"c":3,"d":4} ? "a" == True
- selectList [TestValueJson ?. "a"] []
- >>= matchKeys "50" [strAK,arrList4K,objFullK]
- -- "[]" ? "[]" == True
- -- [] ? "[]" == False
- selectList [TestValueJson ?. "[]"] []
- >>= matchKeys "51" [strArrK]
- -- null ? "null" == False
- selectList [TestValueJson ?. "null"] []
- >>= matchKeys "52" []
- -- true ? "true" == False
- selectList [TestValueJson ?. "true"] []
- >>= matchKeys "53" []
- ----------------------------------------------------------------------------------------
- liftIO $ putStrLn "\n- - - - - Starting ?| tests - - - - -\n"
- -- "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
- selectList [TestValueJson ?|. ["a","b","c"]] []
- >>= matchKeys "54" [strAK,arrFilledK,objDeepK,arrList4K,objFullK]
- -- "{}" ?| ["{}"] == True
- -- {} ?| ["{}"] == False
- selectList [TestValueJson ?|. ["{}"]] []
- >>= matchKeys "55" [strObjK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?| ["test"] == False
- -- "testing" ?| ["test"] == False
- -- {"test":null,"test1":"no"} ?| ["test"] == True
- selectList [TestValueJson ?|. ["test"]] []
- >>= matchKeys "56" [objTestK]
- -- {"c":24.986,"foo":{"deep1":true"}} ?| ["deep1"] == False
- selectList [TestValueJson ?|. ["deep1"]] []
- >>= matchKeys "57" []
- -- ANYTHING ?| [] == False
- selectList [TestValueJson ?|. []] []
- >>= matchKeys "58" []
- -- true ?| ["true","null","1"] == False
- -- null ?| ["true","null","1"] == False
- -- 1 ?| ["true","null","1"] == False
- selectList [TestValueJson ?|. ["true","null","1"]] []
- >>= matchKeys "59" []
- -- [] ?| ["[]"] == False
- -- "[]" ?| ["[]"] == True
- selectList [TestValueJson ?|. ["[]"]] []
- >>= matchKeys "60" [strArrK]
- ----------------------------------------------------------------------------------------
- liftIO $ putStrLn "\n- - - - - Starting ?& tests - - - - -\n"
- -- ANYTHING ?& [] == True
- selectList [TestValueJson ?&. []] []
- >>= matchKeys "61" [ nullK
- , boolTK, boolFK
- , num0K, num1K, numBigK, numFloatK, numSmallK, numFloat2K, numBigFloatK
- , strNullK, strObjK, strArrK, strAK, strTestK, str2K, strFloatK
- , arrNullK, arrListK, arrList2K, arrFilledK
- , objNullK, objTestK, objDeepK
- , arrList3K, arrList4K
- , objEmptyK, objFullK
- ]
- -- "a" ?& ["a"] == True
- -- [["a"],1] ?& ["a"] == False
- -- ["a","b","c","d"] ?& ["a"] == True
- -- {"a":1,"b":2,"c":3,"d":4} ?& ["a"] == True
- selectList [TestValueJson ?&. ["a"]] []
- >>= matchKeys "62" [strAK,arrList4K,objFullK]
- -- [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
- selectList [TestValueJson ?&. ["b","c"]] []
- >>= matchKeys "63" [arrList4K,objFullK]
- -- {} ?& ["{}"] == False
- -- "{}" ?& ["{}"] == True
- selectList [TestValueJson ?&. ["{}"]] []
- >>= matchKeys "64" [strObjK]
- -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?& ["test"] == False
- -- "testing" ?& ["test"] == False
- -- {"test":null,"test1":"no"} ?& ["test"] == True
- selectList [TestValueJson ?&. ["test"]] []
- >>= matchKeys "65" [objTestK]
- -- {"c":24.986,"foo":{"deep1":true"}} ?& ["deep1"] == False
- selectList [TestValueJson ?&. ["deep1"]] []
- >>= matchKeys "66" []
- -- "a" ?& ["a","e"] == False
- -- ["a","b","c","d"] ?& ["a","e"] == False
- -- {"a":1,"b":2,"c":3,"d":4} ?& ["a","e"] == False
- selectList [TestValueJson ?&. ["a","e"]] []
- >>= matchKeys "67" []
- -- [] ?& ["[]"] == False
- -- "[]" ?& ["[]"] == True
- selectList [TestValueJson ?&. ["[]"]] []
- >>= matchKeys "68" [strArrK]
- -- THIS WILL FAIL IF THE IMPLEMENTATION USES
- -- @ '{null}' @
- -- INSTEAD OF
- -- @ ARRAY['null'] @
- -- null ?& ["null"] == False
- selectList [TestValueJson ?&. ["null"]] []
- >>= matchKeys "69" []
- -- [["a"],1] ?& ["1"] == False
- -- "1" ?& ["1"] == True
- selectList [TestValueJson ?&. ["1"]] []
- >>= matchKeys "70" []
- -- {} ?& [""] == False
- -- [] ?& [""] == False
- -- "" ?& [""] == True
- -- {"":9001} ?& [""] == True
- selectList [TestValueJson ?&. [""]] []
- >>= matchKeys "71" [strNullK,objEmptyK]
|