Spec.hs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE QuasiQuotes #-}
  3. {-# LANGUAGE TypeFamilies #-}
  4. import Control.Monad.Logger
  5. import Control.Monad.Trans.Resource
  6. import Control.Monad.Reader
  7. import Data.List.NonEmpty (NonEmpty(..))
  8. import Data.Text (Text)
  9. import System.Log.FastLogger
  10. import Test.Hspec
  11. import Test.HUnit ((@?=))
  12. import UnliftIO
  13. import Database.Persist.Sql
  14. import Database.Persist.Sql.Raw.QQ
  15. import Database.Persist.Sqlite
  16. import PersistTestPetType
  17. import PersistentTestModels
  18. main :: IO ()
  19. main = hspec specs
  20. _debugOn :: Bool
  21. _debugOn = False
  22. sqlite_database_file :: Text
  23. sqlite_database_file = "testdb.sqlite3"
  24. sqlite_database :: SqliteConnectionInfo
  25. sqlite_database = mkSqliteConnectionInfo sqlite_database_file
  26. runConn :: MonadUnliftIO m => SqlPersistT (LoggingT m) t -> m ()
  27. runConn f = do
  28. let debugPrint = _debugOn
  29. let printDebug = if debugPrint then print . fromLogStr else void . return
  30. flip runLoggingT (\_ _ _ s -> printDebug s) $ do
  31. _ <- withSqlitePoolInfo sqlite_database 1 $ runSqlPool f
  32. return ()
  33. db :: SqlPersistT (LoggingT (ResourceT IO)) () -> IO ()
  34. db actions = do
  35. runResourceT $ runConn $ do
  36. runMigration testMigrate
  37. actions
  38. transactionUndo
  39. specs :: Spec
  40. specs = describe "persistent-qq" $ do
  41. it "sqlQQ/?-?" $ db $ do
  42. ret <- [sqlQQ| SELECT #{2 :: Int}+#{2 :: Int} |]
  43. liftIO $ ret @?= [Single (4::Int)]
  44. it "sqlQQ/?-?" $ db $ do
  45. ret <- [sqlQQ| SELECT #{5 :: Int}-#{3 :: Int} |]
  46. liftIO $ ret @?= [Single (2::Int)]
  47. it "sqlQQ/NULL" $ db $ do
  48. ret <- [sqlQQ| SELECT NULL |]
  49. liftIO $ ret @?= [Nothing :: Maybe (Single Int)]
  50. it "sqlQQ/entity" $ db $ do
  51. let insert'
  52. :: PersistStore backend
  53. => PersistEntity val
  54. => PersistEntityBackend val ~ BaseBackend backend
  55. => MonadIO m
  56. => val
  57. -> ReaderT backend m (Key val, val)
  58. insert' v = insert v >>= \k -> return (k, v)
  59. (p1k, p1) <- insert' $ Person "Mathias" 23 Nothing
  60. (p2k, p2) <- insert' $ Person "Norbert" 44 Nothing
  61. (p3k, _ ) <- insert' $ Person "Cassandra" 19 Nothing
  62. (_ , _ ) <- insert' $ Person "Thiago" 19 Nothing
  63. (a1k, a1) <- insert' $ Pet p1k "Rodolfo" Cat
  64. (a2k, a2) <- insert' $ Pet p1k "Zeno" Cat
  65. (a3k, a3) <- insert' $ Pet p2k "Lhama" Dog
  66. (_ , _ ) <- insert' $ Pet p3k "Abacate" Cat
  67. let runQuery
  68. :: (RawSql a, Functor m, MonadIO m)
  69. => Int
  70. -> ReaderT SqlBackend m [a]
  71. runQuery age =
  72. [sqlQQ|
  73. SELECT ??, ??
  74. FROM
  75. ^{Person},
  76. ^{Pet}
  77. WHERE ^{Person}.@{PersonAge} >= #{age}
  78. AND ^{Pet}.@{PetOwnerId} = ^{Person}.@{PersonId}
  79. ORDER BY ^{Person}.@{PersonName}
  80. |]
  81. ret <- runQuery 20
  82. liftIO $ ret @?= [ (Entity p1k p1, Entity a1k a1)
  83. , (Entity p1k p1, Entity a2k a2)
  84. , (Entity p2k p2, Entity a3k a3) ]
  85. ret2 <- runQuery 20
  86. liftIO $ ret2 @?= [ (Just (Entity p1k p1), Just (Entity a1k a1))
  87. , (Just (Entity p1k p1), Just (Entity a2k a2))
  88. , (Just (Entity p2k p2), Just (Entity a3k a3)) ]
  89. ret3 <- runQuery 20
  90. liftIO $ ret3 @?= [ Just (Entity p1k p1, Entity a1k a1)
  91. , Just (Entity p1k p1, Entity a2k a2)
  92. , Just (Entity p2k p2, Entity a3k a3) ]
  93. it "sqlQQ/order-proof" $ db $ do
  94. let p1 = Person "Zacarias" 93 Nothing
  95. p1k <- insert p1
  96. let runQuery
  97. :: (RawSql a, Functor m, MonadIO m)
  98. => ReaderT SqlBackend m [a]
  99. runQuery = [sqlQQ| SELECT ?? FROM ^{Person} |]
  100. ret1 <- runQuery
  101. ret2 <- runQuery :: (MonadIO m) => SqlPersistT m [Entity (ReverseFieldOrder Person)]
  102. liftIO $ ret1 @?= [Entity p1k p1]
  103. liftIO $ ret2 @?= [Entity (RFOKey $ unPersonKey p1k) (RFO p1)]
  104. it "sqlQQ/OUTER JOIN" $ db $ do
  105. let insert' :: (PersistStore backend, PersistEntity val, PersistEntityBackend val ~ BaseBackend backend, MonadIO m)
  106. => val -> ReaderT backend m (Key val, val)
  107. insert' v = insert v >>= \k -> return (k, v)
  108. (p1k, p1) <- insert' $ Person "Mathias" 23 Nothing
  109. (p2k, p2) <- insert' $ Person "Norbert" 44 Nothing
  110. (a1k, a1) <- insert' $ Pet p1k "Rodolfo" Cat
  111. (a2k, a2) <- insert' $ Pet p1k "Zeno" Cat
  112. ret <- [sqlQQ|
  113. SELECT ??, ??
  114. FROM ^{Person}
  115. LEFT OUTER JOIN ^{Pet}
  116. ON ^{Person}.@{PersonId} = ^{Pet}.@{PetOwnerId}
  117. ORDER BY ^{Person}.@{PersonName}
  118. |]
  119. liftIO $ ret @?= [ (Entity p1k p1, Just (Entity a1k a1))
  120. , (Entity p1k p1, Just (Entity a2k a2))
  121. , (Entity p2k p2, Nothing) ]
  122. it "sqlQQ/values syntax" $ db $ do
  123. let insert' :: (PersistStore backend, PersistEntity val, PersistEntityBackend val ~ BaseBackend backend, MonadIO m)
  124. => val -> ReaderT backend m (Key val, val)
  125. insert' v = insert v >>= \k -> return (k, v)
  126. (p1k, p1) <- insert' $ Person "Mathias" 23 (Just "red")
  127. (_ , _ ) <- insert' $ Person "Norbert" 44 (Just "green")
  128. (p3k, p3) <- insert' $ Person "Cassandra" 19 (Just "blue")
  129. (_ , _ ) <- insert' $ Person "Thiago" 19 (Just "yellow")
  130. let
  131. colors = Just "blue" :| Just "red" : [] :: NonEmpty (Maybe Text)
  132. ret <- [sqlQQ|
  133. SELECT ??
  134. FROM ^{Person}
  135. WHERE ^{Person}.@{PersonColor} IN %{colors}
  136. |]
  137. liftIO $ ret @?= [ (Entity p1k p1)
  138. , (Entity p3k p3) ]