{-# language FlexibleContexts #-}

module Rel8.Query.Set
  ( union, unionAll
  , intersect, intersectAll
  , except, exceptAll
  )
where

-- base
import Prelude ()

-- opaleye
import qualified Opaleye.Binary as Opaleye

-- rel8
import Rel8.Expr ( Expr )
import {-# SOURCE #-} Rel8.Query ( Query )
import Rel8.Query.Opaleye ( zipOpaleyeWith )
import Rel8.Table ( Table  )
import Rel8.Table.Eq ( EqTable )
import Rel8.Table.Opaleye ( binaryspec )


-- | Combine the results of two queries of the same type, collapsing
-- duplicates.  @union a b@ is the same as the SQL statement @x UNION b@.
union :: EqTable a => Query a -> Query a -> Query a
union :: Query a -> Query a -> Query a
union = (Select a -> Select a -> Select a) -> Query a -> Query a -> Query a
forall a b c.
(Select a -> Select b -> Select c) -> Query a -> Query b -> Query c
zipOpaleyeWith (Binaryspec a a -> Select a -> Select a -> Select a
forall fields fields'.
Binaryspec fields fields'
-> Select fields -> Select fields -> Select fields'
Opaleye.unionExplicit Binaryspec a a
forall a. Table Expr a => Binaryspec a a
binaryspec)


-- | Combine the results of two queries of the same type, retaining duplicates.
-- @unionAll a b@ is the same as the SQL statement @x UNION ALL b@.
unionAll :: Table Expr a => Query a -> Query a -> Query a
unionAll :: Query a -> Query a -> Query a
unionAll = (Select a -> Select a -> Select a) -> Query a -> Query a -> Query a
forall a b c.
(Select a -> Select b -> Select c) -> Query a -> Query b -> Query c
zipOpaleyeWith (Binaryspec a a -> Select a -> Select a -> Select a
forall fields fields'.
Binaryspec fields fields'
-> Select fields -> Select fields -> Select fields'
Opaleye.unionAllExplicit Binaryspec a a
forall a. Table Expr a => Binaryspec a a
binaryspec)


-- | Find the intersection of two queries, collapsing duplicates.  @intersect a
-- b@ is the same as the SQL statement @x INTERSECT b@.
intersect :: EqTable a => Query a -> Query a -> Query a
intersect :: Query a -> Query a -> Query a
intersect = (Select a -> Select a -> Select a) -> Query a -> Query a -> Query a
forall a b c.
(Select a -> Select b -> Select c) -> Query a -> Query b -> Query c
zipOpaleyeWith (Binaryspec a a -> Select a -> Select a -> Select a
forall fields fields'.
Binaryspec fields fields'
-> Select fields -> Select fields -> Select fields'
Opaleye.intersectExplicit Binaryspec a a
forall a. Table Expr a => Binaryspec a a
binaryspec)


-- | Find the intersection of two queries, retaining duplicates.  @intersectAll
-- a b@ is the same as the SQL statement @x INTERSECT ALL b@.
intersectAll :: EqTable a => Query a -> Query a -> Query a
intersectAll :: Query a -> Query a -> Query a
intersectAll = (Select a -> Select a -> Select a) -> Query a -> Query a -> Query a
forall a b c.
(Select a -> Select b -> Select c) -> Query a -> Query b -> Query c
zipOpaleyeWith (Binaryspec a a -> Select a -> Select a -> Select a
forall fields fields'.
Binaryspec fields fields'
-> Select fields -> Select fields -> Select fields'
Opaleye.intersectAllExplicit Binaryspec a a
forall a. Table Expr a => Binaryspec a a
binaryspec)


-- | Find the difference of two queries, collapsing duplicates @except a b@ is
-- the same as the SQL statement @x INTERSECT b@.
except :: EqTable a => Query a -> Query a -> Query a
except :: Query a -> Query a -> Query a
except = (Select a -> Select a -> Select a) -> Query a -> Query a -> Query a
forall a b c.
(Select a -> Select b -> Select c) -> Query a -> Query b -> Query c
zipOpaleyeWith (Binaryspec a a -> Select a -> Select a -> Select a
forall fields fields'.
Binaryspec fields fields'
-> Select fields -> Select fields -> Select fields'
Opaleye.exceptExplicit Binaryspec a a
forall a. Table Expr a => Binaryspec a a
binaryspec)


-- | Find the difference of two queries, retaining duplicates.  @exceptAll a b@
-- is the same as the SQL statement @x EXCEPT ALL b@.
exceptAll :: EqTable a => Query a -> Query a -> Query a
exceptAll :: Query a -> Query a -> Query a
exceptAll = (Select a -> Select a -> Select a) -> Query a -> Query a -> Query a
forall a b c.
(Select a -> Select b -> Select c) -> Query a -> Query b -> Query c
zipOpaleyeWith (Binaryspec a a -> Select a -> Select a -> Select a
forall fields fields'.
Binaryspec fields fields'
-> Select fields -> Select fields -> Select fields'
Opaleye.exceptAllExplicit Binaryspec a a
forall a. Table Expr a => Binaryspec a a
binaryspec)