{-|
Module: Squeal.PostgreSQL.Query.Table
Description: intermediate table expressions
Copyright: (c) Eitan Chatav, 2019
Maintainer: eitan@morphism.tech
Stability: experimental

intermediate table expressions
-}

{-# 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.Table
  ( -- * Table Expression
    TableExpression (..)
  , from
  , where_
  , groupBy
  , having
  , limit
  , offset
  , lockRows
    -- * Grouping
  , By (..)
  , GroupByClause (..)
  , HavingClause (..)
    -- * Row Locks
  , LockingClause (..)
  , LockStrength (..)
  , Waiting (..)
  ) where

import Control.DeepSeq
import Data.ByteString (ByteString)
import Data.String
import Data.Word
import Generics.SOP hiding (from)
import GHC.TypeLits

import qualified GHC.Generics as GHC

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

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

{-----------------------------------------
Table Expressions
-----------------------------------------}

-- | A `TableExpression` computes a table. The table expression contains
-- a `fromClause` that is optionally followed by a `whereClause`,
-- `groupByClause`, `havingClause`, `orderByClause`, `limitClause`
-- `offsetClause` and `lockingClauses`. Trivial table expressions simply refer
-- to a table on disk, a so-called base table, but more complex expressions
-- can be used to modify or combine base tables in various ways.
data TableExpression
  (grp :: Grouping)
  (lat :: FromType)
  (with :: FromType)
  (db :: SchemasType)
  (params :: [NullType])
  (from :: FromType)
    = TableExpression
    { TableExpression grp lat with db params from
-> FromClause lat with db params from
fromClause :: FromClause lat with db params from
    -- ^ A table reference that can be a table name, or a derived table such
    -- as a subquery, a @JOIN@ construct, or complex combinations of these.
    , TableExpression grp lat with db params from
-> [Condition 'Ungrouped lat with db params from]
whereClause :: [Condition 'Ungrouped lat with db params from]
    -- ^ optional search coditions, combined with `.&&`. After the processing
    -- of the `fromClause` is done, each row of the derived virtual table
    -- is checked against the search condition. If the result of the
    -- condition is true, the row is kept in the output table,
    -- otherwise it is discarded. The search condition typically references
    -- at least one column of the table generated in the `fromClause`;
    -- this is not required, but otherwise the WHERE clause will
    -- be fairly useless.
    , TableExpression grp lat with db params from
-> GroupByClause grp from
groupByClause :: GroupByClause grp from
    -- ^ The `groupByClause` is used to group together those rows in a table
    -- that have the same values in all the columns listed. The order in which
    -- the columns are listed does not matter. The effect is to combine each
    -- set of rows having common values into one group row that represents all
    -- rows in the group. This is done to eliminate redundancy in the output
    -- and/or compute aggregates that apply to these groups.
    , TableExpression grp lat with db params from
-> HavingClause grp lat with db params from
havingClause :: HavingClause grp lat with db params from
    -- ^ If a table has been grouped using `groupBy`, but only certain groups
    -- are of interest, the `havingClause` can be used, much like a
    -- `whereClause`, to eliminate groups from the result. Expressions in the
    -- `havingClause` can refer both to grouped expressions and to ungrouped
    -- expressions (which necessarily involve an aggregate function).
    , TableExpression grp lat with db params from
-> [SortExpression grp lat with db params from]
orderByClause :: [SortExpression grp lat with db params from]
    -- ^ The `orderByClause` is for optional sorting. When more than one
    -- `SortExpression` is specified, the later (right) values are used to sort
    -- rows that are equal according to the earlier (left) values.
    , TableExpression grp lat with db params from -> [Word64]
limitClause :: [Word64]
    -- ^ The `limitClause` is combined with `min` to give a limit count
    -- if nonempty. If a limit count is given, no more than that many rows
    -- will be returned (but possibly fewer, if the query itself yields
    -- fewer rows).
    , TableExpression grp lat with db params from -> [Word64]
offsetClause :: [Word64]
    -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count
    -- if nonempty. The offset count says to skip that many rows before
    -- beginning to return rows. The rows are skipped before the limit count
    -- is applied.
    , TableExpression grp lat with db params from -> [LockingClause from]
lockingClauses :: [LockingClause from]
    -- ^ `lockingClauses` can be added to a table expression with `lockRows`.
    } deriving ((forall x.
 TableExpression grp lat with db params from
 -> Rep (TableExpression grp lat with db params from) x)
-> (forall x.
    Rep (TableExpression grp lat with db params from) x
    -> TableExpression grp lat with db params from)
-> Generic (TableExpression grp lat with db params from)
forall x.
Rep (TableExpression grp lat with db params from) x
-> TableExpression grp lat with db params from
forall x.
TableExpression grp lat with db params from
-> Rep (TableExpression grp lat with db params from) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType) x.
Rep (TableExpression grp lat with db params from) x
-> TableExpression grp lat with db params from
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType) x.
TableExpression grp lat with db params from
-> Rep (TableExpression grp lat with db params from) x
$cto :: forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType) x.
Rep (TableExpression grp lat with db params from) x
-> TableExpression grp lat with db params from
$cfrom :: forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType) x.
TableExpression grp lat with db params from
-> Rep (TableExpression grp lat with db params from) x
GHC.Generic)

-- | Render a `TableExpression`
instance RenderSQL (TableExpression grp lat with db params from) where
  renderSQL :: TableExpression grp lat with db params from -> ByteString
renderSQL
    (TableExpression FromClause lat with db params from
frm' [Condition 'Ungrouped lat with db params from]
whs' GroupByClause grp from
grps' HavingClause grp lat with db params from
hvs' [SortExpression grp lat with db params from]
srts' [Word64]
lims' [Word64]
offs' [LockingClause from]
lks') = [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
      [ ByteString
"FROM ", FromClause lat with db params from -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FromClause lat with db params from
frm'
      , [Condition 'Ungrouped lat with db params from] -> ByteString
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (null :: PGType -> NullType).
[Expression grp lat with db params from (null 'PGbool)]
-> ByteString
renderWheres [Condition 'Ungrouped lat with db params from]
whs'
      , GroupByClause grp from -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL GroupByClause grp from
grps'
      , HavingClause grp lat with db params from -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL HavingClause grp lat with db params from
hvs'
      , [SortExpression grp lat with db params from] -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL [SortExpression grp lat with db params from]
srts'
      , [Word64] -> ByteString
renderLimits [Word64]
lims'
      , [Word64] -> ByteString
renderOffsets [Word64]
offs'
      , [LockingClause from] -> ByteString
renderLocks [LockingClause from]
lks' ]
      where
        renderWheres :: [Expression grp lat with db params from (null 'PGbool)]
-> ByteString
renderWheres = \case
          [] -> ByteString
""
          Expression grp lat with db params from (null 'PGbool)
wh:[Expression grp lat with db params from (null 'PGbool)]
whs -> ByteString
" WHERE" ByteString -> ByteString -> ByteString
<+> Expression grp lat with db params from (null 'PGbool) -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL ((Expression grp lat with db params from (null 'PGbool)
 -> Expression grp lat with db params from (null 'PGbool)
 -> Expression grp lat with db params from (null 'PGbool))
-> Expression grp lat with db params from (null 'PGbool)
-> [Expression grp lat with db params from (null 'PGbool)]
-> Expression grp lat with db params from (null 'PGbool)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Expression grp lat with db params from (null 'PGbool)
-> Expression grp lat with db params from (null 'PGbool)
-> Expression grp lat with db params from (null 'PGbool)
forall (null :: PGType -> NullType).
Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
(.&&) Expression grp lat with db params from (null 'PGbool)
wh [Expression grp lat with db params from (null 'PGbool)]
whs)
        renderLimits :: [Word64] -> ByteString
renderLimits = \case
          [] -> ByteString
""
          [Word64]
lims -> ByteString
" LIMIT" ByteString -> ByteString -> ByteString
<+> String -> ByteString
forall a. IsString a => String -> a
fromString (Word64 -> String
forall a. Show a => a -> String
show ([Word64] -> Word64
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Word64]
lims))
        renderOffsets :: [Word64] -> ByteString
renderOffsets = \case
          [] -> ByteString
""
          [Word64]
offs -> ByteString
" OFFSET" ByteString -> ByteString -> ByteString
<+> String -> ByteString
forall a. IsString a => String -> a
fromString (Word64 -> String
forall a. Show a => a -> String
show ([Word64] -> Word64
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Word64]
offs))
        renderLocks :: [LockingClause from] -> ByteString
renderLocks = (LockingClause from -> ByteString -> ByteString)
-> ByteString -> [LockingClause from] -> ByteString
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\LockingClause from
l ByteString
b -> ByteString
b ByteString -> ByteString -> ByteString
<+> LockingClause from -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL LockingClause from
l) ByteString
""

-- | A `from` generates a `TableExpression` from a table reference that can be
-- a table name, or a derived table such as a subquery, a JOIN construct,
-- or complex combinations of these. A `from` may be transformed by `where_`,
-- `groupBy`, `having`, `orderBy`, `limit` and `offset`,
-- using the `Data.Function.&` operator
-- to match the left-to-right sequencing of their placement in SQL.
from
  :: FromClause lat with db params from -- ^ table reference
  -> TableExpression 'Ungrouped lat with db params from
from :: FromClause lat with db params from
-> TableExpression 'Ungrouped lat with db params from
from FromClause lat with db params from
tab = FromClause lat with db params from
-> [Condition 'Ungrouped lat with db params from]
-> GroupByClause 'Ungrouped from
-> HavingClause 'Ungrouped lat with db params from
-> [SortExpression 'Ungrouped lat with db params from]
-> [Word64]
-> [Word64]
-> [LockingClause from]
-> TableExpression 'Ungrouped lat with db params from
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
FromClause lat with db params from
-> [Condition 'Ungrouped lat with db params from]
-> GroupByClause grp from
-> HavingClause grp lat with db params from
-> [SortExpression grp lat with db params from]
-> [Word64]
-> [Word64]
-> [LockingClause from]
-> TableExpression grp lat with db params from
TableExpression FromClause lat with db params from
tab [] GroupByClause 'Ungrouped from
forall k (from :: k). GroupByClause 'Ungrouped from
noGroups HavingClause 'Ungrouped lat with db params from
forall (lat :: FromType) (with :: FromType) (db :: SchemasType)
       (params :: [NullType]) (from :: FromType).
HavingClause 'Ungrouped lat with db params from
NoHaving [] [] [] []

-- | A `where_` is an endomorphism of `TableExpression`s which adds a
-- search condition to the `whereClause`.
where_
  :: Condition 'Ungrouped lat with db params from -- ^ filtering condition
  -> TableExpression grp lat with db params from
  -> TableExpression grp lat with db params from
where_ :: Condition 'Ungrouped lat with db params from
-> TableExpression grp lat with db params from
-> TableExpression grp lat with db params from
where_ Condition 'Ungrouped lat with db params from
wh TableExpression grp lat with db params from
rels = TableExpression grp lat with db params from
rels {whereClause :: [Condition 'Ungrouped lat with db params from]
whereClause = Condition 'Ungrouped lat with db params from
wh Condition 'Ungrouped lat with db params from
-> [Condition 'Ungrouped lat with db params from]
-> [Condition 'Ungrouped lat with db params from]
forall a. a -> [a] -> [a]
: TableExpression grp lat with db params from
-> [Condition 'Ungrouped lat with db params from]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from
-> [Condition 'Ungrouped lat with db params from]
whereClause TableExpression grp lat with db params from
rels}

-- | A `groupBy` is a transformation of `TableExpression`s which switches
-- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform
-- a "grand total" aggregation query.
groupBy
  :: SListI bys
  => NP (By from) bys -- ^ grouped columns
  -> TableExpression 'Ungrouped lat with db params from
  -> TableExpression ('Grouped bys) lat with db params from
groupBy :: NP (By from) bys
-> TableExpression 'Ungrouped lat with db params from
-> TableExpression ('Grouped bys) lat with db params from
groupBy NP (By from) bys
bys TableExpression 'Ungrouped lat with db params from
rels = TableExpression :: forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
FromClause lat with db params from
-> [Condition 'Ungrouped lat with db params from]
-> GroupByClause grp from
-> HavingClause grp lat with db params from
-> [SortExpression grp lat with db params from]
-> [Word64]
-> [Word64]
-> [LockingClause from]
-> TableExpression grp lat with db params from
TableExpression
  { fromClause :: FromClause lat with db params from
fromClause = TableExpression 'Ungrouped lat with db params from
-> FromClause lat with db params from
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from
-> FromClause lat with db params from
fromClause TableExpression 'Ungrouped lat with db params from
rels
  , whereClause :: [Condition 'Ungrouped lat with db params from]
whereClause = TableExpression 'Ungrouped lat with db params from
-> [Condition 'Ungrouped lat with db params from]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from
-> [Condition 'Ungrouped lat with db params from]
whereClause TableExpression 'Ungrouped lat with db params from
rels
  , groupByClause :: GroupByClause ('Grouped bys) from
groupByClause = NP (By from) bys -> GroupByClause ('Grouped bys) from
forall (bys :: [(Symbol, Symbol)]) (from :: FromType).
SListI bys =>
NP (By from) bys -> GroupByClause ('Grouped bys) from
group NP (By from) bys
bys
  , havingClause :: HavingClause ('Grouped bys) lat with db params from
havingClause = [Condition ('Grouped bys) lat with db params from]
-> HavingClause ('Grouped bys) lat with db params from
forall (bys :: [(Symbol, Symbol)]) (lat :: FromType)
       (with :: FromType) (db :: SchemasType) (params :: [NullType])
       (from :: FromType).
[Condition ('Grouped bys) lat with db params from]
-> HavingClause ('Grouped bys) lat with db params from
Having []
  , orderByClause :: [SortExpression ('Grouped bys) lat with db params from]
orderByClause = []
  , limitClause :: [Word64]
limitClause = TableExpression 'Ungrouped lat with db params from -> [Word64]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from -> [Word64]
limitClause TableExpression 'Ungrouped lat with db params from
rels
  , offsetClause :: [Word64]
offsetClause = TableExpression 'Ungrouped lat with db params from -> [Word64]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from -> [Word64]
offsetClause TableExpression 'Ungrouped lat with db params from
rels
  , lockingClauses :: [LockingClause from]
lockingClauses = TableExpression 'Ungrouped lat with db params from
-> [LockingClause from]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from -> [LockingClause from]
lockingClauses TableExpression 'Ungrouped lat with db params from
rels
  }

-- | A `having` is an endomorphism of `TableExpression`s which adds a
-- search condition to the `havingClause`.
having
  :: Condition ('Grouped bys) lat with db params from -- ^ having condition
  -> TableExpression ('Grouped bys) lat with db params from
  -> TableExpression ('Grouped bys) lat with db params from
having :: Condition ('Grouped bys) lat with db params from
-> TableExpression ('Grouped bys) lat with db params from
-> TableExpression ('Grouped bys) lat with db params from
having Condition ('Grouped bys) lat with db params from
hv TableExpression ('Grouped bys) lat with db params from
rels = TableExpression ('Grouped bys) lat with db params from
rels
  { havingClause :: HavingClause ('Grouped bys) lat with db params from
havingClause = case TableExpression ('Grouped bys) lat with db params from
-> HavingClause ('Grouped bys) lat with db params from
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from
-> HavingClause grp lat with db params from
havingClause TableExpression ('Grouped bys) lat with db params from
rels of Having [Condition ('Grouped bys) lat with db params from]
hvs -> [Condition ('Grouped bys) lat with db params from]
-> HavingClause ('Grouped bys) lat with db params from
forall (bys :: [(Symbol, Symbol)]) (lat :: FromType)
       (with :: FromType) (db :: SchemasType) (params :: [NullType])
       (from :: FromType).
[Condition ('Grouped bys) lat with db params from]
-> HavingClause ('Grouped bys) lat with db params from
Having (Condition ('Grouped bys) lat with db params from
hvCondition ('Grouped bys) lat with db params from
-> [Condition ('Grouped bys) lat with db params from]
-> [Condition ('Grouped bys) lat with db params from]
forall a. a -> [a] -> [a]
:[Condition ('Grouped bys) lat with db params from]
[Condition ('Grouped bys) lat with db params from]
hvs) }

instance OrderBy (TableExpression grp) grp where
  orderBy :: [SortExpression grp lat with db params from]
-> TableExpression grp lat with db params from
-> TableExpression grp lat with db params from
orderBy [SortExpression grp lat with db params from]
srts TableExpression grp lat with db params from
rels = TableExpression grp lat with db params from
rels {orderByClause :: [SortExpression grp lat with db params from]
orderByClause = TableExpression grp lat with db params from
-> [SortExpression grp lat with db params from]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from
-> [SortExpression grp lat with db params from]
orderByClause TableExpression grp lat with db params from
rels [SortExpression grp lat with db params from]
-> [SortExpression grp lat with db params from]
-> [SortExpression grp lat with db params from]
forall a. [a] -> [a] -> [a]
++ [SortExpression grp lat with db params from]
srts}

-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
-- `limitClause`.
limit
  :: Word64 -- ^ limit parameter
  -> TableExpression grp lat with db params from
  -> TableExpression grp lat with db params from
limit :: Word64
-> TableExpression grp lat with db params from
-> TableExpression grp lat with db params from
limit Word64
lim TableExpression grp lat with db params from
rels = TableExpression grp lat with db params from
rels {limitClause :: [Word64]
limitClause = Word64
lim Word64 -> [Word64] -> [Word64]
forall a. a -> [a] -> [a]
: TableExpression grp lat with db params from -> [Word64]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from -> [Word64]
limitClause TableExpression grp lat with db params from
rels}

-- | An `offset` is an endomorphism of `TableExpression`s which adds to the
-- `offsetClause`.
offset
  :: Word64 -- ^ offset parameter
  -> TableExpression grp lat with db params from
  -> TableExpression grp lat with db params from
offset :: Word64
-> TableExpression grp lat with db params from
-> TableExpression grp lat with db params from
offset Word64
off TableExpression grp lat with db params from
rels = TableExpression grp lat with db params from
rels {offsetClause :: [Word64]
offsetClause = Word64
off Word64 -> [Word64] -> [Word64]
forall a. a -> [a] -> [a]
: TableExpression grp lat with db params from -> [Word64]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from -> [Word64]
offsetClause TableExpression grp lat with db params from
rels}

{- | Add a `LockingClause` to a `TableExpression`.
Multiple `LockingClause`s can be written if it is necessary
to specify different locking behavior for different tables.
If the same table is mentioned (or implicitly affected)
by more than one locking clause, then it is processed
as if it was only specified by the strongest one.
Similarly, a table is processed as `NoWait` if that is specified
in any of the clauses affecting it. Otherwise, it is processed
as `SkipLocked` if that is specified in any of the clauses affecting it.
Further, a `LockingClause` cannot be added to a grouped table expression.
-}
lockRows
  :: LockingClause from -- ^ row-level lock
  -> TableExpression 'Ungrouped lat with db params from
  -> TableExpression 'Ungrouped lat with db params from
lockRows :: LockingClause from
-> TableExpression 'Ungrouped lat with db params from
-> TableExpression 'Ungrouped lat with db params from
lockRows LockingClause from
lck TableExpression 'Ungrouped lat with db params from
tab = TableExpression 'Ungrouped lat with db params from
tab {lockingClauses :: [LockingClause from]
lockingClauses = LockingClause from
lck LockingClause from -> [LockingClause from] -> [LockingClause from]
forall a. a -> [a] -> [a]
: TableExpression 'Ungrouped lat with db params from
-> [LockingClause from]
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType).
TableExpression grp lat with db params from -> [LockingClause from]
lockingClauses TableExpression 'Ungrouped lat with db params from
tab}

{-----------------------------------------
Grouping
-----------------------------------------}

-- | `By`s are used in `groupBy` to reference a list of columns which are then
-- used to group together those rows in a table that have the same values
-- in all the columns listed. @By \#col@ will reference an unambiguous
-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
-- qualified column @tab.col@.
data By
    (from :: FromType)
    (by :: (Symbol,Symbol)) where
    By1
      :: (HasUnique table from columns, Has column columns ty)
      => Alias column
      -> By from '(table, column)
    By2
      :: (Has table from columns, Has column columns ty)
      => Alias table
      -> Alias column
      -> By from '(table, column)
deriving instance Show (By from by)
deriving instance Eq (By from by)
deriving instance Ord (By from by)
instance RenderSQL (By from by) where
  renderSQL :: By from by -> ByteString
renderSQL = \case
    By1 Alias column
column -> Alias column -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Alias column
column
    By2 Alias table
rel Alias column
column -> Alias table -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Alias table
rel ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"." ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Alias column -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Alias column
column

instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
  => IsLabel col (By rels by) where fromLabel :: By rels by
fromLabel = Alias col -> By rels '(rel, col)
forall (table :: Symbol) (from :: FromType) (columns :: RowType)
       (table :: Symbol) (ty :: NullType).
(HasUnique table from columns, Has table columns ty) =>
Alias table -> By from '(table, table)
By1 Alias col
forall (x :: Symbol) a. IsLabel x a => a
fromLabel
instance (HasUnique rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])
  => IsLabel col (NP (By rels) bys) where fromLabel :: NP (By rels) bys
fromLabel = Alias col -> By rels '(rel, col)
forall (table :: Symbol) (from :: FromType) (columns :: RowType)
       (table :: Symbol) (ty :: NullType).
(HasUnique table from columns, Has table columns ty) =>
Alias table -> By from '(table, table)
By1 Alias col
forall (x :: Symbol) a. IsLabel x a => a
fromLabel By rels '(rel, col)
-> NP (By rels) '[] -> NP (By rels) '[ '(rel, col)]
forall k (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* NP (By rels) '[]
forall k (a :: k -> *). NP a '[]
Nil
instance (Has rel rels cols, Has col cols ty, by ~ '(rel, col))
  => IsQualified rel col (By rels by) where (!) = Alias rel -> Alias col -> By rels by
forall (table :: Symbol) (from :: FromType) (columns :: RowType)
       (column :: Symbol) (ty :: NullType).
(Has table from columns, Has column columns ty) =>
Alias table -> Alias column -> By from '(table, column)
By2
instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])
  => IsQualified rel col (NP (By rels) bys) where
    Alias rel
rel ! :: Alias rel -> Alias col -> NP (By rels) bys
! Alias col
col = Alias rel -> Alias col -> By rels '(rel, col)
forall (table :: Symbol) (from :: FromType) (columns :: RowType)
       (column :: Symbol) (ty :: NullType).
(Has table from columns, Has column columns ty) =>
Alias table -> Alias column -> By from '(table, column)
By2 Alias rel
rel Alias col
col By rels '(rel, col)
-> NP (By rels) '[] -> NP (By rels) '[ '(rel, col)]
forall k (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* NP (By rels) '[]
forall k (a :: k -> *). NP a '[]
Nil

-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
newtype GroupByClause grp from = UnsafeGroupByClause
  { GroupByClause grp from -> ByteString
renderGroupByClause :: ByteString }
  deriving stock ((forall x.
 GroupByClause grp from -> Rep (GroupByClause grp from) x)
-> (forall x.
    Rep (GroupByClause grp from) x -> GroupByClause grp from)
-> Generic (GroupByClause grp from)
forall x. Rep (GroupByClause grp from) x -> GroupByClause grp from
forall x. GroupByClause grp from -> Rep (GroupByClause grp from) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall k (grp :: k) k (from :: k) x.
Rep (GroupByClause grp from) x -> GroupByClause grp from
forall k (grp :: k) k (from :: k) x.
GroupByClause grp from -> Rep (GroupByClause grp from) x
$cto :: forall k (grp :: k) k (from :: k) x.
Rep (GroupByClause grp from) x -> GroupByClause grp from
$cfrom :: forall k (grp :: k) k (from :: k) x.
GroupByClause grp from -> Rep (GroupByClause grp from) x
GHC.Generic,Int -> GroupByClause grp from -> ShowS
[GroupByClause grp from] -> ShowS
GroupByClause grp from -> String
(Int -> GroupByClause grp from -> ShowS)
-> (GroupByClause grp from -> String)
-> ([GroupByClause grp from] -> ShowS)
-> Show (GroupByClause grp from)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall k (grp :: k) k (from :: k).
Int -> GroupByClause grp from -> ShowS
forall k (grp :: k) k (from :: k).
[GroupByClause grp from] -> ShowS
forall k (grp :: k) k (from :: k). GroupByClause grp from -> String
showList :: [GroupByClause grp from] -> ShowS
$cshowList :: forall k (grp :: k) k (from :: k).
[GroupByClause grp from] -> ShowS
show :: GroupByClause grp from -> String
$cshow :: forall k (grp :: k) k (from :: k). GroupByClause grp from -> String
showsPrec :: Int -> GroupByClause grp from -> ShowS
$cshowsPrec :: forall k (grp :: k) k (from :: k).
Int -> GroupByClause grp from -> ShowS
Show,GroupByClause grp from -> GroupByClause grp from -> Bool
(GroupByClause grp from -> GroupByClause grp from -> Bool)
-> (GroupByClause grp from -> GroupByClause grp from -> Bool)
-> Eq (GroupByClause grp from)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
/= :: GroupByClause grp from -> GroupByClause grp from -> Bool
$c/= :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
== :: GroupByClause grp from -> GroupByClause grp from -> Bool
$c== :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
Eq,Eq (GroupByClause grp from)
Eq (GroupByClause grp from)
-> (GroupByClause grp from -> GroupByClause grp from -> Ordering)
-> (GroupByClause grp from -> GroupByClause grp from -> Bool)
-> (GroupByClause grp from -> GroupByClause grp from -> Bool)
-> (GroupByClause grp from -> GroupByClause grp from -> Bool)
-> (GroupByClause grp from -> GroupByClause grp from -> Bool)
-> (GroupByClause grp from
    -> GroupByClause grp from -> GroupByClause grp from)
-> (GroupByClause grp from
    -> GroupByClause grp from -> GroupByClause grp from)
-> Ord (GroupByClause grp from)
GroupByClause grp from -> GroupByClause grp from -> Bool
GroupByClause grp from -> GroupByClause grp from -> Ordering
GroupByClause grp from
-> GroupByClause grp from -> GroupByClause grp from
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall k (grp :: k) k (from :: k). Eq (GroupByClause grp from)
forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Ordering
forall k (grp :: k) k (from :: k).
GroupByClause grp from
-> GroupByClause grp from -> GroupByClause grp from
min :: GroupByClause grp from
-> GroupByClause grp from -> GroupByClause grp from
$cmin :: forall k (grp :: k) k (from :: k).
GroupByClause grp from
-> GroupByClause grp from -> GroupByClause grp from
max :: GroupByClause grp from
-> GroupByClause grp from -> GroupByClause grp from
$cmax :: forall k (grp :: k) k (from :: k).
GroupByClause grp from
-> GroupByClause grp from -> GroupByClause grp from
>= :: GroupByClause grp from -> GroupByClause grp from -> Bool
$c>= :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
> :: GroupByClause grp from -> GroupByClause grp from -> Bool
$c> :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
<= :: GroupByClause grp from -> GroupByClause grp from -> Bool
$c<= :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
< :: GroupByClause grp from -> GroupByClause grp from -> Bool
$c< :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Bool
compare :: GroupByClause grp from -> GroupByClause grp from -> Ordering
$ccompare :: forall k (grp :: k) k (from :: k).
GroupByClause grp from -> GroupByClause grp from -> Ordering
$cp1Ord :: forall k (grp :: k) k (from :: k). Eq (GroupByClause grp from)
Ord)
  deriving newtype (GroupByClause grp from -> ()
(GroupByClause grp from -> ()) -> NFData (GroupByClause grp from)
forall a. (a -> ()) -> NFData a
forall k (grp :: k) k (from :: k). GroupByClause grp from -> ()
rnf :: GroupByClause grp from -> ()
$crnf :: forall k (grp :: k) k (from :: k). GroupByClause grp from -> ()
NFData)
instance RenderSQL (GroupByClause grp from) where
  renderSQL :: GroupByClause grp from -> ByteString
renderSQL = GroupByClause grp from -> ByteString
forall k (grp :: k) k (from :: k).
GroupByClause grp from -> ByteString
renderGroupByClause
noGroups :: GroupByClause 'Ungrouped from
noGroups :: GroupByClause 'Ungrouped from
noGroups = ByteString -> GroupByClause 'Ungrouped from
forall k k (grp :: k) (from :: k).
ByteString -> GroupByClause grp from
UnsafeGroupByClause ByteString
""
group
  :: SListI bys
  => NP (By from) bys
  -> GroupByClause ('Grouped bys) from
group :: NP (By from) bys -> GroupByClause ('Grouped bys) from
group NP (By from) bys
bys = ByteString -> GroupByClause ('Grouped bys) from
forall k k (grp :: k) (from :: k).
ByteString -> GroupByClause grp from
UnsafeGroupByClause (ByteString -> GroupByClause ('Grouped bys) from)
-> ByteString -> GroupByClause ('Grouped bys) from
forall a b. (a -> b) -> a -> b
$ case NP (By from) bys
bys of
  NP (By from) bys
Nil -> ByteString
""
  NP (By from) bys
_ -> ByteString
" GROUP BY" ByteString -> ByteString -> ByteString
<+> (forall (x :: (Symbol, Symbol)). By from x -> ByteString)
-> NP (By from) bys -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall sql. RenderSQL sql => sql -> ByteString
forall (x :: (Symbol, Symbol)). By from x -> ByteString
renderSQL NP (By from) bys
bys

-- | A `HavingClause` is used to eliminate groups that are not of interest.
-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
-- `TableExpression` must use `Having` whose conditions are combined with
-- `.&&`.
data HavingClause grp lat with db params from where
  NoHaving :: HavingClause 'Ungrouped lat with db params from
  Having
    :: [Condition ('Grouped bys) lat with db params from]
    -> HavingClause ('Grouped bys) lat with db params from
deriving instance Show (HavingClause grp lat with db params from)
deriving instance Eq (HavingClause grp lat with db params from)
deriving instance Ord (HavingClause grp lat with db params from)

-- | Render a `HavingClause`.
instance RenderSQL (HavingClause grp lat with db params from) where
  renderSQL :: HavingClause grp lat with db params from -> ByteString
renderSQL = \case
    HavingClause grp lat with db params from
NoHaving -> ByteString
""
    Having [] -> ByteString
""
    Having [Condition ('Grouped bys) lat with db params from]
conditions ->
      ByteString
" HAVING" ByteString -> ByteString -> ByteString
<+> [ByteString] -> ByteString
commaSeparated (Condition ('Grouped bys) lat with db params from -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL (Condition ('Grouped bys) lat with db params from -> ByteString)
-> [Condition ('Grouped bys) lat with db params from]
-> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Condition ('Grouped bys) lat with db params from]
conditions)

{- |
If specific tables are named in a locking clause,
then only rows coming from those tables are locked;
any other tables used in the `Squeal.PostgreSQL.Query.Select.select` are simply read as usual.
A locking clause with a `Nil` table list affects all tables used in the statement.
If a locking clause is applied to a `view` or `subquery`,
it affects all tables used in the `view` or `subquery`.
However, these clauses do not apply to `Squeal.PostgreSQL.Query.With.with` queries referenced by the primary query.
If you want row locking to occur within a `Squeal.PostgreSQL.Query.With.with` query,
specify a `LockingClause` within the `Squeal.PostgreSQL.Query.With.with` query.
-}
data LockingClause from where
  For
    :: HasAll tabs from tables
    => LockStrength -- ^ lock strength
    -> NP Alias tabs -- ^ table list
    -> Waiting -- ^ wait or not
    -> LockingClause from
instance RenderSQL (LockingClause from) where
  renderSQL :: LockingClause from -> ByteString
renderSQL (For LockStrength
str NP Alias tabs
tabs Waiting
wt) =
    ByteString
"FOR" ByteString -> ByteString -> ByteString
<+> LockStrength -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL LockStrength
str
    ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> case NP Alias tabs
tabs of
        NP Alias tabs
Nil -> ByteString
""
        NP Alias tabs
_ -> ByteString
" OF" ByteString -> ByteString -> ByteString
<+> NP Alias tabs -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL NP Alias tabs
tabs
    ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Waiting -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Waiting
wt

{- |
Row-level locks, which are listed as below with the contexts
in which they are used automatically by PostgreSQL.
Note that a transaction can hold conflicting locks on the same row,
even in different subtransactions; but other than that,
two transactions can never hold conflicting locks on the same row.
Row-level locks do not affect data querying;
they block only writers and lockers to the same row.
Row-level locks are released at transaction end or during savepoint rollback.
-}
data LockStrength
  = Update
  {- ^ `For` `Update` causes the rows retrieved by the `Squeal.PostgreSQL.Query.Select.select` statement
  to be locked as though for update. This prevents them from being locked,
  modified or deleted by other transactions until the current transaction ends.
  That is, other transactions that attempt `Squeal.PostgreSQL.Manipulation.Update.update`, `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom`,
  `Squeal.PostgreSQL.Query.Select.select` `For` `Update`, `Squeal.PostgreSQL.Query.Select.select` `For` `NoKeyUpdate`,
  `Squeal.PostgreSQL.Query.Select.select` `For` `Share` or `Squeal.PostgreSQL.Query.Select.select` `For` `KeyShare` of these rows will be blocked
  until the current transaction ends; conversely, `Squeal.PostgreSQL.Query.Select.select` `For` `Update` will wait
  for a concurrent transaction that has run any of those commands on the same row,
  and will then lock and return the updated row (or no row, if the row was deleted).
  Within a `Squeal.PostgreSQL.Session.Transaction.RepeatableRead` or `Squeal.PostgreSQL.Session.Transaction.Serializable` transaction, however, an error will be
  thrown if a row to be locked has changed since the transaction started.

  The `For` `Update` lock mode is also acquired by any `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom` a row,
  and also by an `Update` that modifies the values on certain columns.
  Currently, the set of columns considered for the `Squeal.PostgreSQL.Manipulation.Update.update` case are those
  that have a unique index on them that can be used in a foreign key
  (so partial indexes and expressional indexes are not considered),
  but this may change in the future.-}
  | NoKeyUpdate
  {- | Behaves similarly to `For` `Update`, except that the lock acquired is weaker:
  this lock will not block `Squeal.PostgreSQL.Query.Select.select` `For` `KeyShare` commands that attempt to acquire
  a lock on the same rows. This lock mode is also acquired by any `Squeal.PostgreSQL.Manipulation.Update.update`
  that does not acquire a `For` `Update` lock.-}
  | Share
  {- | Behaves similarly to `For` `Share`, except that the lock is weaker:
  `Squeal.PostgreSQL.Query.Select.select` `For` `Update` is blocked, but not `Squeal.PostgreSQL.Query.Select.select` `For` `NoKeyUpdate`.
  A key-shared lock blocks other transactions from performing
  `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom` or any `Squeal.PostgreSQL.Manipulation.Update.update` that changes the key values,
  but not other `Update`, and neither does it prevent `Squeal.PostgreSQL.Query.Select.select` `For` `NoKeyUpdate`,
  `Squeal.PostgreSQL.Query.Select.select` `For` `Share`, or `Squeal.PostgreSQL.Query.Select.select` `For` `KeyShare`.-}
  | KeyShare
  deriving (LockStrength -> LockStrength -> Bool
(LockStrength -> LockStrength -> Bool)
-> (LockStrength -> LockStrength -> Bool) -> Eq LockStrength
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LockStrength -> LockStrength -> Bool
$c/= :: LockStrength -> LockStrength -> Bool
== :: LockStrength -> LockStrength -> Bool
$c== :: LockStrength -> LockStrength -> Bool
Eq, Eq LockStrength
Eq LockStrength
-> (LockStrength -> LockStrength -> Ordering)
-> (LockStrength -> LockStrength -> Bool)
-> (LockStrength -> LockStrength -> Bool)
-> (LockStrength -> LockStrength -> Bool)
-> (LockStrength -> LockStrength -> Bool)
-> (LockStrength -> LockStrength -> LockStrength)
-> (LockStrength -> LockStrength -> LockStrength)
-> Ord LockStrength
LockStrength -> LockStrength -> Bool
LockStrength -> LockStrength -> Ordering
LockStrength -> LockStrength -> LockStrength
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: LockStrength -> LockStrength -> LockStrength
$cmin :: LockStrength -> LockStrength -> LockStrength
max :: LockStrength -> LockStrength -> LockStrength
$cmax :: LockStrength -> LockStrength -> LockStrength
>= :: LockStrength -> LockStrength -> Bool
$c>= :: LockStrength -> LockStrength -> Bool
> :: LockStrength -> LockStrength -> Bool
$c> :: LockStrength -> LockStrength -> Bool
<= :: LockStrength -> LockStrength -> Bool
$c<= :: LockStrength -> LockStrength -> Bool
< :: LockStrength -> LockStrength -> Bool
$c< :: LockStrength -> LockStrength -> Bool
compare :: LockStrength -> LockStrength -> Ordering
$ccompare :: LockStrength -> LockStrength -> Ordering
$cp1Ord :: Eq LockStrength
Ord, Int -> LockStrength -> ShowS
[LockStrength] -> ShowS
LockStrength -> String
(Int -> LockStrength -> ShowS)
-> (LockStrength -> String)
-> ([LockStrength] -> ShowS)
-> Show LockStrength
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LockStrength] -> ShowS
$cshowList :: [LockStrength] -> ShowS
show :: LockStrength -> String
$cshow :: LockStrength -> String
showsPrec :: Int -> LockStrength -> ShowS
$cshowsPrec :: Int -> LockStrength -> ShowS
Show, ReadPrec [LockStrength]
ReadPrec LockStrength
Int -> ReadS LockStrength
ReadS [LockStrength]
(Int -> ReadS LockStrength)
-> ReadS [LockStrength]
-> ReadPrec LockStrength
-> ReadPrec [LockStrength]
-> Read LockStrength
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [LockStrength]
$creadListPrec :: ReadPrec [LockStrength]
readPrec :: ReadPrec LockStrength
$creadPrec :: ReadPrec LockStrength
readList :: ReadS [LockStrength]
$creadList :: ReadS [LockStrength]
readsPrec :: Int -> ReadS LockStrength
$creadsPrec :: Int -> ReadS LockStrength
Read, Int -> LockStrength
LockStrength -> Int
LockStrength -> [LockStrength]
LockStrength -> LockStrength
LockStrength -> LockStrength -> [LockStrength]
LockStrength -> LockStrength -> LockStrength -> [LockStrength]
(LockStrength -> LockStrength)
-> (LockStrength -> LockStrength)
-> (Int -> LockStrength)
-> (LockStrength -> Int)
-> (LockStrength -> [LockStrength])
-> (LockStrength -> LockStrength -> [LockStrength])
-> (LockStrength -> LockStrength -> [LockStrength])
-> (LockStrength -> LockStrength -> LockStrength -> [LockStrength])
-> Enum LockStrength
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: LockStrength -> LockStrength -> LockStrength -> [LockStrength]
$cenumFromThenTo :: LockStrength -> LockStrength -> LockStrength -> [LockStrength]
enumFromTo :: LockStrength -> LockStrength -> [LockStrength]
$cenumFromTo :: LockStrength -> LockStrength -> [LockStrength]
enumFromThen :: LockStrength -> LockStrength -> [LockStrength]
$cenumFromThen :: LockStrength -> LockStrength -> [LockStrength]
enumFrom :: LockStrength -> [LockStrength]
$cenumFrom :: LockStrength -> [LockStrength]
fromEnum :: LockStrength -> Int
$cfromEnum :: LockStrength -> Int
toEnum :: Int -> LockStrength
$ctoEnum :: Int -> LockStrength
pred :: LockStrength -> LockStrength
$cpred :: LockStrength -> LockStrength
succ :: LockStrength -> LockStrength
$csucc :: LockStrength -> LockStrength
Enum, (forall x. LockStrength -> Rep LockStrength x)
-> (forall x. Rep LockStrength x -> LockStrength)
-> Generic LockStrength
forall x. Rep LockStrength x -> LockStrength
forall x. LockStrength -> Rep LockStrength x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep LockStrength x -> LockStrength
$cfrom :: forall x. LockStrength -> Rep LockStrength x
GHC.Generic)
instance RenderSQL LockStrength where
  renderSQL :: LockStrength -> ByteString
renderSQL = \case
    LockStrength
Update -> ByteString
"UPDATE"
    LockStrength
NoKeyUpdate -> ByteString
"NO KEY UPDATE"
    LockStrength
Share -> ByteString
"SHARE"
    LockStrength
KeyShare -> ByteString
"KEY SHARE"

-- | To prevent the operation from `Waiting` for other transactions to commit,
-- use either the `NoWait` or `SkipLocked` option.
data Waiting
  = Wait
  -- ^ wait for other transactions to commit
  | NoWait
  -- ^ reports an error, rather than waiting
  | SkipLocked
  -- ^ any selected rows that cannot be immediately locked are skipped
  deriving (Waiting -> Waiting -> Bool
(Waiting -> Waiting -> Bool)
-> (Waiting -> Waiting -> Bool) -> Eq Waiting
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Waiting -> Waiting -> Bool
$c/= :: Waiting -> Waiting -> Bool
== :: Waiting -> Waiting -> Bool
$c== :: Waiting -> Waiting -> Bool
Eq, Eq Waiting
Eq Waiting
-> (Waiting -> Waiting -> Ordering)
-> (Waiting -> Waiting -> Bool)
-> (Waiting -> Waiting -> Bool)
-> (Waiting -> Waiting -> Bool)
-> (Waiting -> Waiting -> Bool)
-> (Waiting -> Waiting -> Waiting)
-> (Waiting -> Waiting -> Waiting)
-> Ord Waiting
Waiting -> Waiting -> Bool
Waiting -> Waiting -> Ordering
Waiting -> Waiting -> Waiting
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Waiting -> Waiting -> Waiting
$cmin :: Waiting -> Waiting -> Waiting
max :: Waiting -> Waiting -> Waiting
$cmax :: Waiting -> Waiting -> Waiting
>= :: Waiting -> Waiting -> Bool
$c>= :: Waiting -> Waiting -> Bool
> :: Waiting -> Waiting -> Bool
$c> :: Waiting -> Waiting -> Bool
<= :: Waiting -> Waiting -> Bool
$c<= :: Waiting -> Waiting -> Bool
< :: Waiting -> Waiting -> Bool
$c< :: Waiting -> Waiting -> Bool
compare :: Waiting -> Waiting -> Ordering
$ccompare :: Waiting -> Waiting -> Ordering
$cp1Ord :: Eq Waiting
Ord, Int -> Waiting -> ShowS
[Waiting] -> ShowS
Waiting -> String
(Int -> Waiting -> ShowS)
-> (Waiting -> String) -> ([Waiting] -> ShowS) -> Show Waiting
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Waiting] -> ShowS
$cshowList :: [Waiting] -> ShowS
show :: Waiting -> String
$cshow :: Waiting -> String
showsPrec :: Int -> Waiting -> ShowS
$cshowsPrec :: Int -> Waiting -> ShowS
Show, ReadPrec [Waiting]
ReadPrec Waiting
Int -> ReadS Waiting
ReadS [Waiting]
(Int -> ReadS Waiting)
-> ReadS [Waiting]
-> ReadPrec Waiting
-> ReadPrec [Waiting]
-> Read Waiting
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Waiting]
$creadListPrec :: ReadPrec [Waiting]
readPrec :: ReadPrec Waiting
$creadPrec :: ReadPrec Waiting
readList :: ReadS [Waiting]
$creadList :: ReadS [Waiting]
readsPrec :: Int -> ReadS Waiting
$creadsPrec :: Int -> ReadS Waiting
Read, Int -> Waiting
Waiting -> Int
Waiting -> [Waiting]
Waiting -> Waiting
Waiting -> Waiting -> [Waiting]
Waiting -> Waiting -> Waiting -> [Waiting]
(Waiting -> Waiting)
-> (Waiting -> Waiting)
-> (Int -> Waiting)
-> (Waiting -> Int)
-> (Waiting -> [Waiting])
-> (Waiting -> Waiting -> [Waiting])
-> (Waiting -> Waiting -> [Waiting])
-> (Waiting -> Waiting -> Waiting -> [Waiting])
-> Enum Waiting
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Waiting -> Waiting -> Waiting -> [Waiting]
$cenumFromThenTo :: Waiting -> Waiting -> Waiting -> [Waiting]
enumFromTo :: Waiting -> Waiting -> [Waiting]
$cenumFromTo :: Waiting -> Waiting -> [Waiting]
enumFromThen :: Waiting -> Waiting -> [Waiting]
$cenumFromThen :: Waiting -> Waiting -> [Waiting]
enumFrom :: Waiting -> [Waiting]
$cenumFrom :: Waiting -> [Waiting]
fromEnum :: Waiting -> Int
$cfromEnum :: Waiting -> Int
toEnum :: Int -> Waiting
$ctoEnum :: Int -> Waiting
pred :: Waiting -> Waiting
$cpred :: Waiting -> Waiting
succ :: Waiting -> Waiting
$csucc :: Waiting -> Waiting
Enum, (forall x. Waiting -> Rep Waiting x)
-> (forall x. Rep Waiting x -> Waiting) -> Generic Waiting
forall x. Rep Waiting x -> Waiting
forall x. Waiting -> Rep Waiting x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Waiting x -> Waiting
$cfrom :: forall x. Waiting -> Rep Waiting x
GHC.Generic)
instance RenderSQL Waiting where
  renderSQL :: Waiting -> ByteString
renderSQL = \case
    Waiting
Wait -> ByteString
""
    Waiting
NoWait -> ByteString
" NOWAIT"
    Waiting
SkipLocked -> ByteString
" SKIP LOCKED"