rel8-1.7.0.0: src/Rel8/Query/These.hs
{-# language FlexibleContexts #-}
{-# language GADTs #-}
module Rel8.Query.These
( alignBy
, keepHereTable, loseHereTable
, keepThereTable, loseThereTable
, keepThisTable, loseThisTable
, keepThatTable, loseThatTable
, keepThoseTable, loseThoseTable
, bitraverseTheseTable
)
where
-- base
import Prelude
-- comonad
import Control.Comonad ( extract )
-- opaleye
import qualified Opaleye.Internal.PackMap as Opaleye
import qualified Opaleye.Internal.PrimQuery as Opaleye
import qualified Opaleye.Internal.QueryArr as Opaleye
import qualified Opaleye.Internal.Tag as Opaleye
-- rel8
import Rel8.Expr ( Expr )
import Rel8.Expr.Bool ( boolExpr, not_ )
import Rel8.Expr.Eq ( (==.) )
import Rel8.Expr.Opaleye ( toPrimExpr, traversePrimExpr )
import Rel8.Expr.Serialize ( litExpr )
import Rel8.Query ( Query )
import Rel8.Query.Filter ( where_ )
import Rel8.Query.Maybe ( optional )
import Rel8.Query.Opaleye ( zipOpaleyeWith )
import Rel8.Table.Either ( EitherTable( EitherTable ) )
import Rel8.Table.Maybe ( MaybeTable( MaybeTable ), isJustTable )
import Rel8.Table.These
( TheseTable( TheseTable, here, there )
, hasHereTable, hasThereTable
, isThisTable, isThatTable, isThoseTable
)
import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ) )
-- | Corresponds to a @FULL OUTER JOIN@ between two queries.
alignBy :: ()
=> (a -> b -> Expr Bool)
-> Query a -> Query b -> Query (TheseTable Expr a b)
alignBy condition = zipOpaleyeWith $ \left right -> Opaleye.stateQueryArr $ \_ t -> case t of
tag -> (tab, join', tag''')
where
(ma, left', tag') = Opaleye.runStateQueryArr (pure <$> left) () tag
(mb, right', tag'') = Opaleye.runStateQueryArr (pure <$> right) () tag'
MaybeTable hasHere a = ma
MaybeTable hasThere b = mb
(hasHere', lbindings) = Opaleye.run $ do
traversePrimExpr (Opaleye.extractAttr "hasHere" tag'') hasHere
(hasThere', rbindings) = Opaleye.run $ do
traversePrimExpr (Opaleye.extractAttr "hasThere" tag'') hasThere
tag''' = Opaleye.next tag''
join = Opaleye.Join Opaleye.FullJoin on left'' right''
where
on = toPrimExpr $ condition (extract a) (extract b)
left'' = (Opaleye.NonLateral, Opaleye.toPrimQuery (left' <> Opaleye.aRebind lbindings))
right'' = (Opaleye.NonLateral, Opaleye.toPrimQuery (right' <> Opaleye.aRebind rbindings))
ma' = MaybeTable hasHere' a
mb' = MaybeTable hasThere' b
tab = TheseTable {here = ma', there = mb'}
join' = Opaleye.aProduct join
keepHereTable :: TheseTable Expr a b -> Query (a, MaybeTable Expr b)
keepHereTable = loseThatTable
loseHereTable :: TheseTable Expr a b -> Query b
loseHereTable = keepThatTable
keepThereTable :: TheseTable Expr a b -> Query (MaybeTable Expr a, b)
keepThereTable = loseThisTable
loseThereTable :: TheseTable Expr a b -> Query a
loseThereTable = keepThisTable
keepThisTable :: TheseTable Expr a b -> Query a
keepThisTable t@(TheseTable (MaybeTable _ a) _) = do
where_ $ isThisTable t
pure (extract a)
loseThisTable :: TheseTable Expr a b -> Query (MaybeTable Expr a, b)
loseThisTable t@(TheseTable ma (MaybeTable _ b)) = do
where_ $ not_ $ isThisTable t
pure (ma, extract b)
keepThatTable :: TheseTable Expr a b -> Query b
keepThatTable t@(TheseTable _ (MaybeTable _ b)) = do
where_ $ isThatTable t
pure (extract b)
loseThatTable :: TheseTable Expr a b -> Query (a, MaybeTable Expr b)
loseThatTable t@(TheseTable (MaybeTable _ a) mb) = do
where_ $ not_ $ isThatTable t
pure (extract a, mb)
keepThoseTable :: TheseTable Expr a b -> Query (a, b)
keepThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do
where_ $ isThoseTable t
pure (extract a, extract b)
loseThoseTable :: TheseTable Expr a b -> Query (EitherTable Expr a b)
loseThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do
where_ $ not_ $ isThoseTable t
pure $ EitherTable tag a b
where
tag = boolExpr (litExpr IsLeft) (litExpr IsRight) (isThatTable t)
bitraverseTheseTable :: ()
=> (a -> Query c)
-> (b -> Query d)
-> TheseTable Expr a b
-> Query (TheseTable Expr c d)
bitraverseTheseTable f g t = do
mc <- optional (f . fst =<< keepHereTable t)
md <- optional (g . snd =<< keepThereTable t)
where_ $ isJustTable mc ==. hasHereTable t
where_ $ isJustTable md ==. hasThereTable t
pure $ TheseTable mc md