File: Test.hs

package info (click to toggle)
haskell-esqueleto 3.6.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 732 kB
  • sloc: haskell: 9,857; makefile: 3
file content (164 lines) | stat: -rw-r--r-- 5,139 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

module SQLite.Test where

import Common.Test.Import hiding (from, on)

import Control.Monad (void)
import Control.Monad.Logger (runNoLoggingT, runStderrLoggingT)
import Database.Esqueleto.Legacy hiding (random_)
import Database.Esqueleto.SQLite (random_)
import Database.Persist.Sqlite (createSqlitePool)
import Database.Sqlite (SqliteException)

import Common.Test

testSqliteRandom :: SpecDb
testSqliteRandom = do
    itDb "works with random_" $ do
        _ <- select $ return (random_ :: SqlExpr (Value Int))
        asserting noExceptions

testSqliteSum :: SpecDb
testSqliteSum = do
    itDb "works with sum_" $ do
        _ <- insert' p1
        _ <- insert' p2
        _ <- insert' p3
        _ <- insert' p4
        ret <- select $
               from $ \p->
               return $ joinV $ sum_ (p ^. PersonAge)
        asserting $ ret `shouldBe` [ Value $ Just (36 + 17 + 17 :: Int) ]





testSqliteTwoAscFields :: SpecDb
testSqliteTwoAscFields = do
    itDb "works with two ASC fields (one call)" $ do
        p1e <- insert' p1
        p2e <- insert' p2
        p3e <- insert' p3
        p4e <- insert' p4
        ret <- select $
               from $ \p -> do
               orderBy [asc (p ^. PersonAge), asc (p ^. PersonName)]
               return p
        -- in SQLite and MySQL, its the reverse
        asserting $ ret `shouldBe` [ p2e, p4e, p3e, p1e ]

testSqliteOneAscOneDesc :: SpecDb
testSqliteOneAscOneDesc = do
    itDb "works with one ASC and one DESC field (two calls)" $ do
        p1e <- insert' p1
        p2e <- insert' p2
        p3e <- insert' p3
        p4e <- insert' p4
        ret <- select $
               from $ \p -> do
               orderBy [desc (p ^. PersonAge)]
               orderBy [asc (p ^. PersonName)]
               return p
        asserting $ ret `shouldBe` [ p1e, p4e, p3e, p2e ]

testSqliteCoalesce :: SpecDb
testSqliteCoalesce = do
    itDb "throws an exception on SQLite with <2 arguments" $ do
        eres <- try $ select $
               from $ \p -> do
               return (coalesce [p ^. PersonAge]) :: SqlQuery (SqlExpr (Value (Maybe Int)))
        asserting $ case eres of
            Left (_ :: SqliteException) ->
                pure ()
            Right _ ->
                expectationFailure "Expected SqliteException with <2 args to coalesce"

testSqliteUpdate :: SpecDb
testSqliteUpdate = do
    itDb "works on a simple example" $ do
        p1k <- insert p1
        p2k <- insert p2
        p3k <- insert p3
        let anon = "Anonymous" :: String
        ()  <- update $ \p -> do
               set p [ PersonName =. val anon
                     , PersonAge *=. just (val 2) ]
               where_ (p ^. PersonName !=. val "Mike")
        n   <- updateCount $ \p -> do
               set p [ PersonAge +=. just (val 1) ]
               where_ (p ^. PersonName !=. val "Mike")
        ret <- select $
               from $ \p -> do
               orderBy [ asc (p ^. PersonName), asc (p ^. PersonAge) ]
               return p
        -- SQLite: nulls appear first, update returns matched rows.
        asserting $ do
            n `shouldBe` 2
            ret `shouldMatchList`
                [ Entity p2k (Person anon Nothing (Just 37) 2)
                , Entity p1k (Person anon (Just 73) Nothing 1)
                , Entity p3k p3
                ]

testSqliteTextFunctions :: SpecDb
testSqliteTextFunctions = do
    describe "text functions" $ do
        itDb "like, (%) and (++.) work on a simple example" $ do
            let query :: String -> SqlPersistT IO [Entity Person]
                query t =
                    select $
                    from $ \p -> do
                    where_ (like
                             (p ^. PersonName)
                             ((%) ++. val t ++. (%)))
                    orderBy [asc (p ^. PersonName)]
                    return p
            [p1e, p2e, p3e, p4e] <- mapM insert' [p1, p2, p3, p4]
            r0 <- query "h"
            r1 <- query "i"
            r2 <- query "iv"
            asserting $ do
                r0 `shouldBe` [p1e, p2e]
                r1 `shouldBe` [p4e, p3e]
                r2 `shouldBe` [p4e]

spec :: HasCallStack => Spec
spec = beforeAll mkConnectionPool $ do
    tests

    describe "SQLite specific tests" $ do
      testAscRandom random_
      testSqliteRandom
      testSqliteSum
      testSqliteTwoAscFields
      testSqliteOneAscOneDesc
      testSqliteCoalesce
      testSqliteUpdate
      testSqliteTextFunctions

mkConnectionPool :: IO ConnectionPool
mkConnectionPool = do
    conn <-
        if verbose
        then runStderrLoggingT $
            createSqlitePool ".esqueleto-test.sqlite" 4
        else runNoLoggingT $
            createSqlitePool ".esqueleto-test.sqlite" 4
    flip runSqlPool conn $ do
        migrateIt

    pure conn

verbose :: Bool
verbose = False

migrateIt :: MonadUnliftIO m => SqlPersistT m ()
migrateIt = do
  void $ runMigrationSilent migrateAll
  cleanDB