on c776efd help sign in
rel8/src/Rel8/Query/Maybe.hs
60 lines 2.0 kB history raw
1module Rel8.Query.Maybe
2 ( optional
3 , catMaybeTable
4 , traverseMaybeTable
5 )
6where
8-- base
9import Prelude
11-- opaleye
12import qualified Opaleye.Internal.MaybeFields as Opaleye
14-- rel8
15import Rel8.Expr.Eq ( (==.) )
16import Rel8.Expr.Opaleye ( fromColumn, fromPrimExpr )
17import Rel8.Query ( Query )
18import Rel8.Query.Filter ( where_ )
19import Rel8.Query.Opaleye ( mapOpaleye )
20import Rel8.Table.Maybe ( MaybeTable( MaybeTable ), isJustTable )
21import Rel8.Table.Tag ( Tag(..), fromExpr )
24-- | Convert a query that might return zero rows to a query that always returns
25-- at least one row.
26--
27-- To speak in more concrete terms, 'optional' is most useful to write @LEFT
28-- JOIN@s.
29optional :: Query a -> Query (MaybeTable a)
30optional =
31 mapOpaleye $
32 Opaleye.optionalInternal $
33 MaybeTable . fromExpr . fromPrimExpr . fromColumn
36-- | Filter out 'MaybeTable's, returning only the tables that are not-null.
37--
38-- This operation can be used to "undo" the effect of 'optional', which
39-- operationally is like turning a @LEFT JOIN@ back into a full @JOIN@. You
40-- can think of this as analogous to 'Data.Maybe.catMaybes'.
41catMaybeTable :: MaybeTable a -> Query a
42catMaybeTable ma@(MaybeTable _ a) = do
43 where_ $ isJustTable ma
44 pure a
47-- | Extend an optional query with another query. This is useful if you want
48-- to step through multiple @LEFT JOINs@.
49--
50-- Note that @traverseMaybeTable@ takes a @a -> Query b@ function, which means
51-- you also have the ability to "expand" one row into multiple rows. If the
52-- @a -> Query b@ function returns no rows, then the resulting query will also
53-- have no rows. However, regardless of the given @a -> Query b@ function, if
54-- the input is @nothingTable@, you will always get exactly one @nothingTable@
55-- back.
56traverseMaybeTable :: (a -> Query b) -> MaybeTable a -> Query (MaybeTable b)
57traverseMaybeTable query ma@(MaybeTable input _) = do
58 MaybeTable output b <- optional (query =<< catMaybeTable ma)
59 where_ $ expr output ==. expr input
60 pure $ MaybeTable input b