orville-postgresql-1.0.0.0: src/Orville/PostgreSQL/Execution/Select.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{- |
Copyright : Flipstone Technology Partners 2023
License : MIT
Stability : Stable
Functions for working with executable @SELECT@ statements. The 'Select' type is
a value that can be passed around and executed later. The 'Select' is directly
associated with how to decode the rows returned by the query. This means it
can be safely executed via 'executeSelect' and used to decode the rows. It is a
lower-level API than the entity select functions in
"Orville.PostgreSQL.Execution.EntityOperations", but not as primitive as
"Orville.PostgreSQL.Expr.Query".
@since 1.0.0.0
-}
module Orville.PostgreSQL.Execution.Select
( Select
, executeSelect
, useSelect
, selectToQueryExpr
, selectTable
, selectMarshalledColumns
, rawSelectQueryExpr
)
where
import qualified Orville.PostgreSQL.Execution.Execute as Execute
import qualified Orville.PostgreSQL.Execution.QueryType as QueryType
import qualified Orville.PostgreSQL.Execution.SelectOptions as SelectOptions
import qualified Orville.PostgreSQL.Expr as Expr
import Orville.PostgreSQL.Marshall.SqlMarshaller (AnnotatedSqlMarshaller, marshallerDerivedColumns, unannotatedSqlMarshaller)
import qualified Orville.PostgreSQL.Monad as Monad
import Orville.PostgreSQL.Schema (TableDefinition, tableMarshaller, tableName)
{- |
Represents a @SELECT@ statement that can be executed against a database. A
'Select' has a 'Orville.PostgreSQL.SqlMarshaller' bound to it that will be
used to decode the database result set when it is executed.
@since 1.0.0.0
-}
data Select readEntity where
Select :: AnnotatedSqlMarshaller writeEntity readEntity -> Expr.QueryExpr -> Select readEntity
{- |
Extracts the query that will be run when the select is executed. Normally you
don't want to extract the query and run it yourself, but this function is
useful to view the query for debugging or query explanation.
@since 1.0.0.0
-}
selectToQueryExpr :: Select readEntity -> Expr.QueryExpr
selectToQueryExpr (Select _ query) = query
{- |
Executes the database query for the 'Select' and uses its
'Orville.PostgreSQL.SqlMarshaller' to decode the result set.
@since 1.0.0.0
-}
executeSelect :: Monad.MonadOrville m => Select row -> m [row]
executeSelect =
useSelect (Execute.executeAndDecode QueryType.SelectQuery)
{- |
Runs a function allowing it to use the data elements containted within the
'Select' it pleases. The marshaller that the function is provided can be use
to decode results from the query.
@since 1.0.0.0
-}
useSelect ::
( forall writeEntity.
Expr.QueryExpr ->
AnnotatedSqlMarshaller writeEntity readEntity ->
a
) ->
Select readEntity ->
a
useSelect f (Select marshaller query) =
f query marshaller
{- |
Builds a 'Select' that will select all the columns described in the
'TableDefinition'. This is the safest way to build a 'Select', because table
name and columns are all read from the 'TableDefinition'. If the table is
being managed with Orville auto-migrations, this will match the schema in the
database.
@since 1.0.0.0
-}
selectTable ::
TableDefinition key writeEntity readEntity ->
SelectOptions.SelectOptions ->
Select readEntity
selectTable tableDef =
selectMarshalledColumns (tableMarshaller tableDef) (tableName tableDef)
{- |
Builds a 'Select' that will select the columns described by the marshaller
from the specified table. It is up to the caller to ensure that the columns
in the marshaller make sense for the table.
This function is useful for querying a subset of table columns using a custom
marshaller.
@since 1.0.0.0
-}
selectMarshalledColumns ::
AnnotatedSqlMarshaller writeEntity readEntity ->
Expr.Qualified Expr.TableName ->
SelectOptions.SelectOptions ->
Select readEntity
selectMarshalledColumns marshaller qualifiedTableName selectOptions =
rawSelectQueryExpr marshaller $
SelectOptions.selectOptionsQueryExpr
(Expr.selectDerivedColumns (marshallerDerivedColumns . unannotatedSqlMarshaller $ marshaller))
(Expr.referencesTable qualifiedTableName)
selectOptions
{- |
Builds a 'Select' that will execute the specified query and use the given
'Orville.PostgreSQL.SqlMarshaller' to decode it. It is up to the caller to
ensure that the given 'Expr.QueryExpr' makes sense and produces a result set
that the 'Orville.PostgreSQL.SqlMarshaller' can decode.
This is the lowest level of escape hatch available for 'Select'. The caller
can build any query that Orville supports using the expression-building
functions, or use @RawSql.fromRawSql@ to build a raw 'Expr.QueryExpr'.
@since 1.0.0.0
-}
rawSelectQueryExpr ::
AnnotatedSqlMarshaller writeEntity readEntity ->
Expr.QueryExpr ->
Select readEntity
rawSelectQueryExpr = Select