wikimusic-api-1.1.0.1: src/WikiMusic/PostgreSQL/ReadAbstraction.hs
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoFieldSelectors #-}
module WikiMusic.PostgreSQL.ReadAbstraction
( persistenceReadCall,
fetchOpinions,
fetchArtworks,
fetchComments,
mkSearchConstraints,
bindParams,
)
where
import Data.ByteString.Lazy qualified as BL
import Data.Map qualified as Map
import Data.Text hiding (map)
import Data.Time
import Data.UUID hiding (fromString)
import Data.Vector qualified as V
import Hasql.Decoders as D
import Hasql.Encoders as E
import Hasql.Pool qualified
import Hasql.Session qualified
import Hasql.Statement (Statement (..))
import NeatInterpolation
import Relude
bindParams :: Int -> Text
bindParams size = Data.Text.intercalate ", " (["$" <> show x | x <- [1 .. size]])
persistenceReadCall ::
(MonadIO m) =>
Hasql.Pool.Pool ->
Hasql.Session.Session b1 ->
([a] -> b2) ->
(b1 -> [a]) ->
m b2
persistenceReadCall pool sessionCreateF responseCreateF vectorParseF = do
eitherItems <- liftIO $ Hasql.Pool.use pool sessionCreateF
either
( \err -> do
liftIO . BL.putStr . fromString . show $ err
pure $ responseCreateF []
)
(pure . responseCreateF . vectorParseF)
eitherItems
fetchOpinions ::
(MonadIO m, Ord k, Foldable foldable) =>
Hasql.Pool.Pool ->
( [ ( UUID,
UUID,
UUID,
Bool,
Bool,
UTCTime,
Maybe UTCTime
)
] ->
[(k, a)]
) ->
Text ->
Text ->
foldable UUID ->
m (Map k a)
fetchOpinions pool parseRow entityTable entityIdentifier identifiers = do
persistenceReadCall
pool
(Hasql.Session.statement identifiers preparedStmt)
Map.fromList
(parseRow . V.toList)
where
preparedStmt = Statement query encoder decoder True
query =
encodeUtf8
[untrimming|
SELECT identifier, $entityIdentifier, created_by, is_like, is_dislike,
created_at, last_edited_at FROM $entityTable WHERE $entityIdentifier = ANY($$1)
|]
encoder =
E.param . E.nonNullable $ (E.foldableArray . E.nonNullable $ E.uuid)
decoder = D.rowVector vector
where
vector =
(,,,,,,)
<$> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.bool)
<*> D.column (D.nonNullable D.bool)
<*> D.column (D.nonNullable D.timestamptz)
<*> D.column (D.nullable D.timestamptz)
fetchArtworks ::
(MonadIO m, Ord k, Foldable foldable) =>
Hasql.Pool.Pool ->
( [ ( UUID,
UUID,
UUID,
Int64,
Maybe UUID,
Text,
Maybe Text,
UTCTime,
Maybe UTCTime,
Int64
)
] ->
[(k, a)]
) ->
Text ->
Text ->
foldable UUID ->
m (Map k a)
fetchArtworks pool parseRow entityTable entityIdentifier identifiers = do
persistenceReadCall
pool
(Hasql.Session.statement identifiers preparedStmt)
Map.fromList
(parseRow . V.toList)
where
preparedStmt = Statement query encoder decoder True
query =
encodeUtf8
[untrimming|
SELECT identifier, $entityIdentifier, created_by, visibility_status, approved_by, content_url, content_caption,
created_at, last_edited_at, order_value FROM $entityTable WHERE $entityIdentifier = ANY($$1) ORDER BY ${entityTable}.order_value ASC
|]
encoder = E.param . E.nonNullable $ (E.foldableArray . E.nonNullable $ E.uuid)
decoder = D.rowVector vector
where
vector =
(,,,,,,,,,)
<$> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.int8)
<*> D.column (D.nullable D.uuid)
<*> D.column (D.nonNullable D.text)
<*> D.column (D.nullable D.text)
<*> D.column (D.nonNullable D.timestamptz)
<*> D.column (D.nullable D.timestamptz)
<*> D.column (D.nonNullable D.int8)
fetchComments ::
(MonadIO m, Ord k, Foldable foldable) =>
Hasql.Pool.Pool ->
( [ ( UUID,
UUID,
Maybe UUID,
UUID,
Int64,
Text,
Maybe UUID,
UTCTime,
Maybe UTCTime
)
] ->
[(k, a)]
) ->
Text ->
Text ->
foldable UUID ->
m (Map k a)
fetchComments pool parseRow entityTable entityIdentifier identifiers = do
persistenceReadCall
pool
(Hasql.Session.statement identifiers preparedStmt)
Map.fromList
(parseRow . V.toList)
where
preparedStmt = Statement query encoder decoder True
query =
encodeUtf8
[untrimming|
SELECT identifier, $entityIdentifier, parent_identifier, created_by, visibility_status,
contents, approved_by, created_at, last_edited_at FROM $entityTable
WHERE $entityIdentifier = ANY($$1) ORDER BY ${entityTable}.created_at ASC
|]
encoder =
E.param . E.nonNullable $ (E.foldableArray . E.nonNullable $ E.uuid)
decoder = D.rowVector vector
where
vector =
(,,,,,,,,)
<$> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.uuid)
<*> D.column (D.nullable D.uuid)
<*> D.column (D.nonNullable D.uuid)
<*> D.column (D.nonNullable D.int8)
<*> D.column (D.nonNullable D.text)
<*> D.column (D.nullable D.uuid)
<*> D.column (D.nonNullable D.timestamptz)
<*> D.column (D.nullable D.timestamptz)
mkSearchConstraints :: Text -> Text
mkSearchConstraints searchInput = Data.Text.intercalate " AND " inputs
where
cleanWords = map (Data.Text.filter (\x -> x /= '\'' && x /= '%' && x /= ';' && x /= '"') . strip) (Data.Text.words searchInput)
inputs = map (\x -> [untrimming|artists.display_name ILIKE '%$x%'|]) cleanWords