aboutsummaryrefslogtreecommitdiff
path: root/server/src/Persistence/Category.hs
blob: b0a6fca39068f20e2d7d9e3fc3e96b2629e98836 (plain)
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
module Persistence.Category
  ( count
  , list
  , listAll
  , create
  , edit
  , delete
  ) where

import qualified Data.Maybe             as Maybe
import           Data.Text              (Text)
import           Data.Time.Clock        (getCurrentTime)
import           Database.SQLite.Simple (FromRow (fromRow), NamedParam ((:=)))
import qualified Database.SQLite.Simple as SQLite
import           Prelude                hiding (id)

import           Common.Model           (Category (..), CategoryId)

import           Model.Query            (Query (Query))

newtype Row = Row Category

instance FromRow Row where
  fromRow = Row <$> (Category <$>
    SQLite.field <*>
    SQLite.field <*>
    SQLite.field <*>
    SQLite.field <*>
    SQLite.field <*>
    SQLite.field)

data CountRow = CountRow Int

instance FromRow CountRow where
  fromRow = CountRow <$> SQLite.field

count :: Query Int
count =
  Query (\conn ->
    (Maybe.fromMaybe 0 . fmap (\(CountRow n) -> n) . Maybe.listToMaybe) <$>
      SQLite.query_ conn "SELECT COUNT(*) FROM category WHERE deleted_at IS NULL"
  )


list :: Int -> Int -> Query [Category]
list page perPage =
  Query (\conn ->
    map (\(Row c) -> c) <$>
      SQLite.queryNamed
          conn
          "SELECT * FROM category WHERE deleted_at IS NULL ORDER BY name LIMIT :limit OFFSET :offset"
          [ ":limit" := perPage
          , ":offset" := (page - 1) * perPage
          ]
  )

listAll :: Query [Category]
listAll =
  Query (\conn ->
    map (\(Row c) -> c) <$>
      SQLite.query_ conn "SELECT * FROM category WHERE deleted_at IS NULL"
  )

create :: Text -> Text -> Query ()
create name color =
  Query (\conn -> do
    currentTime <- getCurrentTime
    SQLite.executeNamed
      conn
      "INSERT INTO category (name, color, created_at) VALUES (:name, :color, :created_at)"
      [ ":name" := name
      , ":color" := color
      , ":created_at" := currentTime
      ]
  )

edit :: CategoryId -> Text -> Text -> Query Bool
edit id name color =
  Query (\conn -> do
    mbCategory <- fmap (\(Row c) -> c) . Maybe.listToMaybe <$>
      (SQLite.queryNamed conn "SELECT * FROM category WHERE id = :id" [ ":id" := id ])
    if Maybe.isJust mbCategory
      then do
        currentTime <- getCurrentTime
        SQLite.executeNamed
          conn
          "UPDATE category SET edited_at = :editedAt, name = :name, color = :color WHERE id = :id"
          [ ":editedAt" := currentTime
          , ":name" := name
          , ":color" := color
          , ":id" := id
          ]
        return True
      else
        return False
  )

data BoolRow = BoolRow Int

instance FromRow BoolRow where
  fromRow = BoolRow <$> SQLite.field

delete :: CategoryId -> Query Bool
delete id =
  Query (\conn -> do
    mbPayment <- (fmap (\(BoolRow b) -> b) . Maybe.listToMaybe) <$>
      (SQLite.queryNamed
        conn
        "SELECT true FROM payment WHERE category = :id AND deleted_at IS NULL"
        [ ":id" := id ])
    if Maybe.isNothing mbPayment
      then do
        currentTime <- getCurrentTime
        SQLite.executeNamed
          conn
          "UPDATE category SET deleted_at = :deletedAt WHERE id = :id AND deleted_at IS NULL"
          [ ":deletedAt" := currentTime
          , ":id" := id
          ]
        return True
      else
        return False
  )