module Database.Relational.Query.Internal.Product (
NodeAttr (..), ProductTree (..),
Node, node, nodeAttr, nodeTree,
growRight,
growProduct, product, restrictProduct,
) where
import Prelude hiding (and, product)
import Database.Relational.Query.Context (Flat)
import Database.Relational.Query.Expr (exprAnd)
import qualified Database.Relational.Query.Expr as Expr
import Data.Monoid ((<>))
import Data.Foldable (Foldable (foldMap))
type Expr = Expr.Expr Flat
data NodeAttr = Just' | Maybe deriving Show
data ProductTree q = Leaf q
| Join !(Node q) !(Node q) !(Maybe (Expr Bool))
deriving Show
data Node q = Node !NodeAttr !(ProductTree q) deriving Show
nodeAttr :: Node q -> NodeAttr
nodeAttr (Node a _) = a where
nodeTree :: Node q -> ProductTree q
nodeTree (Node _ t) = t
instance Foldable ProductTree where
foldMap f = rec where
rec (Leaf q) = f q
rec (Join (Node _ lp) (Node _ rp) _ ) = rec lp <> rec rp
node :: NodeAttr
-> ProductTree q
-> Node q
node = Node
growRight :: Maybe (Node q)
-> (NodeAttr, ProductTree q)
-> Node q
growRight = d where
d Nothing (naR, q) = node naR q
d (Just l) (naR, q) = node Just' $ Join l (node naR q) Nothing
growProduct :: Maybe (Node q)
-> (NodeAttr, q)
-> Node q
growProduct = match where
match t (na, q) = growRight t (na, Leaf q)
product :: Node q
-> Node q
-> Maybe (Expr Bool)
-> ProductTree q
product = Join
restrictProduct' :: ProductTree q
-> Expr Bool
-> ProductTree q
restrictProduct' = d where
d (Join lp rp Nothing) rs' = Join lp rp (Just rs')
d (Join lp rp (Just rs)) rs' = Join lp rp (Just $ rs `exprAnd` rs')
d leaf'@(Leaf _) _ = leaf'
restrictProduct :: Node q
-> Expr Bool
-> Node q
restrictProduct (Node a t) e = node a (restrictProduct' t e)