{-# LANGUAGE BangPatterns, TypeFamilies, DataKinds, PolyKinds, TypeApplications, ScopedTypeVariables, 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
, genericFetchId
, genericfetchIdOneOrNothing
, genericFetchIdOne
, Fetchable (..)
, genericFetchIds
, genericfetchIdsOneOrNothing
, genericFetchIdsOne
, fetchCount
, fetchExists
, fetchVector
, fetchLatest
, fetchLatestBy
)
where

import IHP.Prelude
import IHP.ModelSupport
import IHP.QueryBuilder
import IHP.Hasql.FromRow (FromRowHasql(..))
import Hasql.Implicits.Encoders (DefaultParamEncoder)
import IHP.Fetch.Statement (buildQueryListStatement, buildQueryVectorStatement, buildQueryMaybeStatement, buildCountStatement, buildExistsStatement)

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

instance (model ~ GetModelByTableName table, KnownSymbol table) => Fetchable (QueryBuilder table) model where
    type instance FetchResult (QueryBuilder table) model = [model]
    fetch :: (Table model, FromRowHasql model, ?modelContext :: ModelContext) => QueryBuilder table -> IO [model]
    fetch :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
QueryBuilder table -> IO [model]
fetch !QueryBuilder table
queryBuilder = do
        (?modelContext::ModelContext) => Text -> IO ()
Text -> IO ()
trackTableRead (forall record. Table record => Text
tableName @model)
        let pool :: Pool
pool = ?modelContext::ModelContext
ModelContext
?modelContext.hasqlPool
        Pool -> () -> Statement () [model] -> IO [model]
forall a b.
(?modelContext::ModelContext) =>
Pool -> a -> Statement a b -> IO b
sqlStatementHasql Pool
pool () (QueryBuilder table -> Statement () [model]
forall model (table :: Symbol).
(Table model, model ~ GetModelByTableName table, KnownSymbol table,
 FromRowHasql model) =>
QueryBuilder table -> Statement () [model]
buildQueryListStatement QueryBuilder table
queryBuilder)

    fetchOneOrNothing :: (?modelContext :: ModelContext) => (Table model, FromRowHasql model) => QueryBuilder table -> IO (Maybe model)
    fetchOneOrNothing :: (?modelContext::ModelContext, Table model, FromRowHasql model) =>
QueryBuilder table -> IO (Maybe model)
fetchOneOrNothing !QueryBuilder table
queryBuilder = do
        (?modelContext::ModelContext) => Text -> IO ()
Text -> IO ()
trackTableRead (forall record. Table record => Text
tableName @model)
        let pool :: Pool
pool = ?modelContext::ModelContext
ModelContext
?modelContext.hasqlPool
        Pool -> () -> Statement () (Maybe model) -> IO (Maybe model)
forall a b.
(?modelContext::ModelContext) =>
Pool -> a -> Statement a b -> IO b
sqlStatementHasql Pool
pool () (QueryBuilder table -> Statement () (Maybe model)
forall model (table :: Symbol).
(Table model, model ~ GetModelByTableName table, KnownSymbol table,
 FromRowHasql model) =>
QueryBuilder table -> Statement () (Maybe model)
buildQueryMaybeStatement QueryBuilder table
queryBuilder)

    fetchOne :: (?modelContext :: ModelContext) => (Table model, FromRowHasql model) => QueryBuilder table -> IO model
    fetchOne :: (?modelContext::ModelContext, Table model, FromRowHasql model) =>
QueryBuilder table -> IO model
fetchOne !QueryBuilder table
queryBuilder = do
        maybeModel <- QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing QueryBuilder table
queryBuilder
        case maybeModel of
            Just model
model -> model -> IO model
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure model
model
            Maybe model
Nothing -> RecordNotFoundException -> IO model
forall (m :: * -> *) e a.
(HasCallStack, MonadThrow m, Exception e) =>
e -> m a
throwIO RecordNotFoundException { queryAndParams :: Text
queryAndParams = QueryBuilder table -> Text
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> Text
toSQL QueryBuilder table
queryBuilder }


-- | Like 'fetch', but returns a 'Vector' instead of a list for better performance
-- with large result sets.
--
-- __Example:__ Fetching all users as a Vector
--
-- > allUsers <- query @User |> fetchVector
--
-- __Example:__ Fetching with filters
--
-- > activeUsers <- query @User
-- >     |> filterWhere (#active, True)
-- >     |> fetchVector
fetchVector :: forall model table. (Table model, model ~ GetModelByTableName table, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext) => QueryBuilder table -> IO (Vector model)
fetchVector :: forall model (table :: Symbol).
(Table model, model ~ GetModelByTableName table, KnownSymbol table,
 FromRowHasql model, ?modelContext::ModelContext) =>
QueryBuilder table -> IO (Vector model)
fetchVector !QueryBuilder table
queryBuilder = do
    (?modelContext::ModelContext) => Text -> IO ()
Text -> IO ()
trackTableRead (forall record. Table record => Text
tableName @model)
    let pool :: Pool
pool = ?modelContext::ModelContext
ModelContext
?modelContext.hasqlPool
    Pool -> () -> Statement () (Vector model) -> IO (Vector model)
forall a b.
(?modelContext::ModelContext) =>
Pool -> a -> Statement a b -> IO b
sqlStatementHasql Pool
pool () (QueryBuilder table -> Statement () (Vector model)
forall model (table :: Symbol).
(Table model, model ~ GetModelByTableName table, KnownSymbol table,
 FromRowHasql model) =>
QueryBuilder table -> Statement () (Vector model)
buildQueryVectorStatement 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 :: forall (table :: Symbol).
(?modelContext::ModelContext, KnownSymbol table) =>
QueryBuilder table -> IO Int
fetchCount !QueryBuilder table
queryBuilder = do
    (?modelContext::ModelContext) => Text -> IO ()
Text -> IO ()
trackTableRead (forall (symbol :: Symbol). KnownSymbol symbol => Text
symbolToText @table)
    let pool :: Pool
pool = ?modelContext::ModelContext
ModelContext
?modelContext.hasqlPool
    Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Int) -> IO Int64 -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Pool -> () -> Statement () Int64 -> IO Int64
forall a b.
(?modelContext::ModelContext) =>
Pool -> a -> Statement a b -> IO b
sqlStatementHasql Pool
pool () (QueryBuilder table -> Statement () Int64
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> Statement () Int64
buildCountStatement QueryBuilder table
queryBuilder)

-- | 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 :: forall (table :: Symbol).
(?modelContext::ModelContext, KnownSymbol table) =>
QueryBuilder table -> IO Bool
fetchExists !QueryBuilder table
queryBuilder = do
    (?modelContext::ModelContext) => Text -> IO ()
Text -> IO ()
trackTableRead (forall (symbol :: Symbol). KnownSymbol symbol => Text
symbolToText @table)
    let pool :: Pool
pool = ?modelContext::ModelContext
ModelContext
?modelContext.hasqlPool
    Pool -> () -> Statement () Bool -> IO Bool
forall a b.
(?modelContext::ModelContext) =>
Pool -> a -> Statement a b -> IO b
sqlStatementHasql Pool
pool () (QueryBuilder table -> Statement () Bool
forall (table :: Symbol).
KnownSymbol table =>
QueryBuilder table -> Statement () Bool
buildExistsStatement QueryBuilder table
queryBuilder)

genericFetchId :: forall table model. (Table model, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext, model ~ GetModelByTableName table, GetTableName model ~ table, FilterPrimaryKey table) => Id' table -> IO [model]
genericFetchId :: forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO [model]
genericFetchId !Id' table
id = forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> 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 a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO [model]
QueryBuilder table -> IO (FetchResult (QueryBuilder table) model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch

genericfetchIdOneOrNothing :: forall table model. (Table model, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext, model ~ GetModelByTableName table, GetTableName model ~ table, FilterPrimaryKey table) => Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing :: forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing !Id' table
id = forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> 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 a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

genericFetchIdOne :: forall table model. (Table model, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext, model ~ GetModelByTableName table, GetTableName model ~ table, FilterPrimaryKey table) => Id' table -> IO model
genericFetchIdOne :: forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO model
genericFetchIdOne !Id' table
id = forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> 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 a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO model
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

genericFetchIds :: forall table model. (Table model, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext, model ~ GetModelByTableName table, GetTableName model ~ table, DefaultParamEncoder [PrimaryKey (GetTableName model)]) => [Id model] -> IO [model]
genericFetchIds :: forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> IO [model]
genericFetchIds ![Id model]
ids = forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> [Id model] -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol) model.
(KnownSymbol table, Table model, model ~ GetModelByTableName table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> QueryBuilder table -> QueryBuilder table
filterWhereIdIn [Id model]
ids QueryBuilder table
-> (QueryBuilder table -> IO [model]) -> IO [model]
forall a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO [model]
QueryBuilder table -> IO (FetchResult (QueryBuilder table) model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO (FetchResult fetchable model)
fetch

genericfetchIdsOneOrNothing :: forall table model. (Table model, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext, model ~ GetModelByTableName table, GetTableName model ~ table, DefaultParamEncoder [PrimaryKey (GetTableName model)]) => [Id model] -> IO (Maybe model)
genericfetchIdsOneOrNothing :: forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> IO (Maybe model)
genericfetchIdsOneOrNothing ![Id model]
ids = forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> [Id model] -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol) model.
(KnownSymbol table, Table model, model ~ GetModelByTableName table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> QueryBuilder table -> QueryBuilder table
filterWhereIdIn [Id model]
ids QueryBuilder table
-> (QueryBuilder table -> IO (Maybe model)) -> IO (Maybe model)
forall a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing

genericFetchIdsOne :: forall table model. (Table model, KnownSymbol table, FromRowHasql model, ?modelContext :: ModelContext, model ~ GetModelByTableName table, GetTableName model ~ table, DefaultParamEncoder [PrimaryKey (GetTableName model)]) => [Id model] -> IO model
genericFetchIdsOne :: forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> IO model
genericFetchIdsOne ![Id model]
ids = forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @model QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> [Id model] -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol) model.
(KnownSymbol table, Table model, model ~ GetModelByTableName table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> QueryBuilder table -> QueryBuilder table
filterWhereIdIn [Id model]
ids QueryBuilder table -> (QueryBuilder table -> IO model) -> IO model
forall a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO model
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

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 a b. a -> (a -> b) -> b
|> (Proxy name, value) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol table, KnownSymbol name, DefaultParamEncoder value,
 HasField name model value, EqOrIsOperator value,
 model ~ GetModelByTableName table, Table model) =>
(Proxy name, value) -> QueryBuilder table -> QueryBuilder table
filterWhere (Proxy name
field, value
value) QueryBuilder table
-> (QueryBuilder table -> IO (GetModelByTableName table))
-> IO (GetModelByTableName table)
forall a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO (GetModelByTableName table)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO model
fetchOne

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 a b. a -> (a -> b) -> b
|> (Proxy name, value) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol table, KnownSymbol name, DefaultParamEncoder value,
 HasField name model value, EqOrIsOperator value,
 model ~ GetModelByTableName table, Table model) =>
(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 a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO (Maybe (GetModelByTableName table))
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql 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]
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 a b. a -> (a -> b) -> b
|> (Proxy name, value) -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) (table :: Symbol) model value.
(KnownSymbol table, KnownSymbol name, DefaultParamEncoder value,
 HasField name model value, EqOrIsOperator value,
 model ~ GetModelByTableName table, Table model) =>
(Proxy name, value) -> QueryBuilder table -> QueryBuilder table
filterWhere (Proxy name
field, value
value) QueryBuilder table
-> (QueryBuilder table -> IO [GetModelByTableName table])
-> IO [GetModelByTableName table]
forall a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO [GetModelByTableName table]
QueryBuilder table
-> IO
     (FetchResult (QueryBuilder table) (GetModelByTableName table))
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql 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
    fetch :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
Id' table -> IO (FetchResult (Id' table) model)
fetch = Id' table -> IO model
Id' table -> IO (FetchResult (Id' table) model)
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO model
genericFetchIdOne
    fetchOneOrNothing :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
Id' table -> IO (Maybe model)
fetchOneOrNothing = Id' table -> IO (Maybe model)
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing
    fetchOne :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
Id' table -> IO model
fetchOne = Id' table -> IO model
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey 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]
    fetch :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
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, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO [model]
genericFetchId Id' table
a
    fetch Maybe (Id' table)
Nothing = [model] -> IO [model]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
    fetchOneOrNothing :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
Maybe (Id' table) -> IO (Maybe model)
fetchOneOrNothing Maybe (Id' table)
Nothing = Maybe model -> IO (Maybe model)
forall a. a -> IO a
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, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey table) =>
Id' table -> IO (Maybe model)
genericfetchIdOneOrNothing Id' table
a
    fetchOne :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
Maybe (Id' table) -> IO model
fetchOne (Just Id' table
a) = Id' table -> IO model
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table, FilterPrimaryKey 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), GetModelByTableName table ~ model, GetTableName model ~ table, DefaultParamEncoder [PrimaryKey table]) => Fetchable [Id' table] model where
    type FetchResult [Id' table] model = [model]
    fetch :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
[Id' table] -> IO (FetchResult [Id' table] model)
fetch = [Id' table] -> IO (FetchResult [Id' table] model)
[Id (GetModelByTableName table)] -> IO [GetModelByTableName table]
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> IO [model]
genericFetchIds
    fetchOneOrNothing :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
[Id' table] -> IO (Maybe model)
fetchOneOrNothing = [Id' table] -> IO (Maybe model)
[Id model] -> IO (Maybe model)
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> IO (Maybe model)
genericfetchIdsOneOrNothing
    fetchOne :: (Table model, FromRowHasql model, ?modelContext::ModelContext) =>
[Id' table] -> IO model
fetchOne = [Id' table] -> IO model
[Id model] -> IO model
forall (table :: Symbol) model.
(Table model, KnownSymbol table, FromRowHasql model,
 ?modelContext::ModelContext, model ~ GetModelByTableName table,
 GetTableName model ~ table,
 DefaultParamEncoder [PrimaryKey (GetTableName model)]) =>
[Id model] -> IO model
genericFetchIdsOne

-- | 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 model.
    ( ?modelContext :: ModelContext
    , model ~ GetModelByTableName table
    , KnownSymbol table
    , HasField "createdAt" model UTCTime
    , Table model
    , FromRowHasql model
    ) => QueryBuilder table -> IO (Maybe model)
fetchLatest :: forall (table :: Symbol) model.
(?modelContext::ModelContext, model ~ GetModelByTableName table,
 KnownSymbol table, HasField "createdAt" model UTCTime, Table model,
 FromRowHasql model) =>
QueryBuilder table -> IO (Maybe model)
fetchLatest QueryBuilder table
queryBuilder = QueryBuilder table
queryBuilder QueryBuilder table
-> (QueryBuilder table -> IO (Maybe model)) -> IO (Maybe model)
forall a b. a -> (a -> b) -> b
|> Proxy "createdAt" -> QueryBuilder table -> IO (Maybe model)
forall (table :: Symbol) (createdAt :: Symbol) model.
(?modelContext::ModelContext, KnownSymbol createdAt,
 model ~ GetModelByTableName table, KnownSymbol table,
 HasField createdAt model UTCTime, Table model,
 FromRowHasql model) =>
Proxy createdAt -> QueryBuilder table -> IO (Maybe model)
fetchLatestBy 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 model.
    ( ?modelContext :: ModelContext
    , KnownSymbol createdAt
    , model ~ GetModelByTableName table
    , KnownSymbol table
    , HasField createdAt model UTCTime
    , Table model
    , FromRowHasql model
    ) => Proxy createdAt -> QueryBuilder table -> IO (Maybe model)
fetchLatestBy :: forall (table :: Symbol) (createdAt :: Symbol) model.
(?modelContext::ModelContext, KnownSymbol createdAt,
 model ~ GetModelByTableName table, KnownSymbol table,
 HasField createdAt model UTCTime, Table model,
 FromRowHasql model) =>
Proxy createdAt -> QueryBuilder table -> IO (Maybe model)
fetchLatestBy Proxy createdAt
field QueryBuilder table
queryBuilder =
    QueryBuilder table
queryBuilder
    QueryBuilder table
-> (QueryBuilder table -> QueryBuilder table) -> QueryBuilder table
forall a b. a -> (a -> b) -> b
|> Proxy createdAt -> QueryBuilder table -> QueryBuilder table
forall (name :: Symbol) model (table :: Symbol) value.
(KnownSymbol table, KnownSymbol name, HasField name model value,
 model ~ GetModelByTableName table, Table model) =>
Proxy name -> QueryBuilder table -> QueryBuilder table
orderByDesc Proxy createdAt
field
    QueryBuilder table
-> (QueryBuilder table -> IO (Maybe model)) -> IO (Maybe model)
forall a b. a -> (a -> b) -> b
|> QueryBuilder table -> IO (Maybe model)
forall fetchable model.
(Fetchable fetchable model, Table model, FromRowHasql model,
 ?modelContext::ModelContext) =>
fetchable -> IO (Maybe model)
fetchOneOrNothing