{-# LANGUAGE BangPatterns, TypeFamilies, DataKinds, PolyKinds, TypeApplications, ScopedTypeVariables, TypeInType, ConstraintKinds, TypeOperators, GADTs, UndecidableInstances, StandaloneDeriving, FunctionalDependencies, FlexibleContexts, InstanceSigs, AllowAmbiguousTypes, DeriveAnyClass #-}
{-|
Module: IHP.Fetch
Description: fetch, fetchOne, fetchOneOrNothing and friends
Copyright: (c) digitally induced GmbH, 2020

This modules builds on top of 'IHP.QueryBuilder' and provides functions to fetch a query builder.

For more complex sql queries, use 'IHP.ModelSupport.sqlQuery'.
-}
module IHP.Fetch
( findManyBy
, findMaybeBy
, findBy
, In (In)
, genericFetchId
, genericfetchIdOneOrNothing
, genericFetchIdOne
, Fetchable (..)
, genericFetchIds
, genericfetchIdsOneOrNothing
, genericFetchIdsOne
, fetchCount
, fetchExists
)
where

import IHP.Prelude
import Database.PostgreSQL.Simple (Connection)
import Database.PostgreSQL.Simple.Types (Query (Query), In (In))
import Database.PostgreSQL.Simple.FromField hiding (Field, name)
import Database.PostgreSQL.Simple.ToField
import qualified Database.PostgreSQL.Simple as PG
import qualified Database.PostgreSQL.Simple.Types as PG
import GHC.OverloadedLabels
import IHP.ModelSupport
import qualified Data.ByteString.Builder as Builder
import IHP.HtmlSupport.ToHtml
import qualified Data.ByteString.Char8 as ByteString
import qualified Data.ByteString.Lazy as LByteString
import qualified Control.DeepSeq as DeepSeq
import qualified Data.Text.Encoding as Text
import IHP.QueryBuilder

class Fetchable fetchable model | fetchable -> model where
    type FetchResult fetchable model
    fetch :: (KnownSymbol (GetTableName model), PG.FromRow model, ?modelContext :: ModelContext) => fetchable -> IO (FetchResult fetchable model)
    fetchOneOrNothing :: (KnownSymbol (GetTableName model), PG.FromRow model, ?modelContext :: ModelContext) => fetchable -> IO (Maybe model)
    fetchOne :: (KnownSymbol (GetTableName model), PG.FromRow model, ?modelContext :: ModelContext) => fetchable -> IO model

instance (model ~ GetModelByTableName table, KnownSymbol table) => Fetchable (QueryBuilder table) model where
    type FetchResult (QueryBuilder table) model = [model]
    {-# INLINE fetch #-}
    fetch :: (KnownSymbol (GetTableName model), PG.FromRow model, ?modelContext :: ModelContext) => QueryBuilder table -> IO [model]
    fetch :: QueryBuilder table -> IO [model]
fetch !QueryBuilder table
queryBuilder = do
        let !(ByteString
theQuery, [Action]
theParameters) = QueryBuilder table
queryBuilder
                QueryBuilder table
-> (QueryBuilder table -> (ByteString, [Action]))
-> (ByteString, [Action])
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> (ByteString, [Action])
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> (ByteString, [Action])
toSQL
        (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (KnownSymbol (GetTableName model) => ByteString
forall model. KnownSymbol (GetTableName model) => ByteString
tableNameByteString @model)
        Query -> [Action] -> IO [model]
forall q r.
(?modelContext::ModelContext, ToRow q, FromRow r, Show q) =>
Query -> q -> IO [r]
sqlQuery (ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
theQuery) [Action]
theParameters

    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: (?modelContext :: ModelContext) => (PG.FromRow model, KnownSymbol (GetTableName model)) => QueryBuilder table -> IO (Maybe model)
    fetchOneOrNothing :: QueryBuilder table -> IO (Maybe model)
fetchOneOrNothing !QueryBuilder table
queryBuilder = do
        let !(ByteString
theQuery, [Action]
theParameters) = QueryBuilder table
queryBuilder
                QueryBuilder table -> (QueryBuilder table -> SQLQuery) -> SQLQuery
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> SQLQuery
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> SQLQuery
buildQuery
                SQLQuery -> (SQLQuery -> SQLQuery) -> SQLQuery
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Proxy "limitClause" -> ByteString -> SQLQuery -> SQLQuery
forall model (name :: Symbol) value.
(KnownSymbol name, SetField name model (Maybe value)) =>
Proxy name -> value -> model -> model
setJust IsLabel "limitClause" (Proxy "limitClause")
Proxy "limitClause"
#limitClause ByteString
"LIMIT 1"
                SQLQuery
-> (SQLQuery -> (ByteString, [Action])) -> (ByteString, [Action])
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> SQLQuery -> (ByteString, [Action])
toSQL'
        (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (KnownSymbol (GetTableName model) => ByteString
forall model. KnownSymbol (GetTableName model) => ByteString
tableNameByteString @model)
        [model]
results <- Query -> [Action] -> IO [model]
forall q r.
(?modelContext::ModelContext, ToRow q, FromRow r, Show q) =>
Query -> q -> IO [r]
sqlQuery (ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
theQuery) [Action]
theParameters
        Maybe model -> IO (Maybe model)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe model -> IO (Maybe model))
-> Maybe model -> IO (Maybe model)
forall a b. (a -> b) -> a -> b
$ [model] -> Maybe model
forall a. [a] -> Maybe a
listToMaybe [model]
results

    {-# INLINE fetchOne #-}
    fetchOne :: (?modelContext :: ModelContext) => (PG.FromRow model, KnownSymbol (GetTableName model)) => QueryBuilder table -> IO model
    fetchOne :: QueryBuilder table -> IO model
fetchOne !QueryBuilder table
queryBuilder = do
        Maybe model
maybeModel <- QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing QueryBuilder table
queryBuilder
        case Maybe model
maybeModel of
            Just model
model -> model -> IO model
forall (f :: * -> *) a. Applicative f => a -> f a
pure model
model
            Maybe model
Nothing -> RecordNotFoundException -> IO model
forall e a. Exception e => e -> IO a
throwIO RecordNotFoundException :: (ByteString, [Action]) -> RecordNotFoundException
RecordNotFoundException { $sel:queryAndParams:RecordNotFoundException :: (ByteString, [Action])
queryAndParams = QueryBuilder table -> (ByteString, [Action])
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> (ByteString, [Action])
toSQL QueryBuilder table
queryBuilder }

-- | Returns the count of records selected by the query builder.
--
-- __Example:__ Counting all users.
--
-- > allUsersCount <- query @User |> fetchCount -- SELECT COUNT(*) FROM users
--
--
-- __Example:__ Counting all active projects
--
-- >     activeProjectsCount <- query @Project
-- >         |> filterWhere (#isActive, True)
-- >         |> fetchCount
-- >     -- SELECT COUNT(*) FROM projects WHERE is_active = true
fetchCount :: forall table. (?modelContext :: ModelContext, KnownSymbol table) => QueryBuilder table -> IO Int
fetchCount :: QueryBuilder table -> IO Int
fetchCount !QueryBuilder table
queryBuilder = do
    let !(ByteString
theQuery', [Action]
theParameters) = SQLQuery -> (ByteString, [Action])
toSQL' (QueryBuilder table -> SQLQuery
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> SQLQuery
buildQuery QueryBuilder table
queryBuilder)
    let theQuery :: ByteString
theQuery = ByteString
"SELECT COUNT(*) FROM (" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
theQuery' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
") AS _count_values"
    (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (KnownSymbol table => ByteString
forall (symbol :: Symbol). KnownSymbol symbol => ByteString
symbolToByteString @table)
    [PG.Only Int
count] <- Query -> [Action] -> IO [Only Int]
forall q r.
(?modelContext::ModelContext, ToRow q, FromRow r, Show q) =>
Query -> q -> IO [r]
sqlQuery (ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$! ByteString -> ByteString
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
theQuery) [Action]
theParameters
    Int -> IO Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
count
{-# INLINE fetchCount #-}

-- | Checks whether the query has any results.
--
-- Returns @True@ when there is at least one row matching the conditions of the query. Returns @False@ otherwise.
--
-- __Example:__ Checking whether there are unread messages
--
-- >     hasUnreadMessages <- query @Message
-- >         |> filterWhere (#isUnread, True)
-- >         |> fetchExists
-- >     -- SELECT EXISTS (SELECT * FROM messages WHERE is_unread = true)
fetchExists :: forall table. (?modelContext :: ModelContext, KnownSymbol table) => QueryBuilder table -> IO Bool
fetchExists :: QueryBuilder table -> IO Bool
fetchExists !QueryBuilder table
queryBuilder = do
    let !(ByteString
theQuery', [Action]
theParameters) = SQLQuery -> (ByteString, [Action])
toSQL' (QueryBuilder table -> SQLQuery
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> SQLQuery
buildQuery QueryBuilder table
queryBuilder)
    let theQuery :: ByteString
theQuery = ByteString
"SELECT EXISTS (" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
theQuery' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
") AS _exists_values"
    (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (KnownSymbol table => ByteString
forall (symbol :: Symbol). KnownSymbol symbol => ByteString
symbolToByteString @table)
    [PG.Only Bool
exists] <- Query -> [Action] -> IO [Only Bool]
forall q r.
(?modelContext::ModelContext, ToRow q, FromRow r, Show q) =>
Query -> q -> IO [r]
sqlQuery (ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$! ByteString -> ByteString
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
theQuery) [Action]
theParameters
    Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
exists
{-# INLINE fetchExists #-}

{-# INLINE genericFetchId #-}
genericFetchId :: forall table model. (KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext, FilterPrimaryKey table, model ~ GetModelByTableName table, GetTableName model ~ table) => Id' table -> IO [model]
genericFetchId :: Id' table -> IO [model]
genericFetchId !Id' table
id = forall model (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Id' table -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol).
FilterPrimaryKey table =>
Id' table -> QueryBuilder table -> QueryBuilder table
filterWhereId Id' table
id QueryBuilder table
-> (QueryBuilder table -> IO [model]) -> IO [model]
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO [model]
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch

{-# INLINE genericfetchIdOneOrNothing #-}
genericfetchIdOneOrNothing :: forall table model. (KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext, FilterPrimaryKey table, model ~ GetModelByTableName table, GetTableName model ~ table) => Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing :: Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing !Id' table
id = forall model (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Id' table -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol).
FilterPrimaryKey table =>
Id' table -> QueryBuilder table -> QueryBuilder table
filterWhereId Id' table
id QueryBuilder table
-> (QueryBuilder table -> IO (Maybe model)) -> IO (Maybe model)
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

{-# INLINE genericFetchIdOne #-}
genericFetchIdOne :: forall table model. (KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext, FilterPrimaryKey table, model ~ GetModelByTableName table, GetTableName model ~ table) => Id' table -> IO model
genericFetchIdOne :: Id' table -> IO model
genericFetchIdOne !Id' table
id = forall model (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Id' table -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol).
FilterPrimaryKey table =>
Id' table -> QueryBuilder table -> QueryBuilder table
filterWhereId Id' table
id QueryBuilder table -> (QueryBuilder table -> IO model) -> IO model
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO model
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

{-# INLINE genericFetchIds #-}
genericFetchIds :: forall table model value. (KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext, ToField value, EqOrIsOperator value, HasField "id" model value, model ~ GetModelByTableName table, GetTableName model ~ table) => [value] -> IO [model]
genericFetchIds :: [value] -> IO [model]
genericFetchIds ![value]
ids = forall model (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy "id", [value]) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol name, ToField value, HasField name model value,
 model ~ GetModelByTableName table) =>
(Proxy name, [value]) -> QueryBuilder table -> QueryBuilder table
filterWhereIn (IsLabel "id" (Proxy "id")
Proxy "id"
#id, [value]
ids) QueryBuilder table
-> (QueryBuilder table -> IO [model]) -> IO [model]
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO [model]
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch

{-# INLINE genericfetchIdsOneOrNothing #-}
genericfetchIdsOneOrNothing :: forall model value table. (KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext, ToField value, EqOrIsOperator value, HasField "id" model value, model ~ GetModelByTableName table, GetTableName model ~ table) => [value] -> IO (Maybe model)
genericfetchIdsOneOrNothing :: [value] -> IO (Maybe model)
genericfetchIdsOneOrNothing ![value]
ids = forall model (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy "id", [value]) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol name, ToField value, HasField name model value,
 model ~ GetModelByTableName table) =>
(Proxy name, [value]) -> QueryBuilder table -> QueryBuilder table
filterWhereIn (IsLabel "id" (Proxy "id")
Proxy "id"
#id, [value]
ids) QueryBuilder table
-> (QueryBuilder table -> IO (Maybe model)) -> IO (Maybe model)
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

{-# INLINE genericFetchIdsOne #-}
genericFetchIdsOne :: forall model value table. (KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext, ToField value, EqOrIsOperator value, HasField "id" model value, model ~ GetModelByTableName table, GetTableName model ~ table) => [value] -> IO model
genericFetchIdsOne :: [value] -> IO model
genericFetchIdsOne ![value]
ids = forall model (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy "id", [value]) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol name, ToField value, HasField name model value,
 model ~ GetModelByTableName table) =>
(Proxy name, [value]) -> QueryBuilder table -> QueryBuilder table
filterWhereIn (IsLabel "id" (Proxy "id")
Proxy "id"
#id, [value]
ids) QueryBuilder table -> (QueryBuilder table -> IO model) -> IO model
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO model
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

{-# INLINE findBy #-}
findBy :: Proxy name
-> value -> QueryBuilder table -> IO (GetModelByTableName table)
findBy !Proxy name
field !value
value !QueryBuilder table
queryBuilder = QueryBuilder table
queryBuilder QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy name, value) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol name, ToField value, HasField name model value,
 EqOrIsOperator value, model ~ GetModelByTableName table) =>
(Proxy name, value) -> QueryBuilder table -> QueryBuilder table
filterWhere (Proxy name
field, value
value) QueryBuilder table
-> (QueryBuilder table -> IO (GetModelByTableName table))
-> IO (GetModelByTableName table)
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO (GetModelByTableName table)
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

{-# INLINE findMaybeBy #-}
findMaybeBy :: Proxy name
-> value
-> QueryBuilder table
-> IO (Maybe (GetModelByTableName table))
findMaybeBy !Proxy name
field !value
value !QueryBuilder table
queryBuilder = QueryBuilder table
queryBuilder QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy name, value) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol name, ToField value, HasField name model value,
 EqOrIsOperator value, model ~ GetModelByTableName table) =>
(Proxy name, value) -> QueryBuilder table -> QueryBuilder table
filterWhere (Proxy name
field, value
value) QueryBuilder table
-> (QueryBuilder table -> IO (Maybe (GetModelByTableName table)))
-> IO (Maybe (GetModelByTableName table))
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO (Maybe (GetModelByTableName table))
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

--findManyBy :: (?modelContext :: ModelContext, PG.FromRow model, KnownSymbol (GetTableName model), KnownSymbol name, ToField value, HasField name value model) => Proxy name -> value -> QueryBuilder model -> IO [model]
{-# INLINE findManyBy #-}
findManyBy :: Proxy name
-> value -> QueryBuilder table -> IO [GetModelByTableName table]
findManyBy !Proxy name
field !value
value !QueryBuilder table
queryBuilder = QueryBuilder table
queryBuilder QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy name, value) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol name, ToField value, HasField name model value,
 EqOrIsOperator value, model ~ GetModelByTableName table) =>
(Proxy name, value) -> QueryBuilder table -> QueryBuilder table
filterWhere (Proxy name
field, value
value) QueryBuilder table
-> (QueryBuilder table -> IO [GetModelByTableName table])
-> IO [GetModelByTableName table]
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> QueryBuilder table -> IO [GetModelByTableName table]
forall fetchable model.
(Fetchable fetchable model, KnownSymbol (GetTableName model),
 FromRow model, ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch
-- Step.findOneByWorkflowId id    ==    queryBuilder |> findBy #templateId id

instance (model ~ GetModelById (Id' table), GetTableName model ~ table, FilterPrimaryKey table) => Fetchable (Id' table) model where
    type FetchResult (Id' table) model = model
    {-# INLINE fetch #-}
    fetch :: Id' table -> IO (FetchResult (Id' table) model)
fetch = Id' table -> IO (FetchResult (Id' table) model)
forall (table :: Symbol) model.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 FilterPrimaryKey table, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
Id' table -> IO model
genericFetchIdOne
    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: Id' table -> IO (Maybe model)
fetchOneOrNothing = Id' table -> IO (Maybe model)
forall (table :: Symbol) model.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 FilterPrimaryKey table, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing
    {-# INLINE fetchOne #-}
    fetchOne :: Id' table -> IO model
fetchOne = Id' table -> IO model
forall (table :: Symbol) model.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 FilterPrimaryKey table, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
Id' table -> IO model
genericFetchIdOne

instance (model ~ GetModelById (Id' table), GetTableName model ~ table, FilterPrimaryKey table) => Fetchable (Maybe (Id' table)) model where
    type FetchResult (Maybe (Id' table)) model = [model]
    {-# INLINE fetch #-}
    fetch :: Maybe (Id' table) -> IO (FetchResult (Maybe (Id' table)) model)
fetch (Just Id' table
a) = Id' table -> IO [model]
forall (table :: Symbol) model.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 FilterPrimaryKey table, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
Id' table -> IO [model]
genericFetchId Id' table
a
    fetch Maybe (Id' table)
Nothing = [model] -> IO [model]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: Maybe (Id' table) -> IO (Maybe model)
fetchOneOrNothing Maybe (Id' table)
Nothing = Maybe model -> IO (Maybe model)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe model
forall a. Maybe a
Nothing
    fetchOneOrNothing (Just Id' table
a) = Id' table -> IO (Maybe model)
forall (table :: Symbol) model.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 FilterPrimaryKey table, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing Id' table
a
    {-# INLINE fetchOne #-}
    fetchOne :: Maybe (Id' table) -> IO model
fetchOne (Just Id' table
a) = Id' table -> IO model
forall (table :: Symbol) model.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 FilterPrimaryKey table, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
Id' table -> IO model
genericFetchIdOne Id' table
a
    fetchOne Maybe (Id' table)
Nothing = Text -> IO model
forall a. Text -> a
error Text
"Fetchable (Maybe Id): Failed to fetch because given id is 'Nothing', 'Just id' was expected"

instance (model ~ GetModelById (Id' table), value ~ Id' table, HasField "id" model value, ToField (PrimaryKey table), GetModelByTableName (GetTableName model) ~ model) => Fetchable [Id' table] model where
    type FetchResult [Id' table] model = [model]
    {-# INLINE fetch #-}
    fetch :: [Id' table] -> IO (FetchResult [Id' table] model)
fetch = [Id' table] -> IO (FetchResult [Id' table] model)
forall (table :: Symbol) model value.
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 ToField value, EqOrIsOperator value, HasField "id" model value,
 model ~ GetModelByTableName table, GetTableName model ~ table) =>
[value] -> IO [model]
genericFetchIds
    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: [Id' table] -> IO (Maybe model)
fetchOneOrNothing = [Id' table] -> IO (Maybe model)
forall model value (table :: Symbol).
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 ToField value, EqOrIsOperator value, HasField "id" model value,
 model ~ GetModelByTableName table, GetTableName model ~ table) =>
[value] -> IO (Maybe model)
genericfetchIdsOneOrNothing
    {-# INLINE fetchOne #-}
    fetchOne :: [Id' table] -> IO model
fetchOne = [Id' table] -> IO model
forall model value (table :: Symbol).
(KnownSymbol table, FromRow model, ?modelContext::ModelContext,
 ToField value, EqOrIsOperator value, HasField "id" model value,
 model ~ GetModelByTableName table, GetTableName model ~ table) =>
[value] -> IO model
genericFetchIdsOne