Copyright | Flipstone Technology Partners 2023 |
---|---|
License | MIT |
Stability | Stable |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Since: 1.0.0.0
Synopsis
- data Plan scope param result
- data Planned scope param a
- data Execute
- data Explain
- askParam :: Plan scope param param
- execute :: MonadOrville m => Plan Execute param result -> param -> m result
- explain :: Plan Explain param result -> [String]
- findMaybeOne :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue (Maybe readEntity)
- findMaybeOneWhere :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue (Maybe readEntity)
- findOne :: (Show fieldValue, Ord fieldValue) => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue readEntity
- findOneShowVia :: Ord fieldValue => (fieldValue -> String) -> TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue readEntity
- findOneWhere :: (Show fieldValue, Ord fieldValue) => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue readEntity
- findOneWhereShowVia :: Ord fieldValue => (fieldValue -> String) -> TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue readEntity
- findAll :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue [readEntity]
- findAllWhere :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue [readEntity]
- bind :: Plan scope param a -> (Planned scope param a -> Plan scope param result) -> Plan scope param result
- use :: Planned scope param a -> Plan scope param a
- using :: Planned scope param a -> Plan scope a b -> Plan scope param b
- chain :: Plan scope a b -> Plan scope b c -> Plan scope a c
- chainMaybe :: Plan scope a (Maybe b) -> Plan scope b (Maybe c) -> Plan scope a (Maybe c)
- apply :: Plan scope param (a -> b) -> Plan scope param a -> Plan scope param b
- planMany :: (forall manyScope. Plan manyScope param result) -> Plan scope [param] (Many param result)
- planList :: (forall scope. Plan scope param result) -> Plan listScope [param] [result]
- focusParam :: (a -> b) -> Plan scope b result -> Plan scope a result
- planEither :: Plan scope leftParam leftResult -> Plan scope rightParam rightResult -> Plan scope (Either leftParam rightParam) (Either leftResult rightResult)
- planMaybe :: Plan scope a b -> Plan scope (Maybe a) (Maybe b)
- data AssertionFailed
- assert :: (param -> a -> Either String b) -> Plan scope param a -> Plan scope param b
- planSelect :: Select row -> Plan scope () [row]
- planOperation :: Operation param result -> Plan scope param result
Documentation
data Plan scope param result Source #
A Plan
is an executable set of queries that can be executed to load data
from the database, using the results of prior queries as input parameters to
following queries in controlled ways. In particular, the "controlled" aspect
of this allows plans that take a single input to be adapted to take multiple
input parameters in a list without the resulting plan executing N+1 queries.
This restriction means that while query results can be used as input
parameters to later queries, they cannot be used to decide to run completely
different queries based on other query results. Allowing this would prevent
the Plan
structure from eliminating N+1 query loops.
Note that during execution, queries are never combined across tables to form
joins or subqueries. Queries are still executed in the same sequence as
specified in the plan, just on all the inputs at once rather than in a loop.
If you need to do a join with a plan, you can always construct your own
custom Operation
and use planOperation
to incorporate it into a plan.
The param
type variable indicates what type of value is expected as input
when the plan is executed.
The result
type for a plan indicates what Haskell type is produced
when the plan is executed.
The scope
type is used internally by Orville to track how the plan is
currently executed against a single input or multiple inputs. This type
parameter should never be specified as a concrete type in user code, but must
be exposed as a variable to ensure that execute scope is tracked correctly
through usages of bind
.
Since: 1.0.0.0
Instances
Applicative (Plan scope param) Source # | |
Defined in Orville.PostgreSQL.Plan pure :: a -> Plan scope param a # (<*>) :: Plan scope param (a -> b) -> Plan scope param a -> Plan scope param b # liftA2 :: (a -> b -> c) -> Plan scope param a -> Plan scope param b -> Plan scope param c # (*>) :: Plan scope param a -> Plan scope param b -> Plan scope param b # (<*) :: Plan scope param a -> Plan scope param b -> Plan scope param a # | |
Functor (Plan scope param) Source # | |
data Planned scope param a Source #
A Planned
value is a wrapper around the results of previously-run queries
when using the bind
function. At the time that you are writing a plan, you
do not know whether the Plan
will be run with a single input or multiple
inputs. A Planned
value may end up being either an individual item or a
list of items. Due to this, your ability to interact with the value is
limited to the use of fmap
to extract (or build) other values from the
results. Planned
values can be used together with the use
function to
make a Plan
that produces the extracted value.
Note that while Planned
could provide an Applicative
instance as well, it
does not to avoid confusion with the Applicative
instance for Plan
itself. If you need to build a value from several Planned
values using
Applicative
, you should call use
on each of the values and use the
Applicative
instance for Plan
.
Since: 1.0.0.0
Using a Plan after it is constructed
execute :: MonadOrville m => Plan Execute param result -> param -> m result Source #
execute
accepts the input parameter (or parameters) expected by a Plan
and runs the plan to completion, either throwing an AssertionFailed
exception in the monad m
or producing the expected result.
If you have a plan that takes one input and want to provide a list of
input, use planMany
to adapt it to a multple-input plan before calling
execute
.
Since: 1.0.0.0
Making a Plan to find rows in the database
findMaybeOne :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue (Maybe readEntity) Source #
findMaybeOne
constructs a Plan
that will find at most one row from
the given table where the plan's input value matches the given database
field.
Since: 1.0.0.0
findMaybeOneWhere :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue (Maybe readEntity) Source #
findMaybeOneWhere
is similar to findMaybeOne
, but allows a
BooleanExpr
to be specified to restrict which rows are matched by the
database query.
Since: 1.0.0.0
findOne :: (Show fieldValue, Ord fieldValue) => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue readEntity Source #
findOne
is an alias to findOneShowVia
that uses the Show
instance of
fieldValue
when producing a failure message in the event that the entity
cannot be found.
Since: 1.0.0.0
findOneShowVia :: Ord fieldValue => (fieldValue -> String) -> TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue readEntity Source #
findOneShowVia
is similar to findMaybeOne
, but it expects that there will
always be a row found matching the plan's input value. If no row is found, an
AssertionFailed
exception will be thrown. This is a useful convenience
when looking up foreign-key associations that are expected to be enforced by
the database itself.
Since: 1.0.0.0
findOneWhere :: (Show fieldValue, Ord fieldValue) => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue readEntity Source #
findOneWhere
is an alias to findOneWhereShowVia
that uses the Show
instance of fieldValue
when producing a failure message in the event that
the entity cannot be found.
Since: 1.0.0.0
findOneWhereShowVia :: Ord fieldValue => (fieldValue -> String) -> TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue readEntity Source #
findOneWhereShowVia
is similar to findOneShowVia
, but allows a
BooleanExpr
to be specified to restrict which rows are matched by the
database query.
Since: 1.0.0.0
findAll :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> Plan scope fieldValue [readEntity] Source #
findAllWhere :: Ord fieldValue => TableDefinition key writeEntity readEntity -> FieldDefinition nullability fieldValue -> BooleanExpr -> Plan scope fieldValue [readEntity] Source #
findAllWhere
is similar to findAll
, but allows a BooleanExpr
to be
specified to restrict which rows are matched by the database query.
Since: 1.0.0.0
Creating a multi-step Plan from other Plan values
bind :: Plan scope param a -> (Planned scope param a -> Plan scope param result) -> Plan scope param result Source #
bind
gives access to the results of a plan to use as input values to future
plans. The plan result is given the input parameter to the provided function,
which must produce the remaining Plan
to be executed. The value will be
wrapped in the Planned
type, which may represent either a result or
multiple results, depending on whether one plan is currently being executed
with one and multiple input parameters. This ensures that the caller produces
only a single remaining Plan
to be used for all inputs when there are
multiple to eliminate the need to possibly run different queries for
different inputs (which would an introduce N+1 query execution).
The Planned
value (or values) provided by bind
have actually been
retrieved from the database, so the value can be used multiple times when
constructing the remaining Plan
without fear of causing the query to run
multiple times.
Also see use
for how to lift a Planned
value back into a Plan
.
Since: 1.0.0.0
chain :: Plan scope a b -> Plan scope b c -> Plan scope a c Source #
chain
connects the output of one plan to the input of another to form a
larger plan that will execute the first followed by the second.
Since: 1.0.0.0
chainMaybe :: Plan scope a (Maybe b) -> Plan scope b (Maybe c) -> Plan scope a (Maybe c) Source #
chainMaybe
connects two plans that both yield Maybes.
If the first plan yields no result, the second is skipped.
See also chain
.
Since: 1.0.0.0
apply :: Plan scope param (a -> b) -> Plan scope param a -> Plan scope param b Source #
apply
applies a function produced by a plan to the value produced
by another plan. This is usually used via the <*>
operator through
the Applicative
instance for Plan
.
Since: 1.0.0.0
planMany :: (forall manyScope. Plan manyScope param result) -> Plan scope [param] (Many param result) Source #
planMany
adapts a plan that takes a single input parameter to work on
multiple input parameters. When the new plan is executed, each query will
execute in the same basic order, but with adjusted conditions to find all the
rows for all inputs at once rather than running the planned queries once for
each input.
Since: 1.0.0.0
planList :: (forall scope. Plan scope param result) -> Plan listScope [param] [result] Source #
planList
lifts a plan so both its param and result become lists. This saves
you from having to fmap in elems
when all you want back from a Many
is the list of results inside it.
There will always be the same number of elements in the [result]
list as
there are in the [param]
list, even if there are duplicate values in the
input parameters. This may be counter-intuitive in the trivial case where a
plan that queries a single table is passed to planList
but cannot be
avoided due to more complicated situations where the original plan executes
queries against multiple tables. When a plan that queries multiple tables is
passed, the query results must be correlated based on the input parameters to
build each result
value.
Since: 1.0.0.0
focusParam :: (a -> b) -> Plan scope b result -> Plan scope a result Source #
focusParam
builds a plan from a function and an existing plan, taking the
result of that function as input. This is especially useful when there is
some structure, and a plan that only needs a part of that structure as input.
The function argument can access part of the structure for the plan argument
to use, so the final returned plan can take the entire structure as input.
Since: 1.0.0.0
planEither :: Plan scope leftParam leftResult -> Plan scope rightParam rightResult -> Plan scope (Either leftParam rightParam) (Either leftResult rightResult) Source #
planEither
lets you construct a plan that branches by executing a different
plan for the Left
and Right
sides of an Either
value. When used with a
single input parameter, only one of the two plans will be used, based on the
input parameter. When used on multiple input parameters, each of the two
plans will be executed only once with all the Left
and Right
values
provided as input parameters respectively.
Since: 1.0.0.0
Bridges from other types into Plan
data AssertionFailed Source #
AssertionFailed
may be returned from the execute functions of an
Operation
to indicate that some expected invariant has failed. For example,
following a foreign key that is enforced by the database only to find that no
record exists. When an Operation
returns an AssertionFailed
value during
plan execution, the error is thrown as an exception using the
MonadThrow
instance for whatever monad the plan is
executing in.
Since: 1.0.0.0
Instances
Exception AssertionFailed Source # | |
Defined in Orville.PostgreSQL.Plan.Operation | |
Show AssertionFailed Source # | |
Defined in Orville.PostgreSQL.Plan.Operation showsPrec :: Int -> AssertionFailed -> ShowS # show :: AssertionFailed -> String # showList :: [AssertionFailed] -> ShowS # |
assert :: (param -> a -> Either String b) -> Plan scope param a -> Plan scope param b Source #
assert
allows you to make an assertion about a plan's result that will
throw an AssertionFailed
exception during execution if it proves to be
false. The first parameter is the assertion function, which should return
either an error message to be given in the exception or the value to be used
as the plan's result.
Since: 1.0.0.0
planSelect :: Select row -> Plan scope () [row] Source #
planSelect
allows any Orville Select
query to be incorporated into a
plan. Note that the Select
cannot depend on the plan's input parameters in
this case. If the plan is executed with multiple inputs, the same set of all
the results will be used as the results for each of the input parameters.
Since: 1.0.0.0
planOperation :: Operation param result -> Plan scope param result Source #
planOperation
allows any primitive Operation
to be used as an atomic step
in a plan. When the plan is executed, the appropriate Operation
functions
will be used depending on the execution context.
Since: 1.0.0.0