{-# 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
, fetchSQLQuery
, fetchLatest
, fetchLatestBy
)
where

import IHP.Prelude
import Database.PostgreSQL.Simple.Types (Query (Query))
import Database.PostgreSQL.Simple.FromField hiding (Field, name)
import Database.PostgreSQL.Simple.ToField
import qualified Database.PostgreSQL.Simple as PG
import IHP.ModelSupport
import IHP.QueryBuilder

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

-- The instance declaration had to be split up because a type variable ranging over HasQueryBuilder instances is not allowed in the declaration of the associated type. The common*-functions reduce the redundancy to the necessary minimum.
instance (model ~ GetModelByTableName table, KnownSymbol table) => Fetchable (QueryBuilder table) model where
    type instance FetchResult (QueryBuilder table) model = [model]
    {-# INLINE fetch #-}
    fetch :: (Table model, PG.FromRow model, ?modelContext :: ModelContext) => QueryBuilder table -> IO [model]
    fetch :: QueryBuilder table -> IO [model]
fetch = QueryBuilder table -> IO [model]
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(Table model, HasQueryBuilder queryBuilderProvider joinRegister,
 model ~ GetModelByTableName table, KnownSymbol table,
 FromRow model, ?modelContext::ModelContext) =>
queryBuilderProvider table -> IO [model]
commonFetch 

    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => QueryBuilder table -> IO (Maybe model)
    fetchOneOrNothing :: QueryBuilder table -> IO (Maybe model)
fetchOneOrNothing = QueryBuilder table -> IO (Maybe model)
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO (Maybe model)
commonFetchOneOrNothing

    {-# INLINE fetchOne #-}
    fetchOne :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => QueryBuilder table -> IO model
    fetchOne :: QueryBuilder table -> IO model
fetchOne = QueryBuilder table -> IO model
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 Fetchable (queryBuilderProvider table) model,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO model
commonFetchOne

instance (model ~ GetModelByTableName table, KnownSymbol table) => Fetchable (JoinQueryBuilderWrapper r table) model where
    type instance FetchResult (JoinQueryBuilderWrapper r table) model = [model]
    {-# INLINE fetch #-}
    fetch :: (Table model, PG.FromRow model, ?modelContext :: ModelContext) => JoinQueryBuilderWrapper r table -> IO [model]
    fetch :: JoinQueryBuilderWrapper r table -> IO [model]
fetch = JoinQueryBuilderWrapper r table -> IO [model]
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(Table model, HasQueryBuilder queryBuilderProvider joinRegister,
 model ~ GetModelByTableName table, KnownSymbol table,
 FromRow model, ?modelContext::ModelContext) =>
queryBuilderProvider table -> IO [model]
commonFetch 

    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => JoinQueryBuilderWrapper r table -> IO (Maybe model)
    fetchOneOrNothing :: JoinQueryBuilderWrapper r table -> IO (Maybe model)
fetchOneOrNothing = JoinQueryBuilderWrapper r table -> IO (Maybe model)
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO (Maybe model)
commonFetchOneOrNothing

    {-# INLINE fetchOne #-}
    fetchOne :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => JoinQueryBuilderWrapper r table -> IO model
    fetchOne :: JoinQueryBuilderWrapper r table -> IO model
fetchOne = JoinQueryBuilderWrapper r table -> IO model
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 Fetchable (queryBuilderProvider table) model,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO model
commonFetchOne

instance (model ~ GetModelByTableName table, KnownSymbol table) => Fetchable (NoJoinQueryBuilderWrapper table) model where
    type instance FetchResult (NoJoinQueryBuilderWrapper table) model = [model]
    {-# INLINE fetch #-}
    fetch :: (Table model, PG.FromRow model, ?modelContext :: ModelContext) => NoJoinQueryBuilderWrapper table -> IO [model]
    fetch :: NoJoinQueryBuilderWrapper table -> IO [model]
fetch = NoJoinQueryBuilderWrapper table -> IO [model]
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(Table model, HasQueryBuilder queryBuilderProvider joinRegister,
 model ~ GetModelByTableName table, KnownSymbol table,
 FromRow model, ?modelContext::ModelContext) =>
queryBuilderProvider table -> IO [model]
commonFetch 

    {-# INLINE fetchOneOrNothing #-}
    fetchOneOrNothing :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => NoJoinQueryBuilderWrapper table -> IO (Maybe model)
    fetchOneOrNothing :: NoJoinQueryBuilderWrapper table -> IO (Maybe model)
fetchOneOrNothing = NoJoinQueryBuilderWrapper table -> IO (Maybe model)
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO (Maybe model)
commonFetchOneOrNothing

    {-# INLINE fetchOne #-}
    fetchOne :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => NoJoinQueryBuilderWrapper table -> IO model
    fetchOne :: NoJoinQueryBuilderWrapper table -> IO model
fetchOne = NoJoinQueryBuilderWrapper table -> IO model
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 Fetchable (queryBuilderProvider table) model,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO model
commonFetchOne

instance (model ~ GetModelByTableName table, KnownSymbol table, FromField value, KnownSymbol foreignTable, foreignModel ~ GetModelByTableName foreignTable, KnownSymbol columnName, HasField columnName foreignModel value, HasQueryBuilder (LabeledQueryBuilderWrapper foreignTable columnName value) NoJoins) => Fetchable (LabeledQueryBuilderWrapper foreignTable columnName value table) model where
    type instance FetchResult (LabeledQueryBuilderWrapper foreignTable columnName value table) model = [LabeledData value model]
    -- fetch needs to return a list of labeled data. The 
    {-# INLINE fetch #-}
    fetch :: (Table model, PG.FromRow model, ?modelContext :: ModelContext) => LabeledQueryBuilderWrapper foreignTable columnName value table -> IO [LabeledData value model]
    fetch :: LabeledQueryBuilderWrapper foreignTable columnName value table
-> IO [LabeledData value model]
fetch !LabeledQueryBuilderWrapper foreignTable columnName value table
queryBuilderProvider = do
        let !(ByteString
theQuery, [Action]
theParameters) = LabeledQueryBuilderWrapper foreignTable columnName value table
queryBuilderProvider
                LabeledQueryBuilderWrapper foreignTable columnName value table
-> (LabeledQueryBuilderWrapper foreignTable columnName value table
    -> (ByteString, [Action]))
-> (ByteString, [Action])
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> LabeledQueryBuilderWrapper foreignTable columnName value table
-> (ByteString, [Action])
forall k (table :: Symbol) (queryBuilderProvider :: Symbol -> *)
       (joinRegister :: k).
(KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister) =>
queryBuilderProvider table -> (ByteString, [Action])
toSQL
        (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (Table model => ByteString
forall record. Table record => ByteString
tableNameByteString @model)
        Query -> [Action] -> IO [LabeledData value model]
forall q r.
(?modelContext::ModelContext, ToRow q, FromRow r, Show q) =>
Query -> q -> IO [r]
sqlQuery @_ @(LabeledData value model) (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) => (Table model, PG.FromRow model) => LabeledQueryBuilderWrapper foreignTable columnName value table -> IO (Maybe model)
    fetchOneOrNothing :: LabeledQueryBuilderWrapper foreignTable columnName value table
-> IO (Maybe model)
fetchOneOrNothing = LabeledQueryBuilderWrapper foreignTable columnName value table
-> IO (Maybe model)
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO (Maybe model)
commonFetchOneOrNothing

    {-# INLINE fetchOne #-}
    fetchOne :: (?modelContext :: ModelContext) => (Table model, PG.FromRow model) => LabeledQueryBuilderWrapper foreignTable columnName value table -> IO model
    fetchOne :: LabeledQueryBuilderWrapper foreignTable columnName value table
-> IO model
fetchOne = LabeledQueryBuilderWrapper foreignTable columnName value table
-> IO model
forall k model (table :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(?modelContext::ModelContext, Table model, KnownSymbol table,
 Fetchable (queryBuilderProvider table) model,
 HasQueryBuilder queryBuilderProvider joinRegister,
 FromRow model) =>
queryBuilderProvider table -> IO model
commonFetchOne



{-# INLINE commonFetch #-}
commonFetch :: forall model table queryBuilderProvider joinRegister.(Table model, HasQueryBuilder queryBuilderProvider joinRegister, model ~ GetModelByTableName table, KnownSymbol table, PG.FromRow model, ?modelContext :: ModelContext) => queryBuilderProvider table -> IO [model]
commonFetch :: queryBuilderProvider table -> IO [model]
commonFetch !queryBuilderProvider table
queryBuilder = do
    let !(ByteString
theQuery, [Action]
theParameters) = queryBuilderProvider table
queryBuilder
            queryBuilderProvider table
-> (queryBuilderProvider table -> (ByteString, [Action]))
-> (ByteString, [Action])
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> queryBuilderProvider table -> (ByteString, [Action])
forall k (table :: Symbol) (queryBuilderProvider :: Symbol -> *)
       (joinRegister :: k).
(KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister) =>
queryBuilderProvider table -> (ByteString, [Action])
toSQL
    (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (Table model => ByteString
forall record. Table record => 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 commonFetchOneOrNothing #-}
commonFetchOneOrNothing :: forall model table queryBuilderProvider joinRegister.(?modelContext :: ModelContext) => (Table model, KnownSymbol table, HasQueryBuilder queryBuilderProvider joinRegister, PG.FromRow model) => queryBuilderProvider table -> IO (Maybe model)
commonFetchOneOrNothing :: queryBuilderProvider table -> IO (Maybe model)
commonFetchOneOrNothing !queryBuilderProvider table
queryBuilder = do
    let !(ByteString
theQuery, [Action]
theParameters) = queryBuilderProvider table
queryBuilder
            queryBuilderProvider table
-> (queryBuilderProvider table -> SQLQuery) -> SQLQuery
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> queryBuilderProvider table -> SQLQuery
forall k (table :: Symbol) (queryBuilderProvider :: Symbol -> *)
       (joinRegister :: k).
(KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister) =>
queryBuilderProvider 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 (Table model => ByteString
forall record. Table record => 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 commonFetchOne #-}
commonFetchOne :: forall model table queryBuilderProvider joinRegister.(?modelContext :: ModelContext) => (Table model, KnownSymbol table, Fetchable (queryBuilderProvider table) model, HasQueryBuilder queryBuilderProvider joinRegister, PG.FromRow model) => queryBuilderProvider table -> IO model
commonFetchOne :: queryBuilderProvider table -> IO model
commonFetchOne !queryBuilderProvider table
queryBuilder = do
    Maybe model
maybeModel <- queryBuilderProvider table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing queryBuilderProvider 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 = queryBuilderProvider table -> (ByteString, [Action])
forall k (table :: Symbol) (queryBuilderProvider :: Symbol -> *)
       (joinRegister :: k).
(KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister) =>
queryBuilderProvider table -> (ByteString, [Action])
toSQL queryBuilderProvider 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 queryBuilderProvider joinRegister. (?modelContext :: ModelContext, KnownSymbol table, HasQueryBuilder queryBuilderProvider joinRegister) => queryBuilderProvider table -> IO Int
fetchCount :: queryBuilderProvider table -> IO Int
fetchCount !queryBuilderProvider table
queryBuilder = do
    let !(ByteString
theQuery', [Action]
theParameters) = SQLQuery -> (ByteString, [Action])
toSQL' (queryBuilderProvider table -> SQLQuery
forall k (table :: Symbol) (queryBuilderProvider :: Symbol -> *)
       (joinRegister :: k).
(KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister) =>
queryBuilderProvider table -> SQLQuery
buildQuery queryBuilderProvider 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 queryBuilderProvider joinRegister. (?modelContext :: ModelContext, KnownSymbol table, HasQueryBuilder queryBuilderProvider joinRegister) => queryBuilderProvider table -> IO Bool
fetchExists :: queryBuilderProvider table -> IO Bool
fetchExists !queryBuilderProvider table
queryBuilder = do
    let !(ByteString
theQuery', [Action]
theParameters) = SQLQuery -> (ByteString, [Action])
toSQL' (queryBuilderProvider table -> SQLQuery
forall k (table :: Symbol) (queryBuilderProvider :: Symbol -> *)
       (joinRegister :: k).
(KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister) =>
queryBuilderProvider table -> SQLQuery
buildQuery queryBuilderProvider 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. (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, Table model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, Table 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, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch

{-# INLINE genericfetchIdOneOrNothing #-}
genericfetchIdOneOrNothing :: forall table model. (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, Table model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, Table 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, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

{-# INLINE genericFetchIdOne #-}
genericFetchIdOne :: forall table model. (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, Table model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, Table 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, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

{-# INLINE genericFetchIds #-}
genericFetchIds :: forall table model value. (Table model, 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, Table model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, Table 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
       (queryBuilderProvider :: Symbol -> *) joinRegister.
(KnownSymbol table, KnownSymbol name, ToField value,
 HasField name model value, model ~ GetModelByTableName table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 EqOrIsOperator value, Table model) =>
(Proxy name, [value])
-> queryBuilderProvider table -> queryBuilderProvider 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, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch

{-# INLINE genericfetchIdsOneOrNothing #-}
genericfetchIdsOneOrNothing :: forall model value table. (Table model, 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, Table model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, Table 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
       (queryBuilderProvider :: Symbol -> *) joinRegister.
(KnownSymbol table, KnownSymbol name, ToField value,
 HasField name model value, model ~ GetModelByTableName table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 EqOrIsOperator value, Table model) =>
(Proxy name, [value])
-> queryBuilderProvider table -> queryBuilderProvider 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, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

{-# INLINE genericFetchIdsOne #-}
genericFetchIdsOne :: forall model value table. (Table model, 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, Table model, DefaultScope table) =>
QueryBuilder table
forall (table :: Symbol).
(table ~ GetTableName model, Table 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
       (queryBuilderProvider :: Symbol -> *) joinRegister.
(KnownSymbol table, KnownSymbol name, ToField value,
 HasField name model value, model ~ GetModelByTableName table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 EqOrIsOperator value, Table model) =>
(Proxy name, [value])
-> queryBuilderProvider table -> queryBuilderProvider 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, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

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

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

--findManyBy :: (?modelContext :: ModelContext, PG.FromRow model, KnownSymbol name, ToField value, HasField name value model) => Proxy name -> value -> QueryBuilder model -> IO [model]
{-# INLINE findManyBy #-}
findManyBy :: Proxy name
-> value
-> queryBuilderProvider table
-> IO (FetchResult (queryBuilderProvider table) model)
findManyBy !Proxy name
field !value
value !queryBuilderProvider table
queryBuilder = queryBuilderProvider table
queryBuilder queryBuilderProvider table
-> (queryBuilderProvider table -> queryBuilderProvider table)
-> queryBuilderProvider table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> (Proxy name, value)
-> queryBuilderProvider table -> queryBuilderProvider table
forall k (name :: Symbol) (table :: Symbol) model value
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(KnownSymbol table, KnownSymbol name, ToField value,
 HasField name model value, EqOrIsOperator value,
 model ~ GetModelByTableName table,
 HasQueryBuilder queryBuilderProvider joinRegister, Table model) =>
(Proxy name, value)
-> queryBuilderProvider table -> queryBuilderProvider table
filterWhere (Proxy name
field, value
value) queryBuilderProvider table
-> (queryBuilderProvider table
    -> IO (FetchResult (queryBuilderProvider table) model))
-> IO (FetchResult (queryBuilderProvider table) model)
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> queryBuilderProvider table
-> IO (FetchResult (queryBuilderProvider table) model)
forall fetchable model.
(Fetchable fetchable model, Table 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.
(Table 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.
(Table 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.
(Table 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.
(Table 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.
(Table 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.
(Table 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.
(Table model, 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).
(Table model, 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).
(Table model, KnownSymbol table, FromRow model,
 ?modelContext::ModelContext, ToField value, EqOrIsOperator value,
 HasField "id" model value, model ~ GetModelByTableName table,
 GetTableName model ~ table) =>
[value] -> IO model
genericFetchIdsOne

fetchSQLQuery :: (PG.FromRow model, ?modelContext :: ModelContext) => SQLQuery -> IO [model]
fetchSQLQuery :: SQLQuery -> IO [model]
fetchSQLQuery SQLQuery
theQuery = do
    let (ByteString
sql, [Action]
theParameters) = SQLQuery -> (ByteString, [Action])
toSQL' SQLQuery
theQuery
    (?modelContext::ModelContext) => ByteString -> IO ()
ByteString -> IO ()
trackTableRead (Proxy "selectFrom" -> SQLQuery -> ByteString
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "selectFrom" (Proxy "selectFrom")
Proxy "selectFrom"
#selectFrom SQLQuery
theQuery)
    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
sql) [Action]
theParameters

-- | Returns the latest record or Nothing
--
-- __Example:__
--
-- > latestUser <-
-- >     query @User
-- >         |> fetchLatest
-- >
--
-- 'fetchLatest' is mainly a shortcut for code like this:
--
-- > latestUser <-
-- >     query @User
-- >         |> orderByDesc #createdAt
-- >         |> fetchOneOrNothing
--
fetchLatest :: forall table queryBuilderProvider joinRegister model.
    ( ?modelContext :: ModelContext
    , model ~ GetModelByTableName table
    , KnownSymbol table
    , HasQueryBuilder queryBuilderProvider joinRegister
    , HasField "createdAt" model UTCTime
    , Fetchable (queryBuilderProvider table) model
    , Table model
    , FromRow model
    ) => queryBuilderProvider table -> IO (Maybe model)
fetchLatest :: queryBuilderProvider table -> IO (Maybe model)
fetchLatest queryBuilderProvider table
queryBuilder = queryBuilderProvider table
queryBuilder queryBuilderProvider table
-> (queryBuilderProvider table -> IO (Maybe model))
-> IO (Maybe model)
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Proxy "createdAt" -> queryBuilderProvider table -> IO (Maybe model)
forall k (table :: Symbol) (createdAt :: Symbol)
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k) model.
(?modelContext::ModelContext, KnownSymbol createdAt,
 model ~ GetModelByTableName table, KnownSymbol table,
 HasQueryBuilder queryBuilderProvider joinRegister,
 HasField createdAt model UTCTime,
 Fetchable (queryBuilderProvider table) model, Table model,
 FromRow model) =>
Proxy createdAt -> queryBuilderProvider table -> IO (Maybe model)
fetchLatestBy IsLabel "createdAt" (Proxy "createdAt")
Proxy "createdAt"
#createdAt

-- | Provided a field name, it returns the latest record or Nothing
--
-- See 'fetchLatest' if you're looking for the latest record by the createdAt timestamp.
--
-- __Example:__
--
-- > latestTrialUser <-
-- >     query @User
-- >         |> fetchLatestBy #trialStartedAt
-- >
--
-- 'fetchLatestBy' is mainly a shortcut for code like this:
--
-- > latestUser <-
-- >     query @User
-- >         |> orderByDesc #trialStartedAt
-- >         |> fetchOneOrNothing
--
fetchLatestBy :: forall table createdAt queryBuilderProvider joinRegister model.
    ( ?modelContext :: ModelContext
    , KnownSymbol createdAt
    , model ~ GetModelByTableName table
    , KnownSymbol table
    , HasQueryBuilder queryBuilderProvider joinRegister
    , HasField createdAt model UTCTime
    , Fetchable (queryBuilderProvider table) model
    , Table model
    , FromRow model
    ) => Proxy createdAt -> queryBuilderProvider table -> IO (Maybe model)
fetchLatestBy :: Proxy createdAt -> queryBuilderProvider table -> IO (Maybe model)
fetchLatestBy Proxy createdAt
field queryBuilderProvider table
queryBuilder =
    queryBuilderProvider table
queryBuilder
    queryBuilderProvider table
-> (queryBuilderProvider table -> queryBuilderProvider table)
-> queryBuilderProvider table
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Proxy createdAt
-> queryBuilderProvider table -> queryBuilderProvider table
forall k (name :: Symbol) model (table :: Symbol) value
       (queryBuilderProvider :: Symbol -> *) (joinRegister :: k).
(KnownSymbol table, KnownSymbol name, HasField name model value,
 model ~ GetModelByTableName table,
 HasQueryBuilder queryBuilderProvider joinRegister, Table model) =>
Proxy name
-> queryBuilderProvider table -> queryBuilderProvider table
orderByDesc Proxy createdAt
field
    queryBuilderProvider table
-> (queryBuilderProvider table -> IO (Maybe model))
-> IO (Maybe model)
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> queryBuilderProvider table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRow model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing