This repository has been archived by the owner on May 1, 2021. It is now read-only.
/
SQLite3.purs
76 lines (67 loc) · 2.7 KB
/
SQLite3.purs
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
module QueryDsl.SQLite3 (
runQuery,
runSelectManyQuery,
runSelectOneQuery
) where
import Prelude
import Data.Array as Array
import Data.Either (Either(..))
import Data.Function.Uncurried (Fn6, runFn6)
import Data.Map (Map)
import Data.Map as Map
import Data.Traversable (traverse)
import Effect.Aff (Aff, error, throwError)
import Foreign (Foreign)
import QueryDsl (class ConstantsToRecord, class Query, Constant(..), ParameterizedSql(..), SelectQuery, constantsToRecord, toSql)
import SQLite3 (DBConnection)
import SQLite3 as SQLite3
import Type.Row (RProxy(..))
paramToString :: Constant -> String
paramToString (StringConstant s) = s
paramToString (IntConstant i) = show i
paramToString (NumberConstant n) = show n
paramToString NullConstant = ""
foreign import decodeQueryResponse
:: Fn6
(String -> String -> Map String Constant -> Map String Constant)
(String -> Int -> Map String Constant -> Map String Constant)
(String -> Number -> Map String Constant -> Map String Constant)
(String -> Map String Constant -> Map String Constant)
(Map String Constant)
Foreign
(Array (Map String Constant))
decodeQueryResponseHelper :: Foreign -> Array (Map String Constant)
decodeQueryResponseHelper =
runFn6 decodeQueryResponse
(\k v -> Map.insert k (StringConstant v))
(\k v -> Map.insert k (IntConstant v))
(\k v -> Map.insert k (NumberConstant v))
(\k -> Map.insert k NullConstant)
Map.empty
runQueryInternal :: forall q. Query q => DBConnection -> q -> Aff Foreign
runQueryInternal conn q =
case toSql q of
Left msg ->
throwError $ error msg
Right (ParameterizedSql sql params) ->
SQLite3.queryDB conn sql (paramToString <$> params)
-- | Run a query and ignore any results.
runQuery :: forall q. Query q => DBConnection -> q -> Aff Unit
runQuery conn q = void $ runQueryInternal conn q
-- | Run a `SelectQuery` and return all the results.
runSelectManyQuery :: forall cols. ConstantsToRecord cols => DBConnection -> SelectQuery cols -> Aff (Array { | cols })
runSelectManyQuery conn q = do
res <- runQueryInternal conn q
let resMaps = decodeQueryResponseHelper res
toRecord = constantsToRecord (RProxy :: RProxy cols)
case traverse toRecord resMaps of
Left msg -> throwError $ error msg
Right recs -> pure recs
-- | Run a `SelectQuery` and either return the single result, or throw an error
-- | if there is more than one result or none at all.
runSelectOneQuery :: forall cols. ConstantsToRecord cols => DBConnection -> SelectQuery cols -> Aff { | cols }
runSelectOneQuery conn q = do
many <- runSelectManyQuery conn q
case many of
[result] -> pure result
rs -> throwError $ error $ "Expected one result, but got " <> show (Array.length rs)