module Opaleye.Internal.PrimQuery where

import           Prelude hiding (product)

import qualified Data.List.NonEmpty as NEL
import           Data.Semigroup (Semigroup, (<>))
import qualified Opaleye.Internal.HaskellDB.Sql as HSql
import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ
import           Opaleye.Internal.HaskellDB.PrimQuery (Symbol)

data LimitOp = LimitOp Int | OffsetOp Int | LimitOffsetOp Int Int
             deriving Int -> LimitOp -> ShowS
[LimitOp] -> ShowS
LimitOp -> String
(Int -> LimitOp -> ShowS)
-> (LimitOp -> String) -> ([LimitOp] -> ShowS) -> Show LimitOp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LimitOp] -> ShowS
$cshowList :: [LimitOp] -> ShowS
show :: LimitOp -> String
$cshow :: LimitOp -> String
showsPrec :: Int -> LimitOp -> ShowS
$cshowsPrec :: Int -> LimitOp -> ShowS
Show

data BinOp = Except
           | ExceptAll
           | Union
           | UnionAll
           | Intersect
           | IntersectAll
             deriving Int -> BinOp -> ShowS
[BinOp] -> ShowS
BinOp -> String
(Int -> BinOp -> ShowS)
-> (BinOp -> String) -> ([BinOp] -> ShowS) -> Show BinOp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BinOp] -> ShowS
$cshowList :: [BinOp] -> ShowS
show :: BinOp -> String
$cshow :: BinOp -> String
showsPrec :: Int -> BinOp -> ShowS
$cshowsPrec :: Int -> BinOp -> ShowS
Show

data JoinType = LeftJoin | RightJoin | FullJoin deriving Int -> JoinType -> ShowS
[JoinType] -> ShowS
JoinType -> String
(Int -> JoinType -> ShowS)
-> (JoinType -> String) -> ([JoinType] -> ShowS) -> Show JoinType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [JoinType] -> ShowS
$cshowList :: [JoinType] -> ShowS
show :: JoinType -> String
$cshow :: JoinType -> String
showsPrec :: Int -> JoinType -> ShowS
$cshowsPrec :: Int -> JoinType -> ShowS
Show

data SemijoinType = Semi | Anti deriving Int -> SemijoinType -> ShowS
[SemijoinType] -> ShowS
SemijoinType -> String
(Int -> SemijoinType -> ShowS)
-> (SemijoinType -> String)
-> ([SemijoinType] -> ShowS)
-> Show SemijoinType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SemijoinType] -> ShowS
$cshowList :: [SemijoinType] -> ShowS
show :: SemijoinType -> String
$cshow :: SemijoinType -> String
showsPrec :: Int -> SemijoinType -> ShowS
$cshowsPrec :: Int -> SemijoinType -> ShowS
Show

data TableIdentifier = TableIdentifier
  { TableIdentifier -> Maybe String
tiSchemaName :: Maybe String
  , TableIdentifier -> String
tiTableName  :: String
  } deriving Int -> TableIdentifier -> ShowS
[TableIdentifier] -> ShowS
TableIdentifier -> String
(Int -> TableIdentifier -> ShowS)
-> (TableIdentifier -> String)
-> ([TableIdentifier] -> ShowS)
-> Show TableIdentifier
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TableIdentifier] -> ShowS
$cshowList :: [TableIdentifier] -> ShowS
show :: TableIdentifier -> String
$cshow :: TableIdentifier -> String
showsPrec :: Int -> TableIdentifier -> ShowS
$cshowsPrec :: Int -> TableIdentifier -> ShowS
Show

tiToSqlTable :: TableIdentifier -> HSql.SqlTable
tiToSqlTable :: TableIdentifier -> SqlTable
tiToSqlTable TableIdentifier
ti = SqlTable :: Maybe String -> String -> SqlTable
HSql.SqlTable { sqlTableSchemaName :: Maybe String
HSql.sqlTableSchemaName = TableIdentifier -> Maybe String
tiSchemaName TableIdentifier
ti
                                , sqlTableName :: String
HSql.sqlTableName       = TableIdentifier -> String
tiTableName TableIdentifier
ti }

type Bindings a = [(Symbol, a)]

data Lateral = NonLateral | Lateral
  deriving Int -> Lateral -> ShowS
[Lateral] -> ShowS
Lateral -> String
(Int -> Lateral -> ShowS)
-> (Lateral -> String) -> ([Lateral] -> ShowS) -> Show Lateral
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Lateral] -> ShowS
$cshowList :: [Lateral] -> ShowS
show :: Lateral -> String
$cshow :: Lateral -> String
showsPrec :: Int -> Lateral -> ShowS
$cshowsPrec :: Int -> Lateral -> ShowS
Show

instance Semigroup Lateral where
  Lateral
NonLateral <> :: Lateral -> Lateral -> Lateral
<> Lateral
NonLateral = Lateral
NonLateral
  Lateral
_ <> Lateral
_ = Lateral
Lateral

instance Monoid Lateral where
  mappend :: Lateral -> Lateral -> Lateral
mappend = Lateral -> Lateral -> Lateral
forall a. Semigroup a => a -> a -> a
(<>)
  mempty :: Lateral
mempty = Lateral
NonLateral

-- We use a 'NEL.NonEmpty' for Product because otherwise we'd have to check
-- for emptiness explicity in the SQL generation phase.

-- The type parameter 'a' is used to control whether the 'Empty'
-- constructor can appear.  If 'a' = '()' then it can appear.  If 'a'
-- = 'Void' then it cannot.  When we create queries it is more
-- convenient to allow 'Empty', but it is hard to represent 'Empty' in
-- SQL so we remove it in 'Optimize' and set 'a = Void'.
data PrimQuery' a = Unit
                  | Empty     a
                  | BaseTable TableIdentifier (Bindings HPQ.PrimExpr)
                  | Product   (NEL.NonEmpty (Lateral, PrimQuery' a)) [HPQ.PrimExpr]
                  -- | The subqueries to take the product of and the
                  --   restrictions to apply
                  | Aggregate (Bindings (Maybe (HPQ.AggrOp,
                                                [HPQ.OrderExpr],
                                                HPQ.AggrDistinct),
                                          HPQ.Symbol))
                              (PrimQuery' a)
                  -- | Represents both @DISTINCT ON@ and @ORDER BY@
                  --   clauses. In order to represent valid SQL only,
                  --   @DISTINCT ON@ expressions are always
                  --   interpreted as the first @ORDER BY@s when
                  --   present, preceding any in the provided list.
                  --   See 'Opaleye.Internal.Sql.distinctOnOrderBy'.
                  | DistinctOnOrderBy (Maybe (NEL.NonEmpty HPQ.PrimExpr))
                                      [HPQ.OrderExpr]
                                      (PrimQuery' a)
                  | Limit     LimitOp (PrimQuery' a)
                  | Join      JoinType
                              HPQ.PrimExpr
                              (Bindings HPQ.PrimExpr)
                              (Bindings HPQ.PrimExpr)
                              (PrimQuery' a)
                              (PrimQuery' a)
                  | Semijoin  SemijoinType (PrimQuery' a) (PrimQuery' a)
                  | Exists    Symbol (PrimQuery' a)
                  | Values    [Symbol] (NEL.NonEmpty [HPQ.PrimExpr])
                  | Binary    BinOp
                              (PrimQuery' a, PrimQuery' a)
                  | Label     String (PrimQuery' a)
                  | RelExpr   HPQ.PrimExpr (Bindings HPQ.PrimExpr)
                  | Rebind    Bool
                              (Bindings HPQ.PrimExpr)
                              (PrimQuery' a)
                  | ForUpdate (PrimQuery' a)
                  -- We may support more locking clauses than just
                  -- ForUpdate in the future
                  --
                  -- https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE
                 deriving Int -> PrimQuery' a -> ShowS
[PrimQuery' a] -> ShowS
PrimQuery' a -> String
(Int -> PrimQuery' a -> ShowS)
-> (PrimQuery' a -> String)
-> ([PrimQuery' a] -> ShowS)
-> Show (PrimQuery' a)
forall a. Show a => Int -> PrimQuery' a -> ShowS
forall a. Show a => [PrimQuery' a] -> ShowS
forall a. Show a => PrimQuery' a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PrimQuery' a] -> ShowS
$cshowList :: forall a. Show a => [PrimQuery' a] -> ShowS
show :: PrimQuery' a -> String
$cshow :: forall a. Show a => PrimQuery' a -> String
showsPrec :: Int -> PrimQuery' a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> PrimQuery' a -> ShowS
Show

type PrimQuery = PrimQuery' ()
type PrimQueryFold = PrimQueryFold' ()

data PrimQueryFold' a p = PrimQueryFold
  { PrimQueryFold' a p -> p
unit              :: p
  , PrimQueryFold' a p -> a -> p
empty             :: a -> p
  , PrimQueryFold' a p -> TableIdentifier -> Bindings PrimExpr -> p
baseTable         :: TableIdentifier -> Bindings HPQ.PrimExpr -> p
  , PrimQueryFold' a p -> NonEmpty (Lateral, p) -> [PrimExpr] -> p
product           :: NEL.NonEmpty (Lateral, p) -> [HPQ.PrimExpr] -> p
  , PrimQueryFold' a p
-> Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
-> p
-> p
aggregate         :: Bindings (Maybe
                             (HPQ.AggrOp, [HPQ.OrderExpr], HPQ.AggrDistinct),
                                   HPQ.Symbol)
                      -> p
                      -> p
  , PrimQueryFold' a p
-> Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> p -> p
distinctOnOrderBy :: Maybe (NEL.NonEmpty HPQ.PrimExpr)
                      -> [HPQ.OrderExpr]
                      -> p
                      -> p
  , PrimQueryFold' a p -> LimitOp -> p -> p
limit             :: LimitOp -> p -> p
  , PrimQueryFold' a p
-> JoinType
-> PrimExpr
-> Bindings PrimExpr
-> Bindings PrimExpr
-> p
-> p
-> p
join              :: JoinType
                      -> HPQ.PrimExpr
                      -> Bindings HPQ.PrimExpr
                      -> Bindings HPQ.PrimExpr
                      -> p
                      -> p
                      -> p
  , PrimQueryFold' a p -> SemijoinType -> p -> p -> p
semijoin          :: SemijoinType -> p -> p -> p
  , PrimQueryFold' a p -> Symbol -> p -> p
exists            :: Symbol -> p -> p
  , PrimQueryFold' a p -> [Symbol] -> NonEmpty [PrimExpr] -> p
values            :: [Symbol] -> NEL.NonEmpty [HPQ.PrimExpr] -> p
  , PrimQueryFold' a p -> BinOp -> (p, p) -> p
binary            :: BinOp
                      -> (p, p)
                      -> p
  , PrimQueryFold' a p -> String -> p -> p
label             :: String -> p -> p
  , PrimQueryFold' a p -> PrimExpr -> Bindings PrimExpr -> p
relExpr           :: HPQ.PrimExpr -> Bindings HPQ.PrimExpr -> p
    -- ^ A relation-valued expression
  , PrimQueryFold' a p -> Bool -> Bindings PrimExpr -> p -> p
rebind            :: Bool -> Bindings HPQ.PrimExpr -> p -> p
  , PrimQueryFold' a p -> p -> p
forUpdate         :: p -> p
  }


primQueryFoldDefault :: PrimQueryFold' a (PrimQuery' a)
primQueryFoldDefault :: PrimQueryFold' a (PrimQuery' a)
primQueryFoldDefault = PrimQueryFold :: forall a p.
p
-> (a -> p)
-> (TableIdentifier -> Bindings PrimExpr -> p)
-> (NonEmpty (Lateral, p) -> [PrimExpr] -> p)
-> (Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
    -> p -> p)
-> (Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> p -> p)
-> (LimitOp -> p -> p)
-> (JoinType
    -> PrimExpr
    -> Bindings PrimExpr
    -> Bindings PrimExpr
    -> p
    -> p
    -> p)
-> (SemijoinType -> p -> p -> p)
-> (Symbol -> p -> p)
-> ([Symbol] -> NonEmpty [PrimExpr] -> p)
-> (BinOp -> (p, p) -> p)
-> (String -> p -> p)
-> (PrimExpr -> Bindings PrimExpr -> p)
-> (Bool -> Bindings PrimExpr -> p -> p)
-> (p -> p)
-> PrimQueryFold' a p
PrimQueryFold
  { unit :: PrimQuery' a
unit              = PrimQuery' a
forall a. PrimQuery' a
Unit
  , empty :: a -> PrimQuery' a
empty             = a -> PrimQuery' a
forall a. a -> PrimQuery' a
Empty
  , baseTable :: TableIdentifier -> Bindings PrimExpr -> PrimQuery' a
baseTable         = TableIdentifier -> Bindings PrimExpr -> PrimQuery' a
forall a. TableIdentifier -> Bindings PrimExpr -> PrimQuery' a
BaseTable
  , product :: NonEmpty (Lateral, PrimQuery' a) -> [PrimExpr] -> PrimQuery' a
product           = NonEmpty (Lateral, PrimQuery' a) -> [PrimExpr] -> PrimQuery' a
forall a.
NonEmpty (Lateral, PrimQuery' a) -> [PrimExpr] -> PrimQuery' a
Product
  , aggregate :: Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
-> PrimQuery' a -> PrimQuery' a
aggregate         = Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
-> PrimQuery' a -> PrimQuery' a
forall a.
Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
-> PrimQuery' a -> PrimQuery' a
Aggregate
  , distinctOnOrderBy :: Maybe (NonEmpty PrimExpr)
-> [OrderExpr] -> PrimQuery' a -> PrimQuery' a
distinctOnOrderBy = Maybe (NonEmpty PrimExpr)
-> [OrderExpr] -> PrimQuery' a -> PrimQuery' a
forall a.
Maybe (NonEmpty PrimExpr)
-> [OrderExpr] -> PrimQuery' a -> PrimQuery' a
DistinctOnOrderBy
  , limit :: LimitOp -> PrimQuery' a -> PrimQuery' a
limit             = LimitOp -> PrimQuery' a -> PrimQuery' a
forall a. LimitOp -> PrimQuery' a -> PrimQuery' a
Limit
  , join :: JoinType
-> PrimExpr
-> Bindings PrimExpr
-> Bindings PrimExpr
-> PrimQuery' a
-> PrimQuery' a
-> PrimQuery' a
join              = JoinType
-> PrimExpr
-> Bindings PrimExpr
-> Bindings PrimExpr
-> PrimQuery' a
-> PrimQuery' a
-> PrimQuery' a
forall a.
JoinType
-> PrimExpr
-> Bindings PrimExpr
-> Bindings PrimExpr
-> PrimQuery' a
-> PrimQuery' a
-> PrimQuery' a
Join
  , semijoin :: SemijoinType -> PrimQuery' a -> PrimQuery' a -> PrimQuery' a
semijoin          = SemijoinType -> PrimQuery' a -> PrimQuery' a -> PrimQuery' a
forall a.
SemijoinType -> PrimQuery' a -> PrimQuery' a -> PrimQuery' a
Semijoin
  , values :: [Symbol] -> NonEmpty [PrimExpr] -> PrimQuery' a
values            = [Symbol] -> NonEmpty [PrimExpr] -> PrimQuery' a
forall a. [Symbol] -> NonEmpty [PrimExpr] -> PrimQuery' a
Values
  , binary :: BinOp -> (PrimQuery' a, PrimQuery' a) -> PrimQuery' a
binary            = BinOp -> (PrimQuery' a, PrimQuery' a) -> PrimQuery' a
forall a. BinOp -> (PrimQuery' a, PrimQuery' a) -> PrimQuery' a
Binary
  , label :: String -> PrimQuery' a -> PrimQuery' a
label             = String -> PrimQuery' a -> PrimQuery' a
forall a. String -> PrimQuery' a -> PrimQuery' a
Label
  , relExpr :: PrimExpr -> Bindings PrimExpr -> PrimQuery' a
relExpr           = PrimExpr -> Bindings PrimExpr -> PrimQuery' a
forall a. PrimExpr -> Bindings PrimExpr -> PrimQuery' a
RelExpr
  , exists :: Symbol -> PrimQuery' a -> PrimQuery' a
exists            = Symbol -> PrimQuery' a -> PrimQuery' a
forall a. Symbol -> PrimQuery' a -> PrimQuery' a
Exists
  , rebind :: Bool -> Bindings PrimExpr -> PrimQuery' a -> PrimQuery' a
rebind            = Bool -> Bindings PrimExpr -> PrimQuery' a -> PrimQuery' a
forall a. Bool -> Bindings PrimExpr -> PrimQuery' a -> PrimQuery' a
Rebind
  , forUpdate :: PrimQuery' a -> PrimQuery' a
forUpdate         = PrimQuery' a -> PrimQuery' a
forall a. PrimQuery' a -> PrimQuery' a
ForUpdate
  }

foldPrimQuery :: PrimQueryFold' a p -> PrimQuery' a -> p
foldPrimQuery :: PrimQueryFold' a p -> PrimQuery' a -> p
foldPrimQuery PrimQueryFold' a p
f = ((PrimQuery' a -> p) -> PrimQuery' a -> p) -> PrimQuery' a -> p
forall t. (t -> t) -> t
fix (PrimQuery' a -> p) -> PrimQuery' a -> p
fold
  where fold :: (PrimQuery' a -> p) -> PrimQuery' a -> p
fold PrimQuery' a -> p
self PrimQuery' a
primQ = case PrimQuery' a
primQ of
          PrimQuery' a
Unit                        -> PrimQueryFold' a p -> p
forall a p. PrimQueryFold' a p -> p
unit              PrimQueryFold' a p
f
          Empty a
a                     -> PrimQueryFold' a p -> a -> p
forall a p. PrimQueryFold' a p -> a -> p
empty             PrimQueryFold' a p
f a
a
          BaseTable TableIdentifier
ti Bindings PrimExpr
syms           -> PrimQueryFold' a p -> TableIdentifier -> Bindings PrimExpr -> p
forall a p.
PrimQueryFold' a p -> TableIdentifier -> Bindings PrimExpr -> p
baseTable         PrimQueryFold' a p
f TableIdentifier
ti Bindings PrimExpr
syms
          Product NonEmpty (Lateral, PrimQuery' a)
qs [PrimExpr]
pes              -> PrimQueryFold' a p -> NonEmpty (Lateral, p) -> [PrimExpr] -> p
forall a p.
PrimQueryFold' a p -> NonEmpty (Lateral, p) -> [PrimExpr] -> p
product           PrimQueryFold' a p
f (((Lateral, PrimQuery' a) -> (Lateral, p))
-> NonEmpty (Lateral, PrimQuery' a) -> NonEmpty (Lateral, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((PrimQuery' a -> p) -> (Lateral, PrimQuery' a) -> (Lateral, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PrimQuery' a -> p
self) NonEmpty (Lateral, PrimQuery' a)
qs) [PrimExpr]
pes
          Aggregate Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
aggrs PrimQuery' a
q           -> PrimQueryFold' a p
-> Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
-> p
-> p
forall a p.
PrimQueryFold' a p
-> Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
-> p
-> p
aggregate         PrimQueryFold' a p
f Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), Symbol)
aggrs (PrimQuery' a -> p
self PrimQuery' a
q)
          DistinctOnOrderBy Maybe (NonEmpty PrimExpr)
dxs [OrderExpr]
oxs PrimQuery' a
q -> PrimQueryFold' a p
-> Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> p -> p
forall a p.
PrimQueryFold' a p
-> Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> p -> p
distinctOnOrderBy PrimQueryFold' a p
f Maybe (NonEmpty PrimExpr)
dxs [OrderExpr]
oxs (PrimQuery' a -> p
self PrimQuery' a
q)
          Limit LimitOp
op PrimQuery' a
q                  -> PrimQueryFold' a p -> LimitOp -> p -> p
forall a p. PrimQueryFold' a p -> LimitOp -> p -> p
limit             PrimQueryFold' a p
f LimitOp
op (PrimQuery' a -> p
self PrimQuery' a
q)
          Join JoinType
j PrimExpr
cond Bindings PrimExpr
pe1 Bindings PrimExpr
pe2 PrimQuery' a
q1 PrimQuery' a
q2   -> PrimQueryFold' a p
-> JoinType
-> PrimExpr
-> Bindings PrimExpr
-> Bindings PrimExpr
-> p
-> p
-> p
forall a p.
PrimQueryFold' a p
-> JoinType
-> PrimExpr
-> Bindings PrimExpr
-> Bindings PrimExpr
-> p
-> p
-> p
join              PrimQueryFold' a p
f JoinType
j PrimExpr
cond Bindings PrimExpr
pe1 Bindings PrimExpr
pe2 (PrimQuery' a -> p
self PrimQuery' a
q1) (PrimQuery' a -> p
self PrimQuery' a
q2)
          Semijoin SemijoinType
j PrimQuery' a
q1 PrimQuery' a
q2            -> PrimQueryFold' a p -> SemijoinType -> p -> p -> p
forall a p. PrimQueryFold' a p -> SemijoinType -> p -> p -> p
semijoin          PrimQueryFold' a p
f SemijoinType
j (PrimQuery' a -> p
self PrimQuery' a
q1) (PrimQuery' a -> p
self PrimQuery' a
q2)
          Values [Symbol]
ss NonEmpty [PrimExpr]
pes               -> PrimQueryFold' a p -> [Symbol] -> NonEmpty [PrimExpr] -> p
forall a p.
PrimQueryFold' a p -> [Symbol] -> NonEmpty [PrimExpr] -> p
values            PrimQueryFold' a p
f [Symbol]
ss NonEmpty [PrimExpr]
pes
          Binary BinOp
binop (PrimQuery' a
q1, PrimQuery' a
q2)       -> PrimQueryFold' a p -> BinOp -> (p, p) -> p
forall a p. PrimQueryFold' a p -> BinOp -> (p, p) -> p
binary            PrimQueryFold' a p
f BinOp
binop (PrimQuery' a -> p
self PrimQuery' a
q1, PrimQuery' a -> p
self PrimQuery' a
q2)
          Label String
l PrimQuery' a
pq                  -> PrimQueryFold' a p -> String -> p -> p
forall a p. PrimQueryFold' a p -> String -> p -> p
label             PrimQueryFold' a p
f String
l (PrimQuery' a -> p
self PrimQuery' a
pq)
          RelExpr PrimExpr
pe Bindings PrimExpr
syms             -> PrimQueryFold' a p -> PrimExpr -> Bindings PrimExpr -> p
forall a p.
PrimQueryFold' a p -> PrimExpr -> Bindings PrimExpr -> p
relExpr           PrimQueryFold' a p
f PrimExpr
pe Bindings PrimExpr
syms
          Exists Symbol
s PrimQuery' a
q                  -> PrimQueryFold' a p -> Symbol -> p -> p
forall a p. PrimQueryFold' a p -> Symbol -> p -> p
exists            PrimQueryFold' a p
f Symbol
s (PrimQuery' a -> p
self PrimQuery' a
q)
          Rebind Bool
star Bindings PrimExpr
pes PrimQuery' a
q           -> PrimQueryFold' a p -> Bool -> Bindings PrimExpr -> p -> p
forall a p.
PrimQueryFold' a p -> Bool -> Bindings PrimExpr -> p -> p
rebind            PrimQueryFold' a p
f Bool
star Bindings PrimExpr
pes (PrimQuery' a -> p
self PrimQuery' a
q)
          ForUpdate PrimQuery' a
q                 -> PrimQueryFold' a p -> p -> p
forall a p. PrimQueryFold' a p -> p -> p
forUpdate         PrimQueryFold' a p
f (PrimQuery' a -> p
self PrimQuery' a
q)
        fix :: (t -> t) -> t
fix t -> t
g = let x :: t
x = t -> t
g t
x in t
x

times :: PrimQuery -> PrimQuery -> PrimQuery
times :: PrimQuery -> PrimQuery -> PrimQuery
times PrimQuery
q PrimQuery
q' = NonEmpty (Lateral, PrimQuery) -> [PrimExpr] -> PrimQuery
forall a.
NonEmpty (Lateral, PrimQuery' a) -> [PrimExpr] -> PrimQuery' a
Product (PrimQuery -> (Lateral, PrimQuery)
forall (f :: * -> *) a. Applicative f => a -> f a
pure PrimQuery
q (Lateral, PrimQuery)
-> [(Lateral, PrimQuery)] -> NonEmpty (Lateral, PrimQuery)
forall a. a -> [a] -> NonEmpty a
NEL.:| [PrimQuery -> (Lateral, PrimQuery)
forall (f :: * -> *) a. Applicative f => a -> f a
pure PrimQuery
q']) []

restrict :: HPQ.PrimExpr -> PrimQuery -> PrimQuery
restrict :: PrimExpr -> PrimQuery -> PrimQuery
restrict PrimExpr
cond PrimQuery
primQ = NonEmpty (Lateral, PrimQuery) -> [PrimExpr] -> PrimQuery
forall a.
NonEmpty (Lateral, PrimQuery' a) -> [PrimExpr] -> PrimQuery' a
Product ((Lateral, PrimQuery) -> NonEmpty (Lateral, PrimQuery)
forall (m :: * -> *) a. Monad m => a -> m a
return (PrimQuery -> (Lateral, PrimQuery)
forall (f :: * -> *) a. Applicative f => a -> f a
pure PrimQuery
primQ)) [PrimExpr
cond]

isUnit :: PrimQuery' a -> Bool
isUnit :: PrimQuery' a -> Bool
isUnit PrimQuery' a
Unit = Bool
True
isUnit PrimQuery' a
_    = Bool
False