JSONTest.hs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. {-# LANGUAGE ExistentialQuantification #-}
  2. {-# LANGUAGE FlexibleContexts #-}
  3. {-# LANGUAGE FlexibleInstances #-}
  4. {-# LANGUAGE MultiParamTypeClasses #-}
  5. {-# LANGUAGE OverloadedStrings #-}
  6. {-# LANGUAGE QuasiQuotes #-}
  7. {-# LANGUAGE TemplateHaskell #-}
  8. {-# LANGUAGE TypeFamilies #-}
  9. {-# LANGUAGE UndecidableInstances #-} -- FIXME
  10. module JSONTest where
  11. import Control.Monad.IO.Class (MonadIO)
  12. import Data.Aeson
  13. import qualified Data.Vector as V (fromList)
  14. import Test.HUnit (assertBool)
  15. import Test.Hspec.Expectations ()
  16. import Database.Persist
  17. import Database.Persist.Postgresql.JSON
  18. import PgInit
  19. share [mkPersist persistSettings, mkMigrate "jsonTestMigrate"] [persistLowerCase|
  20. TestValue
  21. json Value
  22. deriving Show
  23. |]
  24. cleanDB :: (BaseBackend backend ~ SqlBackend, PersistQueryWrite backend, MonadIO m) => ReaderT backend m ()
  25. cleanDB = deleteWhere ([] :: [Filter TestValue])
  26. emptyArr :: Value
  27. emptyArr = toJSON ([] :: [Value])
  28. insert' :: (MonadIO m, PersistStoreWrite backend, BaseBackend backend ~ SqlBackend)
  29. => Value -> ReaderT backend m (Key TestValue)
  30. insert' = insert . TestValue
  31. (=@=) :: MonadIO m => String -> Bool -> m ()
  32. s =@= b = liftIO $ assertBool s b
  33. matchKeys :: (Show record, Show (Key record), MonadIO m, Eq (Key record))
  34. => String -> [Key record] -> [Entity record] -> m ()
  35. matchKeys s ys xs = do
  36. msg1 =@= (xLen == yLen)
  37. forM_ ys $ \y -> msg2 y =@= (y `elem` ks)
  38. where ks = entityKey <$> xs
  39. xLen = length xs
  40. yLen = length ys
  41. msg1 = mconcat
  42. [ s, "\nexpected: ", show yLen
  43. , "\n but got: ", show xLen
  44. , "\n[xs: ", show xs
  45. , ", ys: ", show ys, "]"
  46. ]
  47. msg2 y = mconcat
  48. [ s, ": "
  49. , "key \"", show y
  50. , "\" not in result:\n ", show ks
  51. ]
  52. specs :: Spec
  53. specs = describe "postgresql's JSON operators behave" $ do
  54. it "migrate, clean table, insert values and check queries" $ asIO $ runConn $ do
  55. runMigration jsonTestMigrate
  56. cleanDB
  57. liftIO $ putStrLn "\n- - - - - Inserting JSON values - - - - -\n"
  58. nullK <- insert' Null
  59. boolTK <- insert' $ Bool True
  60. boolFK <- insert' $ toJSON False
  61. num0K <- insert' $ Number 0
  62. num1K <- insert' $ Number 1
  63. numBigK <- insert' $ toJSON (1234567890 :: Int)
  64. numFloatK <- insert' $ Number 0.0
  65. numSmallK <- insert' $ Number 0.0000000000000000123
  66. numFloat2K <- insert' $ Number 1.5
  67. -- numBigFloatK will turn into 9876543210.123457 because JSON
  68. numBigFloatK <- insert' $ toJSON (9876543210.123456789 :: Double)
  69. strNullK <- insert' $ String ""
  70. strObjK <- insert' $ String "{}"
  71. strArrK <- insert' $ String "[]"
  72. strAK <- insert' $ String "a"
  73. strTestK <- insert' $ toJSON ("testing" :: Text)
  74. str2K <- insert' $ String "2"
  75. strFloatK <- insert' $ String "0.45876"
  76. arrNullK <- insert' $ Array $ V.fromList []
  77. arrListK <- insert' $ toJSON ([emptyArr,emptyArr,toJSON [emptyArr,emptyArr]])
  78. arrList2K <- insert' $ toJSON [emptyArr,toJSON [Number 3,Bool False],toJSON [emptyArr,toJSON [Object mempty]]]
  79. arrFilledK <- insert' $ toJSON [Null, Number 4, String "b", Object mempty, emptyArr, object [ "test" .= [Null], "test2" .= String "yes"]]
  80. objNullK <- insert' $ Object mempty
  81. objTestK <- insert' $ object ["test" .= Null, "test1" .= String "no"]
  82. objDeepK <- insert' $ object ["c" .= Number 24.986, "foo" .= object ["deep1" .= Bool True]]
  83. ----------------------------------------------------------------------------------------
  84. liftIO $ putStrLn "\n- - - - - Starting @> tests - - - - -\n"
  85. -- An empty Object matches any object
  86. selectList [TestValueJson @>. Object mempty] []
  87. >>= matchKeys "1" [objNullK,objTestK,objDeepK]
  88. -- {"test":null,"test1":"no"} @> {"test":null} == True
  89. selectList [TestValueJson @>. object ["test" .= Null]] []
  90. >>= matchKeys "2" [objTestK]
  91. -- {"c":24.986,"foo":{"deep1":true"}} @> {"foo":{}} == True
  92. selectList [TestValueJson @>. object ["foo" .= object []]] []
  93. >>= matchKeys "3" [objDeepK]
  94. -- {"c":24.986,"foo":{"deep1":true"}} @> {"foo":"nope"} == False
  95. selectList [TestValueJson @>. object ["foo" .= String "nope"]] []
  96. >>= matchKeys "4" []
  97. -- {"c":24.986,"foo":{"deep1":true"}} @> {"foo":{"deep1":true}} == True
  98. selectList [TestValueJson @>. (object ["foo" .= object ["deep1" .= True]])] []
  99. >>= matchKeys "5" [objDeepK]
  100. -- {"c":24.986,"foo":{"deep1":true"}} @> {"deep1":true} == False
  101. selectList [TestValueJson @>. object ["deep1" .= True]] []
  102. >>= matchKeys "6" []
  103. -- An empty Array matches any array
  104. selectList [TestValueJson @>. emptyArr] []
  105. >>= matchKeys "7" [arrNullK,arrListK,arrList2K,arrFilledK]
  106. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [4] == True
  107. selectList [TestValueJson @>. toJSON [4 :: Int]] []
  108. >>= matchKeys "8" [arrFilledK]
  109. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [null,"b"] == True
  110. selectList [TestValueJson @>. toJSON [Null, String "b"]] []
  111. >>= matchKeys "9" [arrFilledK]
  112. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [null,"d"] == False
  113. selectList [TestValueJson @>. toJSON [emptyArr, String "d"]] []
  114. >>= matchKeys "10" []
  115. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [[],"b",{"test":[null],"test2":"yes"},4,null,{}] == True
  116. selectList [TestValueJson @>. toJSON [emptyArr, String "b", object [ "test" .= [Null], "test2" .= String "yes"], Number 4, Null, Object mempty]] []
  117. >>= matchKeys "11" [arrFilledK]
  118. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == False
  119. selectList [TestValueJson @>. toJSON [Null, Number 4, String "b", Object mempty, emptyArr, object [ "test" .= [Null], "test2" .= String "yes"], Bool False]] []
  120. >>= matchKeys "12" []
  121. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [{}] == True
  122. selectList [TestValueJson @>. toJSON [Object mempty]] []
  123. >>= matchKeys "13" [arrFilledK]
  124. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [{"test":[]}] == True
  125. selectList [TestValueJson @>. toJSON [object ["test" .= emptyArr]]] []
  126. >>= matchKeys "14" [arrFilledK]
  127. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [{"test1":[null]}] == False
  128. selectList [TestValueJson @>. toJSON [object ["test1" .= [Null]]]] []
  129. >>= matchKeys "15" []
  130. -- [[],[],[[],[]]] @> [[]] == True
  131. -- [[],[3,false],[[],[{}]]] @> [[]] == True
  132. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> [[]] == True
  133. selectList [TestValueJson @>. toJSON [emptyArr]] []
  134. >>= matchKeys "16" [arrListK,arrList2K,arrFilledK]
  135. -- [[],[3,false],[[],[{}]]] @> [[3]] == True
  136. selectList [TestValueJson @>. toJSON [[3 :: Int]]] []
  137. >>= matchKeys "17" [arrList2K]
  138. -- [[],[3,false],[[],[{}]]] @> [[true,3]] == False
  139. selectList [TestValueJson @>. toJSON [[Bool True, Number 3]]] []
  140. >>= matchKeys "18" []
  141. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> 4 == True
  142. selectList [TestValueJson @>. Number 4] []
  143. >>= matchKeys "19" [arrFilledK]
  144. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> 4 == True
  145. selectList [TestValueJson @>. Number 99] []
  146. >>= matchKeys "20" []
  147. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> "b" == True
  148. selectList [TestValueJson @>. String "b"] []
  149. >>= matchKeys "21" [arrFilledK]
  150. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> "{}" == False
  151. selectList [TestValueJson @>. String "{}"] []
  152. >>= matchKeys "22" [strObjK]
  153. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] @> {"test":[null],"test2":"yes"} == False
  154. selectList [TestValueJson @>. object [ "test" .= [Null], "test2" .= String "yes"]] []
  155. >>= matchKeys "23" []
  156. -- "testing" @> "testing" == True
  157. selectList [TestValueJson @>. String "testing"] []
  158. >>= matchKeys "24" [strTestK]
  159. -- "testing" @> "Testing" == False
  160. selectList [TestValueJson @>. String "Testing"] []
  161. >>= matchKeys "25" []
  162. -- "testing" @> "test" == False
  163. selectList [TestValueJson @>. String "test"] []
  164. >>= matchKeys "26" []
  165. -- "testing" @> {"testing":1} == False
  166. selectList [TestValueJson @>. object ["testing" .= Number 1]] []
  167. >>= matchKeys "27" []
  168. -- 1 @> 1 == True
  169. selectList [TestValueJson @>. toJSON (1 :: Int)] []
  170. >>= matchKeys "28" [num1K]
  171. -- 0 @> 0.0 == True
  172. -- 0.0 @> 0.0 == True
  173. selectList [TestValueJson @>. toJSON (0.0 :: Double)] []
  174. >>= matchKeys "29" [num0K,numFloatK]
  175. -- 1234567890 @> 123456789 == False
  176. selectList [TestValueJson @>. toJSON (123456789 :: Int)] []
  177. >>= matchKeys "30" []
  178. -- 1234567890 @> 234567890 == False
  179. selectList [TestValueJson @>. toJSON (234567890 :: Int)] []
  180. >>= matchKeys "31" []
  181. -- 1 @> "1" == False
  182. selectList [TestValueJson @>. String "1"] []
  183. >>= matchKeys "32" []
  184. -- 1234567890 @> [1,2,3,4,5,6,7,8,9,0] == False
  185. selectList [TestValueJson @>. toJSON ([1,2,3,4,5,6,7,8,9,0] :: [Int])] []
  186. >>= matchKeys "33" []
  187. -- true @> true == True
  188. -- false @> true == False
  189. selectList [TestValueJson @>. toJSON True] []
  190. >>= matchKeys "34" [boolTK]
  191. -- false @> false == True
  192. -- true @> false == False
  193. selectList [TestValueJson @>. Bool False] []
  194. >>= matchKeys "35" [boolFK]
  195. -- true @> "true" == False
  196. selectList [TestValueJson @>. String "true"] []
  197. >>= matchKeys "36" []
  198. -- null @> null == True
  199. selectList [TestValueJson @>. Null] []
  200. >>= matchKeys "37" [nullK,arrFilledK]
  201. -- null @> "null" == False
  202. selectList [TestValueJson @>. String "null"] []
  203. >>= matchKeys "38" []
  204. ----------------------------------------------------------------------------------------
  205. liftIO $ putStrLn "\n- - - - - Starting <@ tests - - - - -\n"
  206. -- {} <@ {"test":null,"test1":"no","blabla":[]} == True
  207. -- {"test":null,"test1":"no"} <@ {"test":null,"test1":"no","blabla":[]} == True
  208. selectList [TestValueJson <@. object ["test" .= Null, "test1" .= String "no", "blabla" .= emptyArr]] []
  209. >>= matchKeys "39" [objNullK,objTestK]
  210. -- [] <@ [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
  211. -- null <@ [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
  212. -- false <@ [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
  213. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] <@ [null,4,"b",{},[],{"test":[null],"test2":"yes"},false] == True
  214. selectList [TestValueJson <@. toJSON [Null, Number 4, String "b", Object mempty, emptyArr, object [ "test" .= [Null], "test2" .= String "yes"], Bool False]] []
  215. >>= matchKeys "40" [arrNullK,arrFilledK,boolFK,nullK]
  216. -- "a" <@ "a" == True
  217. selectList [TestValueJson <@. String "a"] []
  218. >>= matchKeys "41" [strAK]
  219. -- 9876543210.123457 <@ 9876543210.123457 == False
  220. selectList [TestValueJson <@. Number 9876543210.123457] []
  221. >>= matchKeys "42" [numBigFloatK]
  222. -- 9876543210.123457 <@ 9876543210.123456789 == False
  223. selectList [TestValueJson <@. Number 9876543210.123456789] []
  224. >>= matchKeys "43" []
  225. -- null <@ null == True
  226. selectList [TestValueJson <@. Null] []
  227. >>= matchKeys "44" [nullK]
  228. ----------------------------------------------------------------------------------------
  229. liftIO $ putStrLn "\n- - - - - Starting ? tests - - - - -\n"
  230. arrList3K <- insert' $ toJSON [toJSON [String "a"], Number 1]
  231. arrList4K <- insert' $ toJSON [String "a", String "b", String "c", String "d"]
  232. objEmptyK <- insert' $ object ["" .= Number 9001]
  233. objFullK <- insert' $ object ["a" .= Number 1, "b" .= Number 2, "c" .= Number 3, "d" .= Number 4]
  234. -- {"test":null,"test1":"no"} ? "test" == True
  235. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ? "test" == False
  236. selectList [TestValueJson ?. "test"] []
  237. >>= matchKeys "45" [objTestK]
  238. -- {"c":24.986,"foo":{"deep1":true"}} ? "deep1" == False
  239. selectList [TestValueJson ?. "deep1"] []
  240. >>= matchKeys "46" []
  241. -- "{}" ? "{}" == True
  242. -- {} ? "{}" == False
  243. selectList [TestValueJson ?. "{}"] []
  244. >>= matchKeys "47" [strObjK]
  245. -- {} ? "" == False
  246. -- "" ? "" == True
  247. -- {"":9001} ? "" == True
  248. selectList [TestValueJson ?. ""] []
  249. >>= matchKeys "48" [strNullK,objEmptyK]
  250. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ? "b" == True
  251. selectList [TestValueJson ?. "b"] []
  252. >>= matchKeys "49" [arrFilledK,arrList4K,objFullK]
  253. -- [["a"]] ? "a" == False
  254. -- "a" ? "a" == True
  255. -- ["a","b","c","d"] ? "a" == True
  256. -- {"a":1,"b":2,"c":3,"d":4} ? "a" == True
  257. selectList [TestValueJson ?. "a"] []
  258. >>= matchKeys "50" [strAK,arrList4K,objFullK]
  259. -- "[]" ? "[]" == True
  260. -- [] ? "[]" == False
  261. selectList [TestValueJson ?. "[]"] []
  262. >>= matchKeys "51" [strArrK]
  263. -- null ? "null" == False
  264. selectList [TestValueJson ?. "null"] []
  265. >>= matchKeys "52" []
  266. -- true ? "true" == False
  267. selectList [TestValueJson ?. "true"] []
  268. >>= matchKeys "53" []
  269. ----------------------------------------------------------------------------------------
  270. liftIO $ putStrLn "\n- - - - - Starting ?| tests - - - - -\n"
  271. -- "a" ?| ["a","b","c"] == True
  272. -- [["a"],1] ?| ["a","b","c"] == False
  273. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?| ["a","b","c"] == True
  274. -- ["a","b","c","d"] ?| ["a","b","c"] == True
  275. -- {"a":1,"b":2,"c":3,"d":4} ?| ["a","b","c"] == True
  276. selectList [TestValueJson ?|. ["a","b","c"]] []
  277. >>= matchKeys "54" [strAK,arrFilledK,objDeepK,arrList4K,objFullK]
  278. -- "{}" ?| ["{}"] == True
  279. -- {} ?| ["{}"] == False
  280. selectList [TestValueJson ?|. ["{}"]] []
  281. >>= matchKeys "55" [strObjK]
  282. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?| ["test"] == False
  283. -- "testing" ?| ["test"] == False
  284. -- {"test":null,"test1":"no"} ?| ["test"] == True
  285. selectList [TestValueJson ?|. ["test"]] []
  286. >>= matchKeys "56" [objTestK]
  287. -- {"c":24.986,"foo":{"deep1":true"}} ?| ["deep1"] == False
  288. selectList [TestValueJson ?|. ["deep1"]] []
  289. >>= matchKeys "57" []
  290. -- ANYTHING ?| [] == False
  291. selectList [TestValueJson ?|. []] []
  292. >>= matchKeys "58" []
  293. -- true ?| ["true","null","1"] == False
  294. -- null ?| ["true","null","1"] == False
  295. -- 1 ?| ["true","null","1"] == False
  296. selectList [TestValueJson ?|. ["true","null","1"]] []
  297. >>= matchKeys "59" []
  298. -- [] ?| ["[]"] == False
  299. -- "[]" ?| ["[]"] == True
  300. selectList [TestValueJson ?|. ["[]"]] []
  301. >>= matchKeys "60" [strArrK]
  302. ----------------------------------------------------------------------------------------
  303. liftIO $ putStrLn "\n- - - - - Starting ?& tests - - - - -\n"
  304. -- ANYTHING ?& [] == True
  305. selectList [TestValueJson ?&. []] []
  306. >>= matchKeys "61" [ nullK
  307. , boolTK, boolFK
  308. , num0K, num1K, numBigK, numFloatK, numSmallK, numFloat2K, numBigFloatK
  309. , strNullK, strObjK, strArrK, strAK, strTestK, str2K, strFloatK
  310. , arrNullK, arrListK, arrList2K, arrFilledK
  311. , objNullK, objTestK, objDeepK
  312. , arrList3K, arrList4K
  313. , objEmptyK, objFullK
  314. ]
  315. -- "a" ?& ["a"] == True
  316. -- [["a"],1] ?& ["a"] == False
  317. -- ["a","b","c","d"] ?& ["a"] == True
  318. -- {"a":1,"b":2,"c":3,"d":4} ?& ["a"] == True
  319. selectList [TestValueJson ?&. ["a"]] []
  320. >>= matchKeys "62" [strAK,arrList4K,objFullK]
  321. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?& ["b","c"] == False
  322. -- {"c":24.986,"foo":{"deep1":true"}} ?& ["b","c"] == False
  323. -- ["a","b","c","d"] ?& ["b","c"] == True
  324. -- {"a":1,"b":2,"c":3,"d":4} ?& ["b","c"] == True
  325. selectList [TestValueJson ?&. ["b","c"]] []
  326. >>= matchKeys "63" [arrList4K,objFullK]
  327. -- {} ?& ["{}"] == False
  328. -- "{}" ?& ["{}"] == True
  329. selectList [TestValueJson ?&. ["{}"]] []
  330. >>= matchKeys "64" [strObjK]
  331. -- [null,4,"b",{},[],{"test":[null],"test2":"yes"}] ?& ["test"] == False
  332. -- "testing" ?& ["test"] == False
  333. -- {"test":null,"test1":"no"} ?& ["test"] == True
  334. selectList [TestValueJson ?&. ["test"]] []
  335. >>= matchKeys "65" [objTestK]
  336. -- {"c":24.986,"foo":{"deep1":true"}} ?& ["deep1"] == False
  337. selectList [TestValueJson ?&. ["deep1"]] []
  338. >>= matchKeys "66" []
  339. -- "a" ?& ["a","e"] == False
  340. -- ["a","b","c","d"] ?& ["a","e"] == False
  341. -- {"a":1,"b":2,"c":3,"d":4} ?& ["a","e"] == False
  342. selectList [TestValueJson ?&. ["a","e"]] []
  343. >>= matchKeys "67" []
  344. -- [] ?& ["[]"] == False
  345. -- "[]" ?& ["[]"] == True
  346. selectList [TestValueJson ?&. ["[]"]] []
  347. >>= matchKeys "68" [strArrK]
  348. -- THIS WILL FAIL IF THE IMPLEMENTATION USES
  349. -- @ '{null}' @
  350. -- INSTEAD OF
  351. -- @ ARRAY['null'] @
  352. -- null ?& ["null"] == False
  353. selectList [TestValueJson ?&. ["null"]] []
  354. >>= matchKeys "69" []
  355. -- [["a"],1] ?& ["1"] == False
  356. -- "1" ?& ["1"] == True
  357. selectList [TestValueJson ?&. ["1"]] []
  358. >>= matchKeys "70" []
  359. -- {} ?& [""] == False
  360. -- [] ?& [""] == False
  361. -- "" ?& [""] == True
  362. -- {"":9001} ?& [""] == True
  363. selectList [TestValueJson ?&. [""]] []
  364. >>= matchKeys "71" [strNullK,objEmptyK]