{-|
Module: Squeal.PostgreSQL.Query.From.Join
Description: Squeal joins
Copyright: (c) Eitan Chatav, 2019
Maintainer: eitan@morphism.tech
Stability: experimental

Squeal joins
-}

{-# LANGUAGE
    ConstraintKinds
  , DeriveGeneric
  , DerivingStrategies
  , FlexibleContexts
  , FlexibleInstances
  , GADTs
  , GeneralizedNewtypeDeriving
  , LambdaCase
  , MultiParamTypeClasses
  , OverloadedLabels
  , OverloadedStrings
  , QuantifiedConstraints
  , ScopedTypeVariables
  , StandaloneDeriving
  , TypeApplications
  , TypeFamilies
  , TypeInType
  , TypeOperators
  , RankNTypes
  , UndecidableInstances
  #-}

module Squeal.PostgreSQL.Query.From.Join
  ( -- * Join
    JoinItem (..)
  , cross, crossJoin, crossJoinLateral
  , inner, innerJoin, innerJoinLateral
  , leftOuter, leftOuterJoin, leftOuterJoinLateral
  , rightOuter, rightOuterJoin, rightOuterJoinLateral
  , fullOuter, fullOuterJoin, fullOuterJoinLateral
  ) where

import Generics.SOP hiding (from)

import qualified Generics.SOP as SOP

import Squeal.PostgreSQL.Type.Alias
import Squeal.PostgreSQL.Expression
import Squeal.PostgreSQL.Expression.Logic
import Squeal.PostgreSQL.Query
import Squeal.PostgreSQL.Query.From
import Squeal.PostgreSQL.Query.From.Set
import Squeal.PostgreSQL.Render
import Squeal.PostgreSQL.Type.List
import Squeal.PostgreSQL.Type.Schema

-- $setup
-- >>> import Squeal.PostgreSQL

{- |
A `JoinItem` is the right hand side of a `cross`,
`inner`, `leftOuter`, `rightOuter`, `fullOuter` join of
`FromClause`s.
-}
data JoinItem
  (lat :: FromType)
  (with :: FromType)
  (db :: SchemasType)
  (params :: [NullType])
  (left :: FromType)
  (right :: FromType) where
    Join
      :: FromClause lat with db params right
      -- ^ A standard `Squeal.PostgreSQL.Query.Join`.
      -- It is not allowed to reference columns provided
      -- by preceding `FromClause` items.
      -> JoinItem lat with db params left right
    JoinLateral
      :: Aliased (Query (Join lat left) with db params) query
      -- ^ Subqueries can be preceded by `JoinLateral`.
      -- This allows them to reference columns provided
      -- by preceding `FromClause` items.
      -> JoinItem lat with db params left '[query]
    JoinFunction
      :: SetFun db arg set
      -- ^ Set returning functions can be preceded by `JoinFunction`.
      -- This allows them to reference columns provided
      -- by preceding `FromClause` items.
      -> Expression 'Ungrouped lat with db params left arg
      -- ^ argument
      -> JoinItem lat with db params left '[set]
    JoinFunctionN
      :: SListI args
      => SetFunN db args set
      -- ^ Set returning multi-argument functions
      -- can be preceded by `JoinFunctionN`.
      -- This allows them to reference columns provided
      -- by preceding `FromClause` items.
      -> NP (Expression 'Ungrouped lat with db params left) args
      -- ^ arguments
      -> JoinItem lat with db params left '[set]
instance RenderSQL (JoinItem lat with db params left right) where
  renderSQL :: JoinItem lat with db params left right -> ByteString
renderSQL = \case
    Join FromClause lat with db params right
tab -> ByteString
"JOIN" ByteString -> ByteString -> ByteString
<+> FromClause lat with db params right -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params right
tab
    JoinLateral Aliased (Query (Join lat left) with db params) query
qry -> ByteString
"JOIN LATERAL" ByteString -> ByteString -> ByteString
<+>
      (forall (ty :: RowType).
 Query (Join lat left) with db params ty -> ByteString)
-> Aliased (Query (Join lat left) with db params) query
-> ByteString
forall k (expression :: k -> *) (aliased :: (Symbol, k)).
(forall (ty :: k). expression ty -> ByteString)
-> Aliased expression aliased -> ByteString
renderAliased (ByteString -> ByteString
parenthesized (ByteString -> ByteString)
-> (Query (Join lat left) with db params ty -> ByteString)
-> Query (Join lat left) with db params ty
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query (Join lat left) with db params ty -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL) Aliased (Query (Join lat left) with db params) query
qry
    JoinFunction SetFun db arg set
fun Expression 'Ungrouped lat with db params left arg
x -> ByteString
"JOIN" ByteString -> ByteString -> ByteString
<+>
      FromClause Any Any db Any '[set] -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL (Expression 'Ungrouped Any Any db Any '[] arg
-> FromClause Any Any db Any '[set]
SetFun db arg set
fun (ByteString -> Expression 'Ungrouped Any Any db Any '[] arg
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression (Expression 'Ungrouped lat with db params left arg -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Expression 'Ungrouped lat with db params left arg
x)))
    JoinFunctionN SetFunN db args set
fun NP (Expression 'Ungrouped lat with db params left) args
xs -> ByteString
"JOIN" ByteString -> ByteString -> ByteString
<+>
      FromClause Any Any db Any '[set] -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL (NP (Expression 'Ungrouped Any Any db Any '[]) args
-> FromClause Any Any db Any '[set]
SetFunN db args set
fun ((forall (a :: NullType).
 Expression 'Ungrouped lat with db params left a
 -> Expression 'Ungrouped Any Any db Any '[] a)
-> NP (Expression 'Ungrouped lat with db params left) args
-> NP (Expression 'Ungrouped Any Any db Any '[]) args
forall k l (h :: (k -> *) -> l -> *) (xs :: l) (f :: k -> *)
       (f' :: k -> *).
(SListIN (Prod h) xs, HAp h) =>
(forall (a :: k). f a -> f' a) -> h f xs -> h f' xs
SOP.hmap (ByteString -> Expression 'Ungrouped Any Any db Any '[] a
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression (ByteString -> Expression 'Ungrouped Any Any db Any '[] a)
-> (Expression 'Ungrouped lat with db params left a -> ByteString)
-> Expression 'Ungrouped lat with db params left a
-> Expression 'Ungrouped Any Any db Any '[] a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expression 'Ungrouped lat with db params left a -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL) NP (Expression 'Ungrouped lat with db params left) args
xs))

{- |
@left & cross (Join right)@. For every possible combination of rows from
@left@ and @right@ (i.e., a Cartesian product), the joined table will contain
a row consisting of all columns in @left@ followed by all columns in @right@.
If the tables have @n@ and @m@ rows respectively, the joined table will
have @n * m@ rows.
-}
cross
  :: JoinItem lat with db params left right -- ^ right
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left right)
cross :: JoinItem lat with db params left right
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
cross JoinItem lat with db params left right
item FromClause lat with db params left
tab = ByteString -> FromClause lat with db params (Join left right)
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (from :: FromType).
ByteString -> FromClause lat with db params from
UnsafeFromClause (ByteString -> FromClause lat with db params (Join left right))
-> ByteString -> FromClause lat with db params (Join left right)
forall a b. (a -> b) -> a -> b
$
  FromClause lat with db params left -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params left
tab ByteString -> ByteString -> ByteString
<+> ByteString
"CROSS" ByteString -> ByteString -> ByteString
<+> JoinItem lat with db params left right -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL JoinItem lat with db params left right
item

{- |
@left & crossJoin right@. For every possible combination of rows from
@left@ and @right@ (i.e., a Cartesian product), the joined table will contain
a row consisting of all columns in @left@ followed by all columns in @right@.
If the tables have @n@ and @m@ rows respectively, the joined table will
have @n * m@ rows.
-}
crossJoin
  :: FromClause lat with db params right -- ^ right
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left right)
crossJoin :: FromClause lat with db params right
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
crossJoin = JoinItem lat with db params left right
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
cross (JoinItem lat with db params left right
 -> FromClause lat with db params left
 -> FromClause lat with db params (Join left right))
-> (FromClause lat with db params right
    -> JoinItem lat with db params left right)
-> FromClause lat with db params right
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FromClause lat with db params right
-> JoinItem lat with db params left right
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (right :: FromType) (left :: FromType).
FromClause lat with db params right
-> JoinItem lat with db params left right
Join

{- |
Like `crossJoin` with a `subquery` but allowed to reference columns provided
by preceding `FromClause` items.
-}
crossJoinLateral
  :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left '[query])
crossJoinLateral :: Aliased (Query (Join lat left) with db params) query
-> FromClause lat with db params left
-> FromClause lat with db params (Join left '[query])
crossJoinLateral = JoinItem lat with db params left '[query]
-> FromClause lat with db params left
-> FromClause lat with db params (Join left '[query])
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
cross (JoinItem lat with db params left '[query]
 -> FromClause lat with db params left
 -> FromClause lat with db params (Join left '[query]))
-> (Aliased (Query (Join lat left) with db params) query
    -> JoinItem lat with db params left '[query])
-> Aliased (Query (Join lat left) with db params) query
-> FromClause lat with db params left
-> FromClause lat with db params (Join left '[query])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
forall (lat :: FromType) (left :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType])
       (query :: (Symbol, RowType)).
Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
JoinLateral

{- | @left & inner (Join right) on@. The joined table is filtered by
the @on@ condition.
-}
inner
  :: JoinItem lat with db params left right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left right)
inner :: JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
inner JoinItem lat with db params left right
item Condition 'Ungrouped lat with db params (Join left right)
on FromClause lat with db params left
tab = ByteString -> FromClause lat with db params (Join left right)
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (from :: FromType).
ByteString -> FromClause lat with db params from
UnsafeFromClause (ByteString -> FromClause lat with db params (Join left right))
-> ByteString -> FromClause lat with db params (Join left right)
forall a b. (a -> b) -> a -> b
$
  FromClause lat with db params left -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params left
tab ByteString -> ByteString -> ByteString
<+> ByteString
"INNER" ByteString -> ByteString -> ByteString
<+> JoinItem lat with db params left right -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL JoinItem lat with db params left right
item ByteString -> ByteString -> ByteString
<+> ByteString
"ON" ByteString -> ByteString -> ByteString
<+> Condition 'Ungrouped lat with db params (Join left right)
-> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Condition 'Ungrouped lat with db params (Join left right)
on

{- | @left & innerJoin right on@. The joined table is filtered by
the @on@ condition.
-}
innerJoin
  :: FromClause lat with db params right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left right)
innerJoin :: FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
innerJoin = JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
inner (JoinItem lat with db params left right
 -> Condition 'Ungrouped lat with db params (Join left right)
 -> FromClause lat with db params left
 -> FromClause lat with db params (Join left right))
-> (FromClause lat with db params right
    -> JoinItem lat with db params left right)
-> FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FromClause lat with db params right
-> JoinItem lat with db params left right
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (right :: FromType) (left :: FromType).
FromClause lat with db params right
-> JoinItem lat with db params left right
Join

{- |
Like `innerJoin` with a `subquery` but allowed to reference columns provided
by preceding `FromClause` items.
-}
innerJoinLateral
  :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery
  -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left '[query])
innerJoinLateral :: Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join left '[query])
innerJoinLateral = JoinItem lat with db params left '[query]
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join left '[query])
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left right)
inner (JoinItem lat with db params left '[query]
 -> Condition 'Ungrouped lat with db params (Join left '[query])
 -> FromClause lat with db params left
 -> FromClause lat with db params (Join left '[query]))
-> (Aliased (Query (Join lat left) with db params) query
    -> JoinItem lat with db params left '[query])
-> Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join left '[query])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
forall (lat :: FromType) (left :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType])
       (query :: (Symbol, RowType)).
Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
JoinLateral

{- | @left & leftOuter (Join right) on@. First, an inner join is performed.
Then, for each row in @left@ that does not satisfy the @on@ condition with
any row in @right@, a joined row is added with null values in columns of @right@.
Thus, the joined table always has at least one row for each row in @left@.
-}
leftOuter
  :: JoinItem lat with db params left right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left (NullifyFrom right))
leftOuter :: JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom right))
leftOuter JoinItem lat with db params left right
item Condition 'Ungrouped lat with db params (Join left right)
on FromClause lat with db params left
tab = ByteString
-> FromClause lat with db params (Join left (NullifyFrom right))
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (from :: FromType).
ByteString -> FromClause lat with db params from
UnsafeFromClause (ByteString
 -> FromClause lat with db params (Join left (NullifyFrom right)))
-> ByteString
-> FromClause lat with db params (Join left (NullifyFrom right))
forall a b. (a -> b) -> a -> b
$
  FromClause lat with db params left -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params left
tab ByteString -> ByteString -> ByteString
<+> ByteString
"LEFT OUTER" ByteString -> ByteString -> ByteString
<+> JoinItem lat with db params left right -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL JoinItem lat with db params left right
item ByteString -> ByteString -> ByteString
<+> ByteString
"ON" ByteString -> ByteString -> ByteString
<+> Condition 'Ungrouped lat with db params (Join left right)
-> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Condition 'Ungrouped lat with db params (Join left right)
on

{- | @left & leftOuterJoin right on@. First, an inner join is performed.
Then, for each row in @left@ that does not satisfy the @on@ condition with
any row in @right@, a joined row is added with null values in columns of @right@.
Thus, the joined table always has at least one row for each row in @left@.
-}
leftOuterJoin
  :: FromClause lat with db params right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left (NullifyFrom right))
leftOuterJoin :: FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom right))
leftOuterJoin = JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom right))
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom right))
leftOuter (JoinItem lat with db params left right
 -> Condition 'Ungrouped lat with db params (Join left right)
 -> FromClause lat with db params left
 -> FromClause lat with db params (Join left (NullifyFrom right)))
-> (FromClause lat with db params right
    -> JoinItem lat with db params left right)
-> FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom right))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FromClause lat with db params right
-> JoinItem lat with db params left right
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (right :: FromType) (left :: FromType).
FromClause lat with db params right
-> JoinItem lat with db params left right
Join

{- |
Like `leftOuterJoin` with a `subquery` but allowed to reference columns provided
by preceding `FromClause` items.
-}
leftOuterJoinLateral
  :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery
  -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join left (NullifyFrom '[query]))
leftOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom '[query]))
leftOuterJoinLateral = JoinItem lat with db params left '[query]
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom '[query]))
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom right))
leftOuter (JoinItem lat with db params left '[query]
 -> Condition 'Ungrouped lat with db params (Join left '[query])
 -> FromClause lat with db params left
 -> FromClause
      lat with db params (Join left (NullifyFrom '[query])))
-> (Aliased (Query (Join lat left) with db params) query
    -> JoinItem lat with db params left '[query])
-> Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join left (NullifyFrom '[query]))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
forall (lat :: FromType) (left :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType])
       (query :: (Symbol, RowType)).
Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
JoinLateral

{- | @left & rightOuter (Join right) on@. First, an inner join is performed.
Then, for each row in @right@ that does not satisfy the @on@ condition with
any row in @left@, a joined row is added with null values in columns of @left@.
This is the converse of a left join: the result table will always
have a row for each row in @right@.
-}
rightOuter
  :: JoinItem lat with db params left right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join (NullifyFrom left) right)
rightOuter :: JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) right)
rightOuter JoinItem lat with db params left right
item Condition 'Ungrouped lat with db params (Join left right)
on FromClause lat with db params left
tab = ByteString
-> FromClause lat with db params (Join (NullifyFrom left) right)
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (from :: FromType).
ByteString -> FromClause lat with db params from
UnsafeFromClause (ByteString
 -> FromClause lat with db params (Join (NullifyFrom left) right))
-> ByteString
-> FromClause lat with db params (Join (NullifyFrom left) right)
forall a b. (a -> b) -> a -> b
$
  FromClause lat with db params left -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params left
tab ByteString -> ByteString -> ByteString
<+> ByteString
"RIGHT OUTER" ByteString -> ByteString -> ByteString
<+> JoinItem lat with db params left right -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL JoinItem lat with db params left right
item ByteString -> ByteString -> ByteString
<+> ByteString
"ON" ByteString -> ByteString -> ByteString
<+> Condition 'Ungrouped lat with db params (Join left right)
-> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Condition 'Ungrouped lat with db params (Join left right)
on

{- | @left & rightOuterJoin right on@. First, an inner join is performed.
Then, for each row in @right@ that does not satisfy the @on@ condition with
any row in @left@, a joined row is added with null values in columns of @left@.
This is the converse of a left join: the result table will always
have a row for each row in @right@.
-}
rightOuterJoin
  :: FromClause lat with db params right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join (NullifyFrom left) right)
rightOuterJoin :: FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) right)
rightOuterJoin = JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) right)
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) right)
rightOuter (JoinItem lat with db params left right
 -> Condition 'Ungrouped lat with db params (Join left right)
 -> FromClause lat with db params left
 -> FromClause lat with db params (Join (NullifyFrom left) right))
-> (FromClause lat with db params right
    -> JoinItem lat with db params left right)
-> FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) right)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FromClause lat with db params right
-> JoinItem lat with db params left right
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (right :: FromType) (left :: FromType).
FromClause lat with db params right
-> JoinItem lat with db params left right
Join

{- |
Like `rightOuterJoin` with a `subquery` but allowed to reference columns provided
by preceding `FromClause` items.
-}
rightOuterJoinLateral
  :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery
  -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (Join (NullifyFrom left) '[query])
rightOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) '[query])
rightOuterJoinLateral = JoinItem lat with db params left '[query]
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) '[query])
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) right)
rightOuter (JoinItem lat with db params left '[query]
 -> Condition 'Ungrouped lat with db params (Join left '[query])
 -> FromClause lat with db params left
 -> FromClause
      lat with db params (Join (NullifyFrom left) '[query]))
-> (Aliased (Query (Join lat left) with db params) query
    -> JoinItem lat with db params left '[query])
-> Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (Join (NullifyFrom left) '[query])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
forall (lat :: FromType) (left :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType])
       (query :: (Symbol, RowType)).
Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
JoinLateral

{- | @left & fullOuter (Join right) on@. First, an inner join is performed.
Then, for each row in @left@ that does not satisfy the @on@ condition with
any row in @right@, a joined row is added with null values in columns of @right@.
Also, for each row of @right@ that does not satisfy the join condition
with any row in @left@, a joined row with null values in the columns of @left@
is added.
-}
fullOuter
  :: JoinItem lat with db params left right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (NullifyFrom (Join left right))
fullOuter :: JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left right))
fullOuter JoinItem lat with db params left right
item Condition 'Ungrouped lat with db params (Join left right)
on FromClause lat with db params left
tab = ByteString
-> FromClause lat with db params (NullifyFrom (Join left right))
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (from :: FromType).
ByteString -> FromClause lat with db params from
UnsafeFromClause (ByteString
 -> FromClause lat with db params (NullifyFrom (Join left right)))
-> ByteString
-> FromClause lat with db params (NullifyFrom (Join left right))
forall a b. (a -> b) -> a -> b
$
  FromClause lat with db params left -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params left
tab ByteString -> ByteString -> ByteString
<+> ByteString
"FULL OUTER" ByteString -> ByteString -> ByteString
<+> JoinItem lat with db params left right -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL JoinItem lat with db params left right
item ByteString -> ByteString -> ByteString
<+> ByteString
"ON" ByteString -> ByteString -> ByteString
<+> Condition 'Ungrouped lat with db params (Join left right)
-> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Condition 'Ungrouped lat with db params (Join left right)
on

{- | @left & fullOuterJoin right on@. First, an inner join is performed.
Then, for each row in @left@ that does not satisfy the @on@ condition with
any row in @right@, a joined row is added with null values in columns of @right@.
Also, for each row of @right@ that does not satisfy the join condition
with any row in @left@, a joined row with null values in the columns of @left@
is added.
-}
fullOuterJoin
  :: FromClause lat with db params right -- ^ right
  -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (NullifyFrom (Join left right))
fullOuterJoin :: FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left right))
fullOuterJoin = JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left right))
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left right))
fullOuter (JoinItem lat with db params left right
 -> Condition 'Ungrouped lat with db params (Join left right)
 -> FromClause lat with db params left
 -> FromClause lat with db params (NullifyFrom (Join left right)))
-> (FromClause lat with db params right
    -> JoinItem lat with db params left right)
-> FromClause lat with db params right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left right))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FromClause lat with db params right
-> JoinItem lat with db params left right
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (right :: FromType) (left :: FromType).
FromClause lat with db params right
-> JoinItem lat with db params left right
Join

{- |
Like `fullOuterJoin` with a `subquery` but allowed to reference columns provided
by preceding `FromClause` items.
-}
fullOuterJoinLateral
  :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery
  -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition
  -> FromClause lat with db params left -- ^ left
  -> FromClause lat with db params (NullifyFrom (Join left '[query]))
fullOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left '[query]))
fullOuterJoinLateral = JoinItem lat with db params left '[query]
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left '[query]))
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (left :: FromType) (right :: FromType).
JoinItem lat with db params left right
-> Condition 'Ungrouped lat with db params (Join left right)
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left right))
fullOuter (JoinItem lat with db params left '[query]
 -> Condition 'Ungrouped lat with db params (Join left '[query])
 -> FromClause lat with db params left
 -> FromClause
      lat with db params (NullifyFrom (Join left '[query])))
-> (Aliased (Query (Join lat left) with db params) query
    -> JoinItem lat with db params left '[query])
-> Aliased (Query (Join lat left) with db params) query
-> Condition 'Ungrouped lat with db params (Join left '[query])
-> FromClause lat with db params left
-> FromClause lat with db params (NullifyFrom (Join left '[query]))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
forall (lat :: FromType) (left :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType])
       (query :: (Symbol, RowType)).
Aliased (Query (Join lat left) with db params) query
-> JoinItem lat with db params left '[query]
JoinLateral