{-# LANGUAGE OverloadedStrings #-}
module Quokka.Functions (
build
, build1
, buildWith1Rel
, buildWith1CustomRel
, build1With1Rel
, build1With1CustomRel
, buildWithManyRels
, buildWithManyCustomRels
, build1WithManyRels
, build1WithManyCustomRels
, delete
, deleteStatement
, id'
, insertStatement
, insertStatementWith1Rel
, insertStatementWith1CustomRel
, insertStatementWithManyRels
, insertStatementWithManyCustomRels
, mapFromIdToResult
) where
import Data.Functor (void)
import Data.Int (Int64)
import Data.Text (intercalate)
import Data.Text.Encoding (encodeUtf8)
import Database.PostgreSQL.Simple (Connection, ToRow, execute_, returning, query)
import Database.PostgreSQL.Simple.Types (Query (Query))
import Quokka.Types (ChildTable (ChildTable)
, FK (FK)
, Id (getId)
, ParentTable (ParentTable)
, Table (Table)
, Relation (Relation)
, Result (SingleResult))
import Quokka.Text.Countable (singularize)
build
:: (ToRow q)
=> Connection
-> ParentTable
-> [q]
-> IO [Id]
build conn tbl =
let
qry = insertStatement tbl
in
returning conn qry
build1
:: (ToRow q)
=> Connection
-> ParentTable
-> q
-> IO (Maybe Id)
build1 conn tbl =
let
qry = insertStatement tbl
in
fmap build1Helper . query conn qry
buildWith1Rel
:: (ToRow q)
=> Connection
-> ParentTable
-> ChildTable
-> [q]
-> IO [Id]
buildWith1Rel conn parent child =
let
qry = insertStatementWith1Rel parent child
in
returning conn qry
buildWith1CustomRel
:: (ToRow q)
=> Connection
-> Relation
-> ChildTable
-> [q]
-> IO [Id]
buildWith1CustomRel conn relation child =
let
qry = insertStatementWith1CustomRel relation child
in
returning conn qry
build1With1Rel
:: (ToRow q)
=> Connection
-> ParentTable
-> ChildTable
-> q
-> IO (Maybe Id)
build1With1Rel conn parent child =
let
qry = insertStatementWith1Rel parent child
in
fmap build1Helper . query conn qry
build1With1CustomRel
:: (ToRow q)
=> Connection
-> Relation
-> ChildTable
-> q
-> IO (Maybe Id)
build1With1CustomRel conn relation child =
let
qry = insertStatementWith1CustomRel relation child
in
fmap build1Helper . query conn qry
buildWithManyRels
:: (ToRow q)
=> Connection
-> [ParentTable]
-> ChildTable
-> [q]
-> IO [Id]
buildWithManyRels conn parents child =
let
qry = insertStatementWithManyRels parents child
in
returning conn qry
buildWithManyCustomRels
:: (ToRow q)
=> Connection
-> [Relation]
-> ChildTable
-> [q]
-> IO [Id]
buildWithManyCustomRels conn relations child =
let
qry = insertStatementWithManyCustomRels relations child
in
returning conn qry
build1WithManyRels
:: (ToRow q)
=> Connection
-> [ParentTable]
-> ChildTable
-> q
-> IO (Maybe Id)
build1WithManyRels conn parents child =
let
qry = insertStatementWithManyRels parents child
in
fmap build1Helper . query conn qry
build1WithManyCustomRels
:: (ToRow q)
=> Connection
-> [Relation]
-> ChildTable
-> q
-> IO (Maybe Id)
build1WithManyCustomRels conn relations child =
let
qry = insertStatementWithManyCustomRels relations child
in
fmap build1Helper . query conn qry
delete
:: Connection
-> Table
-> IO Int64
delete conn tbl = do
let
alter = alterSequenceStatement tbl
qry = deleteStatement tbl
void $ execute_ conn alter
execute_ conn qry
insertStatement
:: ParentTable
-> Query
insertStatement (ParentTable name columns) =
let
columnsAsText = intercalate "," columns
valuesAsText = intercalate "," (map (const "?") columns)
baseInsert = "insert into " <> name <> " (" <> columnsAsText <> ")"
in
Query (encodeUtf8 $ baseInsert <> " values (" <> valuesAsText <> ") returning id;")
insertStatementWith1Rel
:: ParentTable
-> ChildTable
-> Query
insertStatementWith1Rel parent =
insertStatementWithManyRels [parent]
insertStatementWith1CustomRel
:: Relation
-> ChildTable
-> Query
insertStatementWith1CustomRel relation =
insertStatementWithManyCustomRels [relation]
insertStatementWithManyRels
:: [ParentTable]
-> ChildTable
-> Query
insertStatementWithManyRels parents child =
let
buildFK name = FK (singularize name <> "_id")
relations = map (\p@(ParentTable name _) -> Relation p (buildFK name)) parents
in
insertStatementWithManyCustomRels relations child
insertStatementWithManyCustomRels
:: [Relation]
-> ChildTable
-> Query
insertStatementWithManyCustomRels relations (ChildTable name columns) =
let
updatedColumns = columns ++ map (\(Relation _ (FK fkName)) -> fkName) relations
columnsAsText = intercalate "," updatedColumns
valuesAsText = intercalate "," (map (const "?") updatedColumns)
baseInsert = "insert into " <> name <> " (" <> columnsAsText <> ")"
in
Query (encodeUtf8 $ baseInsert <> " values (" <> valuesAsText <> ") returning id;")
alterSequenceStatement
:: Table
-> Query
alterSequenceStatement (Table name) =
Query (encodeUtf8 $ "alter sequence " <> name <> "_id_seq restart;")
deleteStatement
:: Table
-> Query
deleteStatement (Table name) =
Query (encodeUtf8 $ "truncate table " <> name <> " cascade;")
id' :: [Id] -> Int
id' (x:_) =
getId x
id' [] =
-1
build1Helper
:: [Id]
-> Maybe Id
build1Helper (x:_) =
Just x
build1Helper [] =
Nothing
mapFromIdToResult
:: ParentTable
-> [Id]
-> [Result]
mapFromIdToResult tbl =
map (SingleResult tbl)