{- |

Module "Database.PostgreSQL.PQTypes.SQL.Builder" offers a nice
monadic DSL for building SQL statements on the fly. Some examples:

>>> :{
sqlSelect "documents" $ do
  sqlResult "id"
  sqlResult "title"
  sqlResult "mtime"
  sqlOrderBy "documents.mtime DESC"
  sqlWhereILike "documents.title" "%pattern%"
:}
SQL " SELECT  id, title, mtime FROM documents WHERE (documents.title ILIKE <\"%pattern%\">)    ORDER BY documents.mtime DESC  "

@SQL.Builder@ supports SELECT as 'sqlSelect' and data manipulation using
'sqlInsert', 'sqlInsertSelect', 'sqlDelete' and 'sqlUpdate'.

>>> import Data.Time
>>> let title = "title" :: String
>>> let ctime  = read "2020-01-01 00:00:00 UTC" :: UTCTime
>>> :{
sqlInsert "documents" $ do
  sqlSet "title" title
  sqlSet "ctime" ctime
  sqlResult "id"
:}
SQL " INSERT INTO documents (title, ctime) VALUES (<\"title\">, <2020-01-01 00:00:00 UTC>)  RETURNING id"

The 'sqlInsertSelect' is particulary interesting as it supports INSERT
of values taken from a SELECT clause from same or even different
tables.

There is a possibility to do multiple inserts at once. Data given by
'sqlSetList' will be inserted multiple times, data given by 'sqlSet'
will be multiplied as many times as needed to cover all inserted rows
(it is common to all rows). If you use multiple 'sqlSetList' then
lists will be made equal in length by appending @DEFAULT@ as fill
element.

>>> :{
sqlInsert "documents" $ do
  sqlSet "ctime" ctime
  sqlSetList "title" ["title1", "title2", "title3"]
  sqlResult "id"
:}
SQL " INSERT INTO documents (ctime, title) VALUES (<2020-01-01 00:00:00 UTC>, <\"title1\">) , (<2020-01-01 00:00:00 UTC>, <\"title2\">) , (<2020-01-01 00:00:00 UTC>, <\"title3\">)  RETURNING id"

The above will insert 3 new documents.

@SQL.Builder@ provides quite a lot of SQL magic, including @ORDER BY@ as
'sqlOrderBy', @GROUP BY@ as 'sqlGroupBy'.

>>> :{
sqlSelect "documents" $ do
  sqlResult "id"
  sqlResult "title"
  sqlResult "mtime"
  sqlOrderBy "documents.mtime DESC"
  sqlOrderBy "documents.title"
  sqlGroupBy "documents.status"
  sqlJoinOn "users" "documents.user_id = users.id"
  sqlWhere $ mkSQL "documents.title ILIKE" <?> "%pattern%"
:}
SQL " SELECT  id, title, mtime FROM documents  JOIN  users  ON  documents.user_id = users.id WHERE (documents.title ILIKE <\"%pattern%\">)  GROUP BY documents.status  ORDER BY documents.mtime DESC, documents.title  "

Joins are done by 'sqlJoinOn', 'sqlLeftJoinOn', 'sqlRightJoinOn',
'sqlJoinOn', 'sqlFullJoinOn'. If everything fails use 'sqlJoin' and
'sqlFrom' to set join clause as string. Support for a join grammars as
some kind of abstract syntax data type is lacking.

>>> :{
sqlDelete "mails" $ do
  sqlWhere "id > 67"
:}
SQL " DELETE FROM mails  WHERE (id > 67) "

>>> :{
sqlUpdate "document_tags" $ do
  sqlSet "value" (123 :: Int)
  sqlWhere "name = 'abc'"
:}
SQL " UPDATE document_tags SET value=<123>  WHERE (name = 'abc') "

-}

-- TODO: clean this up, add more documentation.

module Database.PostgreSQL.PQTypes.SQL.Builder
  ( sqlWhere
  , sqlWhereEq
  , sqlWhereEqSql
  , sqlWhereNotEq
  , sqlWhereEqualsAny
  , sqlWhereIn
  , sqlWhereInSql
  , sqlWhereNotIn
  , sqlWhereNotInSql
  , sqlWhereExists
  , sqlWhereNotExists
  , sqlWhereLike
  , sqlWhereILike
  , sqlWhereIsNULL
  , sqlWhereIsNotNULL

  , sqlFrom
  , sqlJoin
  , sqlJoinOn
  , sqlLeftJoinOn
  , sqlRightJoinOn
  , sqlFullJoinOn
  , sqlOnConflictDoNothing
  , sqlOnConflictOnColumns
  , sqlOnConflictOnColumnsDoNothing
  , sqlSet
  , sqlSetInc
  , sqlSetList
  , sqlSetListWithDefaults
  , sqlSetCmd
  , sqlSetCmdList
  , sqlCopyColumn
  , sqlResult
  , sqlOrderBy
  , sqlGroupBy
  , sqlHaving
  , sqlOffset
  , sqlLimit
  , sqlDistinct
  , sqlWith
  , sqlWithMaterialized
  , sqlUnion
  , sqlUnionAll
  , checkAndRememberMaterializationSupport

  , sqlSelect
  , sqlSelect2
  , SqlSelect(..)
  , sqlInsert
  , SqlInsert(..)
  , sqlInsertSelect
  , SqlInsertSelect(..)
  , sqlUpdate
  , SqlUpdate(..)
  , sqlDelete
  , SqlDelete(..)

  , sqlWhereAny

  , SqlResult
  , SqlSet
  , SqlFrom
  , SqlWhere
  , SqlWith
  , SqlOrderBy
  , SqlGroupByHaving
  , SqlOffsetLimit
  , SqlDistinct

  , SqlCondition(..)
  , sqlGetWhereConditions

  , Sqlable(..)
  , sqlOR
  , sqlConcatComma
  , sqlConcatAND
  , sqlConcatOR
  , parenthesize
  , AscDesc(..)
  )
  where

import Control.Monad.State
import Control.Monad.Catch
import Data.Int
import Data.IORef
import Data.Either
import Data.List
import Data.Maybe
import Data.Monoid.Utils
import Data.String
import Data.Typeable
import Database.PostgreSQL.PQTypes
import System.IO.Unsafe

class Sqlable a where
  toSQLCommand :: a -> SQL

instance Sqlable SQL where
  toSQLCommand :: SQL -> SQL
toSQLCommand = forall a. a -> a
id

smintercalate :: (IsString m, Monoid m) => m -> [m] -> m
smintercalate :: forall m. (IsString m, Monoid m) => m -> [m] -> m
smintercalate m
m = forall m. Monoid m => m -> [m] -> m
mintercalate forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [forall m. (IsString m, Monoid m) => m
mspace, m
m, forall m. (IsString m, Monoid m) => m
mspace]

sqlOR :: SQL -> SQL -> SQL
sqlOR :: SQL -> SQL -> SQL
sqlOR SQL
s1 SQL
s2 = [SQL] -> SQL
sqlConcatOR [SQL
s1, SQL
s2]

sqlConcatComma :: [SQL] -> SQL
sqlConcatComma :: [SQL] -> SQL
sqlConcatComma = forall m. Monoid m => m -> [m] -> m
mintercalate SQL
", "

sqlConcatAND :: [SQL] -> SQL
sqlConcatAND :: [SQL] -> SQL
sqlConcatAND = forall m. (IsString m, Monoid m) => m -> [m] -> m
smintercalate SQL
"AND" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map SQL -> SQL
parenthesize

sqlConcatOR :: [SQL] -> SQL
sqlConcatOR :: [SQL] -> SQL
sqlConcatOR = forall m. (IsString m, Monoid m) => m -> [m] -> m
smintercalate SQL
"OR" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map SQL -> SQL
parenthesize

parenthesize :: SQL -> SQL
parenthesize :: SQL -> SQL
parenthesize SQL
s = SQL
"(" forall a. Semigroup a => a -> a -> a
<> SQL
s forall a. Semigroup a => a -> a -> a
<> SQL
")"

-- | 'AscDesc' marks ORDER BY order as ascending or descending.
-- Conversion to SQL adds DESC marker to descending and no marker
-- to ascending order.
data AscDesc a = Asc a | Desc a
  deriving (AscDesc a -> AscDesc a -> Bool
forall a. Eq a => AscDesc a -> AscDesc a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AscDesc a -> AscDesc a -> Bool
$c/= :: forall a. Eq a => AscDesc a -> AscDesc a -> Bool
== :: AscDesc a -> AscDesc a -> Bool
$c== :: forall a. Eq a => AscDesc a -> AscDesc a -> Bool
Eq, Int -> AscDesc a -> ShowS
forall a. Show a => Int -> AscDesc a -> ShowS
forall a. Show a => [AscDesc a] -> ShowS
forall a. Show a => AscDesc a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AscDesc a] -> ShowS
$cshowList :: forall a. Show a => [AscDesc a] -> ShowS
show :: AscDesc a -> String
$cshow :: forall a. Show a => AscDesc a -> String
showsPrec :: Int -> AscDesc a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> AscDesc a -> ShowS
Show)

data Multiplicity a = Single a | Many [a]
  deriving (Multiplicity a -> Multiplicity a -> Bool
forall a. Eq a => Multiplicity a -> Multiplicity a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Multiplicity a -> Multiplicity a -> Bool
$c/= :: forall a. Eq a => Multiplicity a -> Multiplicity a -> Bool
== :: Multiplicity a -> Multiplicity a -> Bool
$c== :: forall a. Eq a => Multiplicity a -> Multiplicity a -> Bool
Eq, Multiplicity a -> Multiplicity a -> Bool
Multiplicity a -> Multiplicity a -> Ordering
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 {a}. Ord a => Eq (Multiplicity a)
forall a. Ord a => Multiplicity a -> Multiplicity a -> Bool
forall a. Ord a => Multiplicity a -> Multiplicity a -> Ordering
forall a.
Ord a =>
Multiplicity a -> Multiplicity a -> Multiplicity a
min :: Multiplicity a -> Multiplicity a -> Multiplicity a
$cmin :: forall a.
Ord a =>
Multiplicity a -> Multiplicity a -> Multiplicity a
max :: Multiplicity a -> Multiplicity a -> Multiplicity a
$cmax :: forall a.
Ord a =>
Multiplicity a -> Multiplicity a -> Multiplicity a
>= :: Multiplicity a -> Multiplicity a -> Bool
$c>= :: forall a. Ord a => Multiplicity a -> Multiplicity a -> Bool
> :: Multiplicity a -> Multiplicity a -> Bool
$c> :: forall a. Ord a => Multiplicity a -> Multiplicity a -> Bool
<= :: Multiplicity a -> Multiplicity a -> Bool
$c<= :: forall a. Ord a => Multiplicity a -> Multiplicity a -> Bool
< :: Multiplicity a -> Multiplicity a -> Bool
$c< :: forall a. Ord a => Multiplicity a -> Multiplicity a -> Bool
compare :: Multiplicity a -> Multiplicity a -> Ordering
$ccompare :: forall a. Ord a => Multiplicity a -> Multiplicity a -> Ordering
Ord, Int -> Multiplicity a -> ShowS
forall a. Show a => Int -> Multiplicity a -> ShowS
forall a. Show a => [Multiplicity a] -> ShowS
forall a. Show a => Multiplicity a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Multiplicity a] -> ShowS
$cshowList :: forall a. Show a => [Multiplicity a] -> ShowS
show :: Multiplicity a -> String
$cshow :: forall a. Show a => Multiplicity a -> String
showsPrec :: Int -> Multiplicity a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Multiplicity a -> ShowS
Show, Typeable)

-- | 'SqlCondition' are clauses that are part of the WHERE block in
-- SQL statements. Each statement has a list of conditions, all of
-- them must be fulfilled.  Sometimes we need to inspect internal
-- structure of a condition. For now it seems that the only
-- interesting case is EXISTS (SELECT ...), because that internal
-- SELECT can have explainable clauses.
data SqlCondition = SqlPlainCondition SQL
                  | SqlExistsCondition SqlSelect
                    deriving (Typeable, Int -> SqlCondition -> ShowS
[SqlCondition] -> ShowS
SqlCondition -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SqlCondition] -> ShowS
$cshowList :: [SqlCondition] -> ShowS
show :: SqlCondition -> String
$cshow :: SqlCondition -> String
showsPrec :: Int -> SqlCondition -> ShowS
$cshowsPrec :: Int -> SqlCondition -> ShowS
Show)

instance Sqlable SqlCondition where
  toSQLCommand :: SqlCondition -> SQL
toSQLCommand (SqlPlainCondition SQL
a) = SQL
a
  toSQLCommand (SqlExistsCondition SqlSelect
a) = SQL
"EXISTS (" forall a. Semigroup a => a -> a -> a
<> forall a. Sqlable a => a -> SQL
toSQLCommand (SqlSelect
a { sqlSelectResult :: [SQL]
sqlSelectResult = [SQL
"TRUE"] }) forall a. Semigroup a => a -> a -> a
<> SQL
")"

data SqlSelect = SqlSelect
  { SqlSelect -> SQL
sqlSelectFrom     :: SQL
  , SqlSelect -> [SQL]
sqlSelectUnion    :: [SQL]
  , SqlSelect -> [SQL]
sqlSelectUnionAll :: [SQL]
  , SqlSelect -> Bool
sqlSelectDistinct :: Bool
  , SqlSelect -> [SQL]
sqlSelectResult   :: [SQL]
  , SqlSelect -> [SqlCondition]
sqlSelectWhere    :: [SqlCondition]
  , SqlSelect -> [SQL]
sqlSelectOrderBy  :: [SQL]
  , SqlSelect -> [SQL]
sqlSelectGroupBy  :: [SQL]
  , SqlSelect -> [SQL]
sqlSelectHaving   :: [SQL]
  , SqlSelect -> Integer
sqlSelectOffset   :: Integer
  , SqlSelect -> Integer
sqlSelectLimit    :: Integer
  , SqlSelect -> [(SQL, SQL, Materialized)]
sqlSelectWith     :: [(SQL, SQL, Materialized)]
  }

data SqlUpdate = SqlUpdate
  { SqlUpdate -> SQL
sqlUpdateWhat   :: SQL
  , SqlUpdate -> SQL
sqlUpdateFrom   :: SQL
  , SqlUpdate -> [SqlCondition]
sqlUpdateWhere  :: [SqlCondition]
  , SqlUpdate -> [(SQL, SQL)]
sqlUpdateSet    :: [(SQL,SQL)]
  , SqlUpdate -> [SQL]
sqlUpdateResult :: [SQL]
  , SqlUpdate -> [(SQL, SQL, Materialized)]
sqlUpdateWith   :: [(SQL, SQL, Materialized)]
  }

data SqlInsert = SqlInsert
  { SqlInsert -> SQL
sqlInsertWhat       :: SQL
  , SqlInsert -> Maybe (SQL, Maybe SQL)
sqlInsertOnConflict :: Maybe (SQL, Maybe SQL)
  , SqlInsert -> [(SQL, Multiplicity SQL)]
sqlInsertSet        :: [(SQL, Multiplicity SQL)]
  , SqlInsert -> [SQL]
sqlInsertResult     :: [SQL]
  , SqlInsert -> [(SQL, SQL, Materialized)]
sqlInsertWith       :: [(SQL, SQL, Materialized)]
  }

data SqlInsertSelect = SqlInsertSelect
  { SqlInsertSelect -> SQL
sqlInsertSelectWhat       :: SQL
  , SqlInsertSelect -> Maybe (SQL, Maybe SQL)
sqlInsertSelectOnConflict :: Maybe (SQL, Maybe SQL)
  , SqlInsertSelect -> Bool
sqlInsertSelectDistinct   :: Bool
  , SqlInsertSelect -> [(SQL, SQL)]
sqlInsertSelectSet        :: [(SQL, SQL)]
  , SqlInsertSelect -> [SQL]
sqlInsertSelectResult     :: [SQL]
  , SqlInsertSelect -> SQL
sqlInsertSelectFrom       :: SQL
  , SqlInsertSelect -> [SqlCondition]
sqlInsertSelectWhere      :: [SqlCondition]
  , SqlInsertSelect -> [SQL]
sqlInsertSelectOrderBy    :: [SQL]
  , SqlInsertSelect -> [SQL]
sqlInsertSelectGroupBy    :: [SQL]
  , SqlInsertSelect -> [SQL]
sqlInsertSelectHaving     :: [SQL]
  , SqlInsertSelect -> Integer
sqlInsertSelectOffset     :: Integer
  , SqlInsertSelect -> Integer
sqlInsertSelectLimit      :: Integer
  , SqlInsertSelect -> [(SQL, SQL, Materialized)]
sqlInsertSelectWith       :: [(SQL, SQL, Materialized)]
  }

data SqlDelete = SqlDelete
  { SqlDelete -> SQL
sqlDeleteFrom   :: SQL
  , SqlDelete -> SQL
sqlDeleteUsing  :: SQL
  , SqlDelete -> [SqlCondition]
sqlDeleteWhere  :: [SqlCondition]
  , SqlDelete -> [SQL]
sqlDeleteResult :: [SQL]
  , SqlDelete -> [(SQL, SQL, Materialized)]
sqlDeleteWith   :: [(SQL, SQL, Materialized)]
  }

-- | This is not exported and is used as an implementation detail in
-- 'sqlWhereAll'.
data SqlAll = SqlAll
  { SqlAll -> [SqlCondition]
sqlAllWhere :: [SqlCondition]
  }

instance Show SqlSelect where
  show :: SqlSelect -> String
show = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance Show SqlInsert where
  show :: SqlInsert -> String
show = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance Show SqlInsertSelect where
  show :: SqlInsertSelect -> String
show = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance Show SqlUpdate where
  show :: SqlUpdate -> String
show = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance Show SqlDelete where
  show :: SqlDelete -> String
show = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance Show SqlAll where
  show :: SqlAll -> String
show = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

emitClause :: Sqlable sql => SQL -> sql -> SQL
emitClause :: forall sql. Sqlable sql => SQL -> sql -> SQL
emitClause SQL
name sql
s = case forall a. Sqlable a => a -> SQL
toSQLCommand sql
s of
  SQL
sql
    | SQL -> Bool
isSqlEmpty SQL
sql -> SQL
""
    | Bool
otherwise   -> SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
sql

emitClausesSep :: SQL -> SQL -> [SQL] -> SQL
emitClausesSep :: SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
_name SQL
_sep [] = forall a. Monoid a => a
mempty
emitClausesSep SQL
name SQL
sep [SQL]
sqls = SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall m. (IsString m, Monoid m) => m -> [m] -> m
smintercalate SQL
sep (forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. SQL -> Bool
isSqlEmpty) forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map SQL -> SQL
parenthesize [SQL]
sqls)

emitClausesSepComma :: SQL -> [SQL] -> SQL
emitClausesSepComma :: SQL -> [SQL] -> SQL
emitClausesSepComma SQL
_name [] = forall a. Monoid a => a
mempty
emitClausesSepComma SQL
name [SQL]
sqls = SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> [SQL] -> SQL
sqlConcatComma (forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. SQL -> Bool
isSqlEmpty) [SQL]
sqls)

instance IsSQL SqlSelect where
  withSQL :: forall r.
SqlSelect
-> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL = forall sql r.
IsSQL sql =>
sql -> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance IsSQL SqlInsert where
  withSQL :: forall r.
SqlInsert
-> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL = forall sql r.
IsSQL sql =>
sql -> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance IsSQL SqlInsertSelect where
  withSQL :: forall r.
SqlInsertSelect
-> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL = forall sql r.
IsSQL sql =>
sql -> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance IsSQL SqlUpdate where
  withSQL :: forall r.
SqlUpdate
-> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL = forall sql r.
IsSQL sql =>
sql -> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance IsSQL SqlDelete where
  withSQL :: forall r.
SqlDelete
-> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL = forall sql r.
IsSQL sql =>
sql -> ParamAllocator -> (Ptr PGparam -> CString -> IO r) -> IO r
withSQL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand

instance Sqlable SqlSelect where
  toSQLCommand :: SqlSelect -> SQL
toSQLCommand SqlSelect
cmd = forall m. (IsString m, Monoid m) => [m] -> m
smconcat
    [ SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"WITH" forall a b. (a -> b) -> a -> b
$
      forall a b. (a -> b) -> [a] -> [b]
map (\(SQL
name,SQL
command,Materialized
mat) -> SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"AS" forall m. (IsString m, Monoid m) => m -> m -> m
<+> Materialized -> SQL
materializedClause Materialized
mat forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize SQL
command) (SqlSelect -> [(SQL, SQL, Materialized)]
sqlSelectWith SqlSelect
cmd)
    , if Bool
hasUnion Bool -> Bool -> Bool
|| Bool
hasUnionAll
      then SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
"" SQL
unionKeyword (SQL
mainSelectClause forall a. a -> [a] -> [a]
: [SQL]
unionCmd)
      else SQL
mainSelectClause
    , SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"GROUP BY" (SqlSelect -> [SQL]
sqlSelectGroupBy SqlSelect
cmd)
    , SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
"HAVING" SQL
"AND" (SqlSelect -> [SQL]
sqlSelectHaving SqlSelect
cmd)
    , SQL
orderByClause
    , if SqlSelect -> Integer
sqlSelectOffset SqlSelect
cmd forall a. Ord a => a -> a -> Bool
> Integer
0
      then forall sql. (IsSQL sql, IsString sql) => String -> sql
unsafeSQL (String
"OFFSET " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (SqlSelect -> Integer
sqlSelectOffset SqlSelect
cmd))
      else SQL
""
    , if SqlSelect -> Integer
sqlSelectLimit SqlSelect
cmd forall a. Ord a => a -> a -> Bool
>= Integer
0
      then SQL
limitClause
      else SQL
""
    ]
    where
      mainSelectClause :: SQL
mainSelectClause = forall m. (IsString m, Monoid m) => [m] -> m
smconcat
        [ SQL
"SELECT" forall m. (IsString m, Monoid m) => m -> m -> m
<+> (if SqlSelect -> Bool
sqlSelectDistinct SqlSelect
cmd then SQL
"DISTINCT" else forall a. Monoid a => a
mempty)
        , [SQL] -> SQL
sqlConcatComma (SqlSelect -> [SQL]
sqlSelectResult SqlSelect
cmd)
        , forall sql. Sqlable sql => SQL -> sql -> SQL
emitClause SQL
"FROM" (SqlSelect -> SQL
sqlSelectFrom SqlSelect
cmd)
        , SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
"WHERE" SQL
"AND" (forall a b. (a -> b) -> [a] -> [b]
map forall a. Sqlable a => a -> SQL
toSQLCommand forall a b. (a -> b) -> a -> b
$ SqlSelect -> [SqlCondition]
sqlSelectWhere SqlSelect
cmd)
        -- If there's a union, the result is sorted and has a limit, applying
        -- the order and limit to the main subquery won't reduce the overall
        -- query result, but might reduce its processing time.
        , if Bool
hasUnion Bool -> Bool -> Bool
&& Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ SqlSelect -> [SQL]
sqlSelectOrderBy SqlSelect
cmd) Bool -> Bool -> Bool
&& SqlSelect -> Integer
sqlSelectLimit SqlSelect
cmd forall a. Ord a => a -> a -> Bool
>= Integer
0
          then forall m. (IsString m, Monoid m) => [m] -> m
smconcat [SQL
orderByClause, SQL
limitClause]
          else SQL
""
        ]

      hasUnion :: Bool
hasUnion      = Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ SqlSelect -> [SQL]
sqlSelectUnion SqlSelect
cmd
      hasUnionAll :: Bool
hasUnionAll   = Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ SqlSelect -> [SQL]
sqlSelectUnionAll SqlSelect
cmd
      unionKeyword :: SQL
unionKeyword = case (Bool
hasUnion, Bool
hasUnionAll) of
                        (Bool
False, Bool
True) -> SQL
"UNION ALL"
                        (Bool
True, Bool
False) -> SQL
"UNION"
                        -- False, False is caught by the (hasUnion || hasUnionAll) above.
                        -- Hence, the catch-all is implicitly for (True, True).
                        (Bool, Bool)
_ -> forall a. HasCallStack => String -> a
error String
"Having both `sqlSelectUnion` and `sqlSelectUnionAll` is not supported at the moment."
      unionCmd :: [SQL]
unionCmd = case (Bool
hasUnion, Bool
hasUnionAll) of
                        (Bool
False, Bool
True) -> SqlSelect -> [SQL]
sqlSelectUnionAll SqlSelect
cmd
                        (Bool
True, Bool
False) -> SqlSelect -> [SQL]
sqlSelectUnion SqlSelect
cmd
                        -- False, False is caught by the (hasUnion || hasUnionAll) above.
                        -- Hence, the catch-all is implicitly for (True, True).
                        (Bool, Bool)
_ -> forall a. HasCallStack => String -> a
error String
"Having both `sqlSelectUnion` and `sqlSelectUnionAll` is not supported at the moment."
      orderByClause :: SQL
orderByClause = SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"ORDER BY" forall a b. (a -> b) -> a -> b
$ SqlSelect -> [SQL]
sqlSelectOrderBy SqlSelect
cmd
      limitClause :: SQL
limitClause   = forall sql. (IsSQL sql, IsString sql) => String -> sql
unsafeSQL forall a b. (a -> b) -> a -> b
$ String
"LIMIT" forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall a. Show a => a -> String
show (SqlSelect -> Integer
sqlSelectLimit SqlSelect
cmd)

emitClauseOnConflictForInsert :: Maybe (SQL, Maybe SQL) -> SQL
emitClauseOnConflictForInsert :: Maybe (SQL, Maybe SQL) -> SQL
emitClauseOnConflictForInsert = \case
       Maybe (SQL, Maybe SQL)
Nothing                   -> SQL
""
       Just (SQL
condition, Maybe SQL
maction) -> forall sql. Sqlable sql => SQL -> sql -> SQL
emitClause SQL
"ON CONFLICT" forall a b. (a -> b) -> a -> b
$
         SQL
condition forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"DO" forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall a. a -> Maybe a -> a
fromMaybe SQL
"NOTHING" Maybe SQL
maction

instance Sqlable SqlInsert where
  toSQLCommand :: SqlInsert -> SQL
toSQLCommand SqlInsert
cmd =
    SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"WITH" (forall a b. (a -> b) -> [a] -> [b]
map (\(SQL
name,SQL
command,Materialized
mat) -> SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"AS" forall m. (IsString m, Monoid m) => m -> m -> m
<+> Materialized -> SQL
materializedClause Materialized
mat forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize SQL
command) (SqlInsert -> [(SQL, SQL, Materialized)]
sqlInsertWith SqlInsert
cmd)) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL
"INSERT INTO" forall m. (IsString m, Monoid m) => m -> m -> m
<+> SqlInsert -> SQL
sqlInsertWhat SqlInsert
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL -> SQL
parenthesize ([SQL] -> SQL
sqlConcatComma (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst (SqlInsert -> [(SQL, Multiplicity SQL)]
sqlInsertSet SqlInsert
cmd))) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
"VALUES" SQL
"," (forall a b. (a -> b) -> [a] -> [b]
map [SQL] -> SQL
sqlConcatComma (forall a. [[a]] -> [[a]]
transpose (forall a b. (a -> b) -> [a] -> [b]
map (Multiplicity SQL -> [SQL]
makeLongEnough forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) (SqlInsert -> [(SQL, Multiplicity SQL)]
sqlInsertSet SqlInsert
cmd)))) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    Maybe (SQL, Maybe SQL) -> SQL
emitClauseOnConflictForInsert (SqlInsert -> Maybe (SQL, Maybe SQL)
sqlInsertOnConflict SqlInsert
cmd) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"RETURNING" (SqlInsert -> [SQL]
sqlInsertResult SqlInsert
cmd)
   where
     -- this is the longest list of values
     longest :: Int
longest = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum (Int
1 forall a. a -> [a] -> [a]
: (forall a b. (a -> b) -> [a] -> [b]
map (forall {a}. Multiplicity a -> Int
lengthOfEither forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) (SqlInsert -> [(SQL, Multiplicity SQL)]
sqlInsertSet SqlInsert
cmd)))
     lengthOfEither :: Multiplicity a -> Int
lengthOfEither (Single a
_) = Int
1
     lengthOfEither (Many [a]
x)   = forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
x
     makeLongEnough :: Multiplicity SQL -> [SQL]
makeLongEnough (Single SQL
x) = forall a. Int -> [a] -> [a]
take Int
longest (forall a. a -> [a]
repeat SQL
x)
     makeLongEnough (Many [SQL]
x)   = forall a. Int -> [a] -> [a]
take Int
longest ([SQL]
x forall a. [a] -> [a] -> [a]
++ forall a. a -> [a]
repeat SQL
"DEFAULT")

instance Sqlable SqlInsertSelect where
  toSQLCommand :: SqlInsertSelect -> SQL
toSQLCommand SqlInsertSelect
cmd = forall m. (IsString m, Monoid m) => [m] -> m
smconcat
    -- WITH clause needs to be at the top level, so we emit it here and not
    -- include it in the SqlSelect below.
    [ SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"WITH" forall a b. (a -> b) -> a -> b
$
      forall a b. (a -> b) -> [a] -> [b]
map (\(SQL
name,SQL
command,Materialized
mat) -> SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"AS" forall m. (IsString m, Monoid m) => m -> m -> m
<+> Materialized -> SQL
materializedClause Materialized
mat forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize SQL
command) (SqlInsertSelect -> [(SQL, SQL, Materialized)]
sqlInsertSelectWith SqlInsertSelect
cmd)
    , SQL
"INSERT INTO" forall m. (IsString m, Monoid m) => m -> m -> m
<+> SqlInsertSelect -> SQL
sqlInsertSelectWhat SqlInsertSelect
cmd
    , SQL -> SQL
parenthesize forall b c a. (b -> c) -> (a -> b) -> a -> c
. [SQL] -> SQL
sqlConcatComma forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ SqlInsertSelect -> [(SQL, SQL)]
sqlInsertSelectSet SqlInsertSelect
cmd
    , SQL -> SQL
parenthesize forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand forall a b. (a -> b) -> a -> b
$ SqlSelect { sqlSelectFrom :: SQL
sqlSelectFrom    = SqlInsertSelect -> SQL
sqlInsertSelectFrom SqlInsertSelect
cmd
                                              , sqlSelectUnion :: [SQL]
sqlSelectUnion   = []
                                              , sqlSelectUnionAll :: [SQL]
sqlSelectUnionAll = []
                                              , sqlSelectDistinct :: Bool
sqlSelectDistinct = SqlInsertSelect -> Bool
sqlInsertSelectDistinct SqlInsertSelect
cmd
                                              , sqlSelectResult :: [SQL]
sqlSelectResult  = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall a b. (a -> b) -> a -> b
$ SqlInsertSelect -> [(SQL, SQL)]
sqlInsertSelectSet SqlInsertSelect
cmd
                                              , sqlSelectWhere :: [SqlCondition]
sqlSelectWhere   = SqlInsertSelect -> [SqlCondition]
sqlInsertSelectWhere SqlInsertSelect
cmd
                                              , sqlSelectOrderBy :: [SQL]
sqlSelectOrderBy = SqlInsertSelect -> [SQL]
sqlInsertSelectOrderBy SqlInsertSelect
cmd
                                              , sqlSelectGroupBy :: [SQL]
sqlSelectGroupBy = SqlInsertSelect -> [SQL]
sqlInsertSelectGroupBy SqlInsertSelect
cmd
                                              , sqlSelectHaving :: [SQL]
sqlSelectHaving  = SqlInsertSelect -> [SQL]
sqlInsertSelectHaving SqlInsertSelect
cmd
                                              , sqlSelectOffset :: Integer
sqlSelectOffset  = SqlInsertSelect -> Integer
sqlInsertSelectOffset SqlInsertSelect
cmd
                                              , sqlSelectLimit :: Integer
sqlSelectLimit   = SqlInsertSelect -> Integer
sqlInsertSelectLimit SqlInsertSelect
cmd
                                              , sqlSelectWith :: [(SQL, SQL, Materialized)]
sqlSelectWith    = []
                                              }
    , Maybe (SQL, Maybe SQL) -> SQL
emitClauseOnConflictForInsert (SqlInsertSelect -> Maybe (SQL, Maybe SQL)
sqlInsertSelectOnConflict SqlInsertSelect
cmd)
    , SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"RETURNING" forall a b. (a -> b) -> a -> b
$ SqlInsertSelect -> [SQL]
sqlInsertSelectResult SqlInsertSelect
cmd
    ]

-- This function has to be called as one of first things in your program
-- for the library to make sure that it is aware if the "WITH MATERIALIZED"
-- clause is supported by your PostgreSQL version.
checkAndRememberMaterializationSupport :: (MonadDB m, MonadIO m, MonadMask m) => m ()
checkAndRememberMaterializationSupport :: forall (m :: * -> *). (MonadDB m, MonadIO m, MonadMask m) => m ()
checkAndRememberMaterializationSupport = do
  Either DBException Int64
res :: Either DBException Int64 <- forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
try forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadDB m => m a -> m a
withNewConnection forall a b. (a -> b) -> a -> b
$ do
    forall (m :: * -> *). (MonadDB m, MonadThrow m) => SQL -> m ()
runSQL01_ forall a b. (a -> b) -> a -> b
$ SQL
"WITH t(n) AS MATERIALIZED (SELECT (1 :: bigint)) SELECT n FROM t LIMIT 1"
    forall (m :: * -> *) row t.
(MonadDB m, MonadThrow m, FromRow row) =>
(row -> t) -> m t
fetchOne forall a. Identity a -> a
runIdentity
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> a -> IO ()
writeIORef IORef Bool
withMaterializedSupported (forall a b. Either a b -> Bool
isRight Either DBException Int64
res)

withMaterializedSupported :: IORef Bool
{-# NOINLINE withMaterializedSupported #-}
withMaterializedSupported :: IORef Bool
withMaterializedSupported = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Bool
False

isWithMaterializedSupported :: Bool
isWithMaterializedSupported :: Bool
isWithMaterializedSupported = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> IO a
readIORef IORef Bool
withMaterializedSupported

materializedClause :: Materialized -> SQL
materializedClause :: Materialized -> SQL
materializedClause Materialized
Materialized = if Bool
isWithMaterializedSupported then SQL
"MATERIALIZED" else SQL
""
materializedClause Materialized
NonMaterialized = if Bool
isWithMaterializedSupported then SQL
"NOT MATERIALIZED" else SQL
""

instance Sqlable SqlUpdate where
  toSQLCommand :: SqlUpdate -> SQL
toSQLCommand SqlUpdate
cmd =
    SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"WITH" (forall a b. (a -> b) -> [a] -> [b]
map (\(SQL
name,SQL
command,Materialized
mat) -> SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"AS" forall m. (IsString m, Monoid m) => m -> m -> m
<+> Materialized -> SQL
materializedClause Materialized
mat forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize SQL
command) (SqlUpdate -> [(SQL, SQL, Materialized)]
sqlUpdateWith SqlUpdate
cmd)) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL
"UPDATE" forall m. (IsString m, Monoid m) => m -> m -> m
<+> SqlUpdate -> SQL
sqlUpdateWhat SqlUpdate
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"SET" forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    [SQL] -> SQL
sqlConcatComma (forall a b. (a -> b) -> [a] -> [b]
map (\(SQL
name, SQL
command) -> SQL
name forall a. Semigroup a => a -> a -> a
<> SQL
"=" forall a. Semigroup a => a -> a -> a
<> SQL
command) (SqlUpdate -> [(SQL, SQL)]
sqlUpdateSet SqlUpdate
cmd)) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    forall sql. Sqlable sql => SQL -> sql -> SQL
emitClause SQL
"FROM" (SqlUpdate -> SQL
sqlUpdateFrom SqlUpdate
cmd) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
"WHERE" SQL
"AND" (forall a b. (a -> b) -> [a] -> [b]
map forall a. Sqlable a => a -> SQL
toSQLCommand forall a b. (a -> b) -> a -> b
$ SqlUpdate -> [SqlCondition]
sqlUpdateWhere SqlUpdate
cmd) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"RETURNING" (SqlUpdate -> [SQL]
sqlUpdateResult SqlUpdate
cmd)

instance Sqlable SqlDelete where
  toSQLCommand :: SqlDelete -> SQL
toSQLCommand SqlDelete
cmd =
    SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"WITH" (forall a b. (a -> b) -> [a] -> [b]
map (\(SQL
name,SQL
command,Materialized
mat) -> SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"AS" forall m. (IsString m, Monoid m) => m -> m -> m
<+> Materialized -> SQL
materializedClause Materialized
mat forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize SQL
command) (SqlDelete -> [(SQL, SQL, Materialized)]
sqlDeleteWith SqlDelete
cmd)) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL
"DELETE FROM" forall m. (IsString m, Monoid m) => m -> m -> m
<+> SqlDelete -> SQL
sqlDeleteFrom SqlDelete
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    forall sql. Sqlable sql => SQL -> sql -> SQL
emitClause SQL
"USING" (SqlDelete -> SQL
sqlDeleteUsing SqlDelete
cmd) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
        SQL -> SQL -> [SQL] -> SQL
emitClausesSep SQL
"WHERE" SQL
"AND" (forall a b. (a -> b) -> [a] -> [b]
map forall a. Sqlable a => a -> SQL
toSQLCommand forall a b. (a -> b) -> a -> b
$ SqlDelete -> [SqlCondition]
sqlDeleteWhere SqlDelete
cmd) forall m. (IsString m, Monoid m) => m -> m -> m
<+>
    SQL -> [SQL] -> SQL
emitClausesSepComma SQL
"RETURNING" (SqlDelete -> [SQL]
sqlDeleteResult SqlDelete
cmd)

instance Sqlable SqlAll where
  toSQLCommand :: SqlAll -> SQL
toSQLCommand SqlAll
cmd | forall (t :: * -> *) a. Foldable t => t a -> Bool
null (SqlAll -> [SqlCondition]
sqlAllWhere SqlAll
cmd) = SQL
"TRUE"
  toSQLCommand SqlAll
cmd =
    SQL
"(" forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall m. (IsString m, Monoid m) => m -> [m] -> m
smintercalate SQL
"AND" (forall a b. (a -> b) -> [a] -> [b]
map (SQL -> SQL
parenthesize forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand) (SqlAll -> [SqlCondition]
sqlAllWhere SqlAll
cmd)) forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
")"

sqlSelect :: SQL -> State SqlSelect () -> SqlSelect
sqlSelect :: SQL -> State SqlSelect () -> SqlSelect
sqlSelect SQL
table State SqlSelect ()
refine =
  forall s a. State s a -> s -> s
execState State SqlSelect ()
refine (SQL
-> [SQL]
-> [SQL]
-> Bool
-> [SQL]
-> [SqlCondition]
-> [SQL]
-> [SQL]
-> [SQL]
-> Integer
-> Integer
-> [(SQL, SQL, Materialized)]
-> SqlSelect
SqlSelect SQL
table [] [] Bool
False [] [] [] [] [] Integer
0 (-Integer
1) [])

sqlSelect2 :: SQL -> State SqlSelect () -> SqlSelect
sqlSelect2 :: SQL -> State SqlSelect () -> SqlSelect
sqlSelect2 SQL
from State SqlSelect ()
refine =
  forall s a. State s a -> s -> s
execState State SqlSelect ()
refine (SQL
-> [SQL]
-> [SQL]
-> Bool
-> [SQL]
-> [SqlCondition]
-> [SQL]
-> [SQL]
-> [SQL]
-> Integer
-> Integer
-> [(SQL, SQL, Materialized)]
-> SqlSelect
SqlSelect SQL
from [] [] Bool
False [] [] [] [] [] Integer
0 (-Integer
1) [])

sqlInsert :: SQL -> State SqlInsert () -> SqlInsert
sqlInsert :: SQL -> State SqlInsert () -> SqlInsert
sqlInsert SQL
table State SqlInsert ()
refine =
  forall s a. State s a -> s -> s
execState State SqlInsert ()
refine (SQL
-> Maybe (SQL, Maybe SQL)
-> [(SQL, Multiplicity SQL)]
-> [SQL]
-> [(SQL, SQL, Materialized)]
-> SqlInsert
SqlInsert SQL
table forall a. Maybe a
Nothing forall a. Monoid a => a
mempty [] [])

sqlInsertSelect :: SQL -> SQL -> State SqlInsertSelect () -> SqlInsertSelect
sqlInsertSelect :: SQL -> SQL -> State SqlInsertSelect () -> SqlInsertSelect
sqlInsertSelect SQL
table SQL
from State SqlInsertSelect ()
refine =
  forall s a. State s a -> s -> s
execState State SqlInsertSelect ()
refine (SqlInsertSelect
                    { sqlInsertSelectWhat :: SQL
sqlInsertSelectWhat       = SQL
table
                    , sqlInsertSelectOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertSelectOnConflict = forall a. Maybe a
Nothing
                    , sqlInsertSelectDistinct :: Bool
sqlInsertSelectDistinct   = Bool
False
                    , sqlInsertSelectSet :: [(SQL, SQL)]
sqlInsertSelectSet        = []
                    , sqlInsertSelectResult :: [SQL]
sqlInsertSelectResult     = []
                    , sqlInsertSelectFrom :: SQL
sqlInsertSelectFrom       = SQL
from
                    , sqlInsertSelectWhere :: [SqlCondition]
sqlInsertSelectWhere      = []
                    , sqlInsertSelectOrderBy :: [SQL]
sqlInsertSelectOrderBy    = []
                    , sqlInsertSelectGroupBy :: [SQL]
sqlInsertSelectGroupBy    = []
                    , sqlInsertSelectHaving :: [SQL]
sqlInsertSelectHaving     = []
                    , sqlInsertSelectOffset :: Integer
sqlInsertSelectOffset     = Integer
0
                    , sqlInsertSelectLimit :: Integer
sqlInsertSelectLimit      = -Integer
1
                    , sqlInsertSelectWith :: [(SQL, SQL, Materialized)]
sqlInsertSelectWith       = []
                    })

sqlUpdate :: SQL -> State SqlUpdate () -> SqlUpdate
sqlUpdate :: SQL -> State SqlUpdate () -> SqlUpdate
sqlUpdate SQL
table State SqlUpdate ()
refine =
  forall s a. State s a -> s -> s
execState State SqlUpdate ()
refine (SQL
-> SQL
-> [SqlCondition]
-> [(SQL, SQL)]
-> [SQL]
-> [(SQL, SQL, Materialized)]
-> SqlUpdate
SqlUpdate SQL
table forall a. Monoid a => a
mempty [] [] [] [])

sqlDelete :: SQL -> State SqlDelete () -> SqlDelete
sqlDelete :: SQL -> State SqlDelete () -> SqlDelete
sqlDelete SQL
table State SqlDelete ()
refine =
  forall s a. State s a -> s -> s
execState State SqlDelete ()
refine (SqlDelete  { sqlDeleteFrom :: SQL
sqlDeleteFrom   = SQL
table
                               , sqlDeleteUsing :: SQL
sqlDeleteUsing  = forall a. Monoid a => a
mempty
                               , sqlDeleteWhere :: [SqlCondition]
sqlDeleteWhere  = []
                               , sqlDeleteResult :: [SQL]
sqlDeleteResult = []
                               , sqlDeleteWith :: [(SQL, SQL, Materialized)]
sqlDeleteWith   = []
                               })


data Materialized = Materialized | NonMaterialized

class SqlWith a where
  sqlWith1 :: a -> SQL -> SQL -> Materialized -> a


instance SqlWith SqlSelect where
  sqlWith1 :: SqlSelect -> SQL -> SQL -> Materialized -> SqlSelect
sqlWith1 SqlSelect
cmd SQL
name SQL
sql Materialized
mat = SqlSelect
cmd { sqlSelectWith :: [(SQL, SQL, Materialized)]
sqlSelectWith = SqlSelect -> [(SQL, SQL, Materialized)]
sqlSelectWith SqlSelect
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name,SQL
sql, Materialized
mat)] }

instance SqlWith SqlInsertSelect where
  sqlWith1 :: SqlInsertSelect -> SQL -> SQL -> Materialized -> SqlInsertSelect
sqlWith1 SqlInsertSelect
cmd SQL
name SQL
sql Materialized
mat = SqlInsertSelect
cmd { sqlInsertSelectWith :: [(SQL, SQL, Materialized)]
sqlInsertSelectWith = SqlInsertSelect -> [(SQL, SQL, Materialized)]
sqlInsertSelectWith SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name,SQL
sql,Materialized
mat)] }

instance SqlWith SqlUpdate where
  sqlWith1 :: SqlUpdate -> SQL -> SQL -> Materialized -> SqlUpdate
sqlWith1 SqlUpdate
cmd SQL
name SQL
sql Materialized
mat = SqlUpdate
cmd { sqlUpdateWith :: [(SQL, SQL, Materialized)]
sqlUpdateWith = SqlUpdate -> [(SQL, SQL, Materialized)]
sqlUpdateWith SqlUpdate
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name,SQL
sql,Materialized
mat)] }

instance SqlWith SqlDelete where
  sqlWith1 :: SqlDelete -> SQL -> SQL -> Materialized -> SqlDelete
sqlWith1 SqlDelete
cmd SQL
name SQL
sql Materialized
mat = SqlDelete
cmd { sqlDeleteWith :: [(SQL, SQL, Materialized)]
sqlDeleteWith = SqlDelete -> [(SQL, SQL, Materialized)]
sqlDeleteWith SqlDelete
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name,SQL
sql,Materialized
mat)] }

sqlWith :: (MonadState v m, SqlWith v, Sqlable s) => SQL -> s -> m ()
sqlWith :: forall v (m :: * -> *) s.
(MonadState v m, SqlWith v, Sqlable s) =>
SQL -> s -> m ()
sqlWith SQL
name s
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlWith a => a -> SQL -> SQL -> Materialized -> a
sqlWith1 v
cmd SQL
name (forall a. Sqlable a => a -> SQL
toSQLCommand s
sql) Materialized
NonMaterialized)

sqlWithMaterialized :: (MonadState v m, SqlWith v, Sqlable s) => SQL -> s -> m ()
sqlWithMaterialized :: forall v (m :: * -> *) s.
(MonadState v m, SqlWith v, Sqlable s) =>
SQL -> s -> m ()
sqlWithMaterialized SQL
name s
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlWith a => a -> SQL -> SQL -> Materialized -> a
sqlWith1 v
cmd SQL
name (forall a. Sqlable a => a -> SQL
toSQLCommand s
sql) Materialized
Materialized)

-- | Note: WHERE clause of the main SELECT is treated specially, i.e. it only
-- applies to the main SELECT, not the whole union.
sqlUnion :: (MonadState SqlSelect m, Sqlable sql) => [sql] -> m ()
sqlUnion :: forall (m :: * -> *) sql.
(MonadState SqlSelect m, Sqlable sql) =>
[sql] -> m ()
sqlUnion [sql]
sqls = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\SqlSelect
cmd -> SqlSelect
cmd { sqlSelectUnion :: [SQL]
sqlSelectUnion = forall a b. (a -> b) -> [a] -> [b]
map forall a. Sqlable a => a -> SQL
toSQLCommand [sql]
sqls })

-- | Note: WHERE clause of the main SELECT is treated specially, i.e. it only
-- applies to the main SELECT, not the whole union.
--
-- @since 1.16.4.0
sqlUnionAll :: (MonadState SqlSelect m, Sqlable sql) => [sql] -> m ()
sqlUnionAll :: forall (m :: * -> *) sql.
(MonadState SqlSelect m, Sqlable sql) =>
[sql] -> m ()
sqlUnionAll [sql]
sqls = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\SqlSelect
cmd -> SqlSelect
cmd { sqlSelectUnionAll :: [SQL]
sqlSelectUnionAll = forall a b. (a -> b) -> [a] -> [b]
map forall a. Sqlable a => a -> SQL
toSQLCommand [sql]
sqls })

class SqlWhere a where
  sqlWhere1 :: a -> SqlCondition -> a
  sqlGetWhereConditions :: a -> [SqlCondition]

instance SqlWhere SqlSelect where
  sqlWhere1 :: SqlSelect -> SqlCondition -> SqlSelect
sqlWhere1 SqlSelect
cmd SqlCondition
cond = SqlSelect
cmd { sqlSelectWhere :: [SqlCondition]
sqlSelectWhere = SqlSelect -> [SqlCondition]
sqlSelectWhere SqlSelect
cmd forall a. [a] -> [a] -> [a]
++ [SqlCondition
cond] }
  sqlGetWhereConditions :: SqlSelect -> [SqlCondition]
sqlGetWhereConditions = SqlSelect -> [SqlCondition]
sqlSelectWhere

instance SqlWhere SqlInsertSelect where
  sqlWhere1 :: SqlInsertSelect -> SqlCondition -> SqlInsertSelect
sqlWhere1 SqlInsertSelect
cmd SqlCondition
cond = SqlInsertSelect
cmd { sqlInsertSelectWhere :: [SqlCondition]
sqlInsertSelectWhere = SqlInsertSelect -> [SqlCondition]
sqlInsertSelectWhere SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [SqlCondition
cond] }
  sqlGetWhereConditions :: SqlInsertSelect -> [SqlCondition]
sqlGetWhereConditions = SqlInsertSelect -> [SqlCondition]
sqlInsertSelectWhere

instance SqlWhere SqlUpdate where
  sqlWhere1 :: SqlUpdate -> SqlCondition -> SqlUpdate
sqlWhere1 SqlUpdate
cmd SqlCondition
cond = SqlUpdate
cmd { sqlUpdateWhere :: [SqlCondition]
sqlUpdateWhere = SqlUpdate -> [SqlCondition]
sqlUpdateWhere SqlUpdate
cmd forall a. [a] -> [a] -> [a]
++ [SqlCondition
cond] }
  sqlGetWhereConditions :: SqlUpdate -> [SqlCondition]
sqlGetWhereConditions = SqlUpdate -> [SqlCondition]
sqlUpdateWhere

instance SqlWhere SqlDelete where
  sqlWhere1 :: SqlDelete -> SqlCondition -> SqlDelete
sqlWhere1 SqlDelete
cmd SqlCondition
cond = SqlDelete
cmd { sqlDeleteWhere :: [SqlCondition]
sqlDeleteWhere = SqlDelete -> [SqlCondition]
sqlDeleteWhere SqlDelete
cmd forall a. [a] -> [a] -> [a]
++ [SqlCondition
cond] }
  sqlGetWhereConditions :: SqlDelete -> [SqlCondition]
sqlGetWhereConditions = SqlDelete -> [SqlCondition]
sqlDeleteWhere

instance SqlWhere SqlAll where
  sqlWhere1 :: SqlAll -> SqlCondition -> SqlAll
sqlWhere1 SqlAll
cmd SqlCondition
cond = SqlAll
cmd { sqlAllWhere :: [SqlCondition]
sqlAllWhere = SqlAll -> [SqlCondition]
sqlAllWhere SqlAll
cmd forall a. [a] -> [a] -> [a]
++ [SqlCondition
cond] }
  sqlGetWhereConditions :: SqlAll -> [SqlCondition]
sqlGetWhereConditions = SqlAll -> [SqlCondition]
sqlAllWhere

-- | The @WHERE@ part of an SQL query. See above for a usage
-- example. See also 'SqlCondition'.
sqlWhere :: (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere :: forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlWhere a => a -> SqlCondition -> a
sqlWhere1 v
cmd (SQL -> SqlCondition
SqlPlainCondition SQL
sql))

sqlWhereEq :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> a -> m ()
sqlWhereEq :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> a -> m ()
sqlWhereEq SQL
name a
value = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"=" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> a
value

sqlWhereEqSql :: (MonadState v m, SqlWhere v, Sqlable sql) => SQL -> sql -> m ()
sqlWhereEqSql :: forall v (m :: * -> *) sql.
(MonadState v m, SqlWhere v, Sqlable sql) =>
SQL -> sql -> m ()
sqlWhereEqSql SQL
name1 sql
name2 = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name1 forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"=" forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall a. Sqlable a => a -> SQL
toSQLCommand sql
name2

sqlWhereNotEq :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> a -> m ()
sqlWhereNotEq :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> a -> m ()
sqlWhereNotEq SQL
name a
value = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"<>" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> a
value

sqlWhereLike :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> a -> m ()
sqlWhereLike :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> a -> m ()
sqlWhereLike SQL
name a
value = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"LIKE" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> a
value

sqlWhereILike :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> a -> m ()
sqlWhereILike :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> a -> m ()
sqlWhereILike SQL
name a
value = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere  forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"ILIKE" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> a
value

-- | Similar to 'sqlWhereIn', but uses @ANY@ instead of @SELECT UNNEST@.
sqlWhereEqualsAny :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> [a] -> m ()
sqlWhereEqualsAny :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> [a] -> m ()
sqlWhereEqualsAny SQL
name [a]
values = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"= ANY(" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> forall a. [a] -> Array1 a
Array1 [a]
values forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
")"

sqlWhereIn :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> [a] -> m ()
sqlWhereIn :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> [a] -> m ()
sqlWhereIn SQL
name [a]
values = do
  -- Unpack the array to give query optimizer more options.
  forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"IN (SELECT UNNEST(" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> forall a. [a] -> Array1 a
Array1 [a]
values forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"))"

sqlWhereInSql :: (MonadState v m, Sqlable a, SqlWhere v) => SQL -> a -> m ()
sqlWhereInSql :: forall v (m :: * -> *) a.
(MonadState v m, Sqlable a, SqlWhere v) =>
SQL -> a -> m ()
sqlWhereInSql SQL
name a
sql = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"IN" forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize (forall a. Sqlable a => a -> SQL
toSQLCommand a
sql)

sqlWhereNotIn :: (MonadState v m, SqlWhere v, Show a, ToSQL a) => SQL -> [a] -> m ()
sqlWhereNotIn :: forall v (m :: * -> *) a.
(MonadState v m, SqlWhere v, Show a, ToSQL a) =>
SQL -> [a] -> m ()
sqlWhereNotIn SQL
name [a]
values = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"NOT IN (SELECT UNNEST(" forall t. (Show t, ToSQL t) => SQL -> t -> SQL
<?> forall a. [a] -> Array1 a
Array1 [a]
values forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"))"

sqlWhereNotInSql :: (MonadState v m, Sqlable a, SqlWhere v) => SQL -> a -> m ()
sqlWhereNotInSql :: forall v (m :: * -> *) a.
(MonadState v m, Sqlable a, SqlWhere v) =>
SQL -> a -> m ()
sqlWhereNotInSql SQL
name a
sql = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"NOT IN" forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL -> SQL
parenthesize (forall a. Sqlable a => a -> SQL
toSQLCommand a
sql)

sqlWhereExists :: (MonadState v m, SqlWhere v) => SqlSelect -> m ()
sqlWhereExists :: forall v (m :: * -> *).
(MonadState v m, SqlWhere v) =>
SqlSelect -> m ()
sqlWhereExists SqlSelect
sql = do
  forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlWhere a => a -> SqlCondition -> a
sqlWhere1 v
cmd (SqlSelect -> SqlCondition
SqlExistsCondition SqlSelect
sql))

sqlWhereNotExists :: (MonadState v m, SqlWhere v) => SqlSelect -> m ()
sqlWhereNotExists :: forall v (m :: * -> *).
(MonadState v m, SqlWhere v) =>
SqlSelect -> m ()
sqlWhereNotExists SqlSelect
sqlSelectD = do
  forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere (SQL
"NOT EXISTS (" forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall a. Sqlable a => a -> SQL
toSQLCommand (SqlSelect
sqlSelectD { sqlSelectResult :: [SQL]
sqlSelectResult = [SQL
"TRUE"] }) forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
")")

sqlWhereIsNULL :: (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhereIsNULL :: forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhereIsNULL SQL
col = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
col forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"IS NULL"

sqlWhereIsNotNULL :: (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhereIsNotNULL :: forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhereIsNotNULL SQL
col = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall a b. (a -> b) -> a -> b
$ SQL
col forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"IS NOT NULL"

-- | Add a condition in the WHERE statement that holds if any of the given
-- condition holds.
sqlWhereAny :: (MonadState v m, SqlWhere v) => [State SqlAll ()] -> m ()
sqlWhereAny :: forall v (m :: * -> *).
(MonadState v m, SqlWhere v) =>
[State SqlAll ()] -> m ()
sqlWhereAny = forall v (m :: * -> *). (MonadState v m, SqlWhere v) => SQL -> m ()
sqlWhere forall b c a. (b -> c) -> (a -> b) -> a -> c
. [State SqlAll ()] -> SQL
sqlWhereAnyImpl

sqlWhereAnyImpl :: [State SqlAll ()] -> SQL
sqlWhereAnyImpl :: [State SqlAll ()] -> SQL
sqlWhereAnyImpl [] = SQL
"FALSE"
sqlWhereAnyImpl [State SqlAll ()]
l =
  SQL
"(" forall m. (IsString m, Monoid m) => m -> m -> m
<+> forall m. (IsString m, Monoid m) => m -> [m] -> m
smintercalate SQL
"OR" (forall a b. (a -> b) -> [a] -> [b]
map (SQL -> SQL
parenthesize forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Sqlable a => a -> SQL
toSQLCommand
                                   forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall s a. State s a -> s -> s
execState ([SqlCondition] -> SqlAll
SqlAll [])) [State SqlAll ()]
l) forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
")"

class SqlFrom a where
  sqlFrom1 :: a -> SQL -> a

instance SqlFrom SqlSelect where
  sqlFrom1 :: SqlSelect -> SQL -> SqlSelect
sqlFrom1 SqlSelect
cmd SQL
sql = SqlSelect
cmd { sqlSelectFrom :: SQL
sqlSelectFrom = SqlSelect -> SQL
sqlSelectFrom SqlSelect
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
sql }

instance SqlFrom SqlInsertSelect where
  sqlFrom1 :: SqlInsertSelect -> SQL -> SqlInsertSelect
sqlFrom1 SqlInsertSelect
cmd SQL
sql = SqlInsertSelect
cmd { sqlInsertSelectFrom :: SQL
sqlInsertSelectFrom = SqlInsertSelect -> SQL
sqlInsertSelectFrom SqlInsertSelect
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
sql }

instance SqlFrom SqlUpdate where
  sqlFrom1 :: SqlUpdate -> SQL -> SqlUpdate
sqlFrom1 SqlUpdate
cmd SQL
sql = SqlUpdate
cmd { sqlUpdateFrom :: SQL
sqlUpdateFrom = SqlUpdate -> SQL
sqlUpdateFrom SqlUpdate
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
sql }

instance SqlFrom SqlDelete where
  sqlFrom1 :: SqlDelete -> SQL -> SqlDelete
sqlFrom1 SqlDelete
cmd SQL
sql = SqlDelete
cmd { sqlDeleteUsing :: SQL
sqlDeleteUsing = SqlDelete -> SQL
sqlDeleteUsing SqlDelete
cmd forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
sql }

sqlFrom :: (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom :: forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlFrom a => a -> SQL -> a
sqlFrom1 v
cmd SQL
sql)

sqlJoin :: (MonadState v m, SqlFrom v) => SQL -> m ()
sqlJoin :: forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlJoin SQL
table = forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom (SQL
", " forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
table)

sqlJoinOn :: (MonadState v m, SqlFrom v) => SQL -> SQL -> m ()
sqlJoinOn :: forall v (m :: * -> *).
(MonadState v m, SqlFrom v) =>
SQL -> SQL -> m ()
sqlJoinOn SQL
table SQL
condition = forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom (SQL
" JOIN " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                     SQL
table forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                     SQL
" ON " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                     SQL
condition)

sqlLeftJoinOn :: (MonadState v m, SqlFrom v) => SQL -> SQL -> m ()
sqlLeftJoinOn :: forall v (m :: * -> *).
(MonadState v m, SqlFrom v) =>
SQL -> SQL -> m ()
sqlLeftJoinOn SQL
table SQL
condition = forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom (SQL
" LEFT JOIN " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                         SQL
table forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                         SQL
" ON " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                         SQL
condition)

sqlRightJoinOn :: (MonadState v m, SqlFrom v) => SQL -> SQL -> m ()
sqlRightJoinOn :: forall v (m :: * -> *).
(MonadState v m, SqlFrom v) =>
SQL -> SQL -> m ()
sqlRightJoinOn SQL
table SQL
condition = forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom (SQL
" RIGHT JOIN " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                          SQL
table forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                          SQL
" ON " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                          SQL
condition)

sqlFullJoinOn :: (MonadState v m, SqlFrom v) => SQL -> SQL -> m ()
sqlFullJoinOn :: forall v (m :: * -> *).
(MonadState v m, SqlFrom v) =>
SQL -> SQL -> m ()
sqlFullJoinOn SQL
table SQL
condition = forall v (m :: * -> *). (MonadState v m, SqlFrom v) => SQL -> m ()
sqlFrom (SQL
" FULL JOIN " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                         SQL
table forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                         SQL
" ON " forall m. (IsString m, Monoid m) => m -> m -> m
<+>
                                         SQL
condition)

class SqlSet a where
  sqlSet1 :: a -> SQL -> SQL -> a

instance SqlSet SqlUpdate where
  sqlSet1 :: SqlUpdate -> SQL -> SQL -> SqlUpdate
sqlSet1 SqlUpdate
cmd SQL
name SQL
v = SqlUpdate
cmd { sqlUpdateSet :: [(SQL, SQL)]
sqlUpdateSet = SqlUpdate -> [(SQL, SQL)]
sqlUpdateSet SqlUpdate
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name, SQL
v)] }

instance SqlSet SqlInsert where
  sqlSet1 :: SqlInsert -> SQL -> SQL -> SqlInsert
sqlSet1 SqlInsert
cmd SQL
name SQL
v = SqlInsert
cmd { sqlInsertSet :: [(SQL, Multiplicity SQL)]
sqlInsertSet = SqlInsert -> [(SQL, Multiplicity SQL)]
sqlInsertSet SqlInsert
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name, forall a. a -> Multiplicity a
Single SQL
v)] }

instance SqlSet SqlInsertSelect where
  sqlSet1 :: SqlInsertSelect -> SQL -> SQL -> SqlInsertSelect
sqlSet1 SqlInsertSelect
cmd SQL
name SQL
v = SqlInsertSelect
cmd { sqlInsertSelectSet :: [(SQL, SQL)]
sqlInsertSelectSet = SqlInsertSelect -> [(SQL, SQL)]
sqlInsertSelectSet SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name, SQL
v)] }

sqlSetCmd :: (MonadState v m, SqlSet v) => SQL -> SQL -> m ()
sqlSetCmd :: forall v (m :: * -> *).
(MonadState v m, SqlSet v) =>
SQL -> SQL -> m ()
sqlSetCmd SQL
name SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlSet a => a -> SQL -> SQL -> a
sqlSet1 v
cmd SQL
name SQL
sql)

sqlSetCmdList :: (MonadState SqlInsert m) => SQL -> [SQL] -> m ()
sqlSetCmdList :: forall (m :: * -> *).
MonadState SqlInsert m =>
SQL -> [SQL] -> m ()
sqlSetCmdList SQL
name [SQL]
as = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\SqlInsert
cmd -> SqlInsert
cmd { sqlInsertSet :: [(SQL, Multiplicity SQL)]
sqlInsertSet = SqlInsert -> [(SQL, Multiplicity SQL)]
sqlInsertSet SqlInsert
cmd forall a. [a] -> [a] -> [a]
++ [(SQL
name, forall a. [a] -> Multiplicity a
Many [SQL]
as)] })

sqlSet :: (MonadState v m, SqlSet v, Show a, ToSQL a) => SQL -> a -> m ()
sqlSet :: forall v (m :: * -> *) a.
(MonadState v m, SqlSet v, Show a, ToSQL a) =>
SQL -> a -> m ()
sqlSet SQL
name a
a = forall v (m :: * -> *).
(MonadState v m, SqlSet v) =>
SQL -> SQL -> m ()
sqlSetCmd SQL
name (forall t. (Show t, ToSQL t) => t -> SQL
sqlParam a
a)

sqlSetInc :: (MonadState v m, SqlSet v) => SQL -> m ()
sqlSetInc :: forall v (m :: * -> *). (MonadState v m, SqlSet v) => SQL -> m ()
sqlSetInc SQL
name = forall v (m :: * -> *).
(MonadState v m, SqlSet v) =>
SQL -> SQL -> m ()
sqlSetCmd SQL
name forall a b. (a -> b) -> a -> b
$ SQL
name forall m. (IsString m, Monoid m) => m -> m -> m
<+> SQL
"+ 1"

sqlSetList :: (MonadState SqlInsert m, Show a, ToSQL a) => SQL -> [a] -> m ()
sqlSetList :: forall (m :: * -> *) a.
(MonadState SqlInsert m, Show a, ToSQL a) =>
SQL -> [a] -> m ()
sqlSetList SQL
name [a]
as = forall (m :: * -> *).
MonadState SqlInsert m =>
SQL -> [SQL] -> m ()
sqlSetCmdList SQL
name (forall a b. (a -> b) -> [a] -> [b]
map forall t. (Show t, ToSQL t) => t -> SQL
sqlParam [a]
as)

sqlSetListWithDefaults :: (MonadState SqlInsert m, Show a, ToSQL a) => SQL -> [Maybe a] -> m ()
sqlSetListWithDefaults :: forall (m :: * -> *) a.
(MonadState SqlInsert m, Show a, ToSQL a) =>
SQL -> [Maybe a] -> m ()
sqlSetListWithDefaults SQL
name [Maybe a]
as = forall (m :: * -> *).
MonadState SqlInsert m =>
SQL -> [SQL] -> m ()
sqlSetCmdList SQL
name (forall a b. (a -> b) -> [a] -> [b]
map (forall b a. b -> (a -> b) -> Maybe a -> b
maybe SQL
"DEFAULT" forall t. (Show t, ToSQL t) => t -> SQL
sqlParam) [Maybe a]
as)

sqlCopyColumn :: (MonadState v m, SqlSet v) => SQL -> m ()
sqlCopyColumn :: forall v (m :: * -> *). (MonadState v m, SqlSet v) => SQL -> m ()
sqlCopyColumn SQL
column = forall v (m :: * -> *).
(MonadState v m, SqlSet v) =>
SQL -> SQL -> m ()
sqlSetCmd SQL
column SQL
column

class SqlOnConflict a where
  sqlOnConflictDoNothing1 :: a -> a
  sqlOnConflictOnColumnsDoNothing1 :: a -> [SQL] -> a
  sqlOnConflictOnColumns1 :: Sqlable sql => a -> [SQL] -> sql -> a

instance SqlOnConflict SqlInsert where
  sqlOnConflictDoNothing1 :: SqlInsert -> SqlInsert
sqlOnConflictDoNothing1 SqlInsert
cmd = 
    SqlInsert
cmd { sqlInsertOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertOnConflict = forall a. a -> Maybe a
Just (SQL
"", forall a. Maybe a
Nothing) }
  sqlOnConflictOnColumns1 :: forall sql. Sqlable sql => SqlInsert -> [SQL] -> sql -> SqlInsert
sqlOnConflictOnColumns1 SqlInsert
cmd [SQL]
columns sql
sql = 
    SqlInsert
cmd { sqlInsertOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertOnConflict = forall a. a -> Maybe a
Just (SQL -> SQL
parenthesize forall a b. (a -> b) -> a -> b
$ [SQL] -> SQL
sqlConcatComma [SQL]
columns, forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Sqlable a => a -> SQL
toSQLCommand sql
sql) }
  sqlOnConflictOnColumnsDoNothing1 :: SqlInsert -> [SQL] -> SqlInsert
sqlOnConflictOnColumnsDoNothing1 SqlInsert
cmd [SQL]
columns = 
    SqlInsert
cmd { sqlInsertOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertOnConflict = forall a. a -> Maybe a
Just (SQL -> SQL
parenthesize forall a b. (a -> b) -> a -> b
$ [SQL] -> SQL
sqlConcatComma [SQL]
columns, forall a. Maybe a
Nothing) }

instance SqlOnConflict SqlInsertSelect where
  sqlOnConflictDoNothing1 :: SqlInsertSelect -> SqlInsertSelect
sqlOnConflictDoNothing1 SqlInsertSelect
cmd = 
    SqlInsertSelect
cmd { sqlInsertSelectOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertSelectOnConflict = forall a. a -> Maybe a
Just (SQL
"", forall a. Maybe a
Nothing) }
  sqlOnConflictOnColumns1 :: forall sql.
Sqlable sql =>
SqlInsertSelect -> [SQL] -> sql -> SqlInsertSelect
sqlOnConflictOnColumns1 SqlInsertSelect
cmd [SQL]
columns sql
sql = 
    SqlInsertSelect
cmd { sqlInsertSelectOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertSelectOnConflict = forall a. a -> Maybe a
Just (SQL -> SQL
parenthesize forall a b. (a -> b) -> a -> b
$ [SQL] -> SQL
sqlConcatComma [SQL]
columns, forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Sqlable a => a -> SQL
toSQLCommand sql
sql) }
  sqlOnConflictOnColumnsDoNothing1 :: SqlInsertSelect -> [SQL] -> SqlInsertSelect
sqlOnConflictOnColumnsDoNothing1 SqlInsertSelect
cmd [SQL]
columns = 
    SqlInsertSelect
cmd { sqlInsertSelectOnConflict :: Maybe (SQL, Maybe SQL)
sqlInsertSelectOnConflict = forall a. a -> Maybe a
Just (SQL -> SQL
parenthesize forall a b. (a -> b) -> a -> b
$ [SQL] -> SQL
sqlConcatComma [SQL]
columns, forall a. Maybe a
Nothing) }

sqlOnConflictDoNothing :: (MonadState v m, SqlOnConflict v) => m ()
sqlOnConflictDoNothing :: forall v (m :: * -> *). (MonadState v m, SqlOnConflict v) => m ()
sqlOnConflictDoNothing = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify forall a. SqlOnConflict a => a -> a
sqlOnConflictDoNothing1

sqlOnConflictOnColumnsDoNothing :: (MonadState v m, SqlOnConflict v) => [SQL] -> m ()
sqlOnConflictOnColumnsDoNothing :: forall v (m :: * -> *).
(MonadState v m, SqlOnConflict v) =>
[SQL] -> m ()
sqlOnConflictOnColumnsDoNothing [SQL]
columns = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlOnConflict a => a -> [SQL] -> a
sqlOnConflictOnColumnsDoNothing1 v
cmd [SQL]
columns)

sqlOnConflictOnColumns :: (MonadState v m, SqlOnConflict v, Sqlable sql) => [SQL] -> sql -> m ()
sqlOnConflictOnColumns :: forall v (m :: * -> *) sql.
(MonadState v m, SqlOnConflict v, Sqlable sql) =>
[SQL] -> sql -> m ()
sqlOnConflictOnColumns [SQL]
columns sql
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a sql.
(SqlOnConflict a, Sqlable sql) =>
a -> [SQL] -> sql -> a
sqlOnConflictOnColumns1 v
cmd [SQL]
columns sql
sql)

class SqlResult a where
  sqlResult1 :: a -> SQL -> a

instance SqlResult SqlSelect where
  sqlResult1 :: SqlSelect -> SQL -> SqlSelect
sqlResult1 SqlSelect
cmd SQL
sql = SqlSelect
cmd { sqlSelectResult :: [SQL]
sqlSelectResult = SqlSelect -> [SQL]
sqlSelectResult SqlSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

instance SqlResult SqlInsert where
  sqlResult1 :: SqlInsert -> SQL -> SqlInsert
sqlResult1 SqlInsert
cmd SQL
sql = SqlInsert
cmd { sqlInsertResult :: [SQL]
sqlInsertResult = SqlInsert -> [SQL]
sqlInsertResult SqlInsert
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

instance SqlResult SqlInsertSelect where
  sqlResult1 :: SqlInsertSelect -> SQL -> SqlInsertSelect
sqlResult1 SqlInsertSelect
cmd SQL
sql = SqlInsertSelect
cmd { sqlInsertSelectResult :: [SQL]
sqlInsertSelectResult = SqlInsertSelect -> [SQL]
sqlInsertSelectResult SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

instance SqlResult SqlUpdate where
  sqlResult1 :: SqlUpdate -> SQL -> SqlUpdate
sqlResult1 SqlUpdate
cmd SQL
sql = SqlUpdate
cmd { sqlUpdateResult :: [SQL]
sqlUpdateResult = SqlUpdate -> [SQL]
sqlUpdateResult SqlUpdate
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

instance SqlResult SqlDelete where
  sqlResult1 :: SqlDelete -> SQL -> SqlDelete
sqlResult1 SqlDelete
cmd SQL
sql = SqlDelete
cmd { sqlDeleteResult :: [SQL]
sqlDeleteResult = SqlDelete -> [SQL]
sqlDeleteResult SqlDelete
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

sqlResult :: (MonadState v m, SqlResult v) => SQL -> m ()
sqlResult :: forall v (m :: * -> *).
(MonadState v m, SqlResult v) =>
SQL -> m ()
sqlResult SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlResult a => a -> SQL -> a
sqlResult1 v
cmd SQL
sql)

class SqlOrderBy a where
  sqlOrderBy1 :: a -> SQL -> a

instance SqlOrderBy SqlSelect where
  sqlOrderBy1 :: SqlSelect -> SQL -> SqlSelect
sqlOrderBy1 SqlSelect
cmd SQL
sql = SqlSelect
cmd { sqlSelectOrderBy :: [SQL]
sqlSelectOrderBy = SqlSelect -> [SQL]
sqlSelectOrderBy SqlSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

instance SqlOrderBy SqlInsertSelect where
  sqlOrderBy1 :: SqlInsertSelect -> SQL -> SqlInsertSelect
sqlOrderBy1 SqlInsertSelect
cmd SQL
sql = SqlInsertSelect
cmd { sqlInsertSelectOrderBy :: [SQL]
sqlInsertSelectOrderBy = SqlInsertSelect -> [SQL]
sqlInsertSelectOrderBy SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }


sqlOrderBy :: (MonadState v m, SqlOrderBy v) => SQL -> m ()
sqlOrderBy :: forall v (m :: * -> *).
(MonadState v m, SqlOrderBy v) =>
SQL -> m ()
sqlOrderBy SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlOrderBy a => a -> SQL -> a
sqlOrderBy1 v
cmd SQL
sql)

class SqlGroupByHaving a where
  sqlGroupBy1 :: a -> SQL -> a
  sqlHaving1 :: a -> SQL -> a

instance SqlGroupByHaving SqlSelect where
  sqlGroupBy1 :: SqlSelect -> SQL -> SqlSelect
sqlGroupBy1 SqlSelect
cmd SQL
sql = SqlSelect
cmd { sqlSelectGroupBy :: [SQL]
sqlSelectGroupBy = SqlSelect -> [SQL]
sqlSelectGroupBy SqlSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }
  sqlHaving1 :: SqlSelect -> SQL -> SqlSelect
sqlHaving1 SqlSelect
cmd SQL
sql = SqlSelect
cmd { sqlSelectHaving :: [SQL]
sqlSelectHaving = SqlSelect -> [SQL]
sqlSelectHaving SqlSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

instance SqlGroupByHaving SqlInsertSelect where
  sqlGroupBy1 :: SqlInsertSelect -> SQL -> SqlInsertSelect
sqlGroupBy1 SqlInsertSelect
cmd SQL
sql = SqlInsertSelect
cmd { sqlInsertSelectGroupBy :: [SQL]
sqlInsertSelectGroupBy = SqlInsertSelect -> [SQL]
sqlInsertSelectGroupBy SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }
  sqlHaving1 :: SqlInsertSelect -> SQL -> SqlInsertSelect
sqlHaving1 SqlInsertSelect
cmd SQL
sql = SqlInsertSelect
cmd { sqlInsertSelectHaving :: [SQL]
sqlInsertSelectHaving = SqlInsertSelect -> [SQL]
sqlInsertSelectHaving SqlInsertSelect
cmd forall a. [a] -> [a] -> [a]
++ [SQL
sql] }

sqlGroupBy :: (MonadState v m, SqlGroupByHaving v) => SQL -> m ()
sqlGroupBy :: forall v (m :: * -> *).
(MonadState v m, SqlGroupByHaving v) =>
SQL -> m ()
sqlGroupBy SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlGroupByHaving a => a -> SQL -> a
sqlGroupBy1 v
cmd SQL
sql)

sqlHaving :: (MonadState v m, SqlGroupByHaving v) => SQL -> m ()
sqlHaving :: forall v (m :: * -> *).
(MonadState v m, SqlGroupByHaving v) =>
SQL -> m ()
sqlHaving SQL
sql = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlGroupByHaving a => a -> SQL -> a
sqlHaving1 v
cmd SQL
sql)


class SqlOffsetLimit a where
  sqlOffset1 :: a -> Integer -> a
  sqlLimit1 :: a -> Integer -> a

instance SqlOffsetLimit SqlSelect where
  sqlOffset1 :: SqlSelect -> Integer -> SqlSelect
sqlOffset1 SqlSelect
cmd Integer
num = SqlSelect
cmd { sqlSelectOffset :: Integer
sqlSelectOffset = Integer
num }
  sqlLimit1 :: SqlSelect -> Integer -> SqlSelect
sqlLimit1 SqlSelect
cmd Integer
num = SqlSelect
cmd { sqlSelectLimit :: Integer
sqlSelectLimit = Integer
num }

instance SqlOffsetLimit SqlInsertSelect where
  sqlOffset1 :: SqlInsertSelect -> Integer -> SqlInsertSelect
sqlOffset1 SqlInsertSelect
cmd Integer
num = SqlInsertSelect
cmd { sqlInsertSelectOffset :: Integer
sqlInsertSelectOffset = Integer
num }
  sqlLimit1 :: SqlInsertSelect -> Integer -> SqlInsertSelect
sqlLimit1 SqlInsertSelect
cmd Integer
num = SqlInsertSelect
cmd { sqlInsertSelectLimit :: Integer
sqlInsertSelectLimit = Integer
num }

sqlOffset :: (MonadState v m, SqlOffsetLimit v, Integral int) => int -> m ()
sqlOffset :: forall v (m :: * -> *) int.
(MonadState v m, SqlOffsetLimit v, Integral int) =>
int -> m ()
sqlOffset int
val = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlOffsetLimit a => a -> Integer -> a
sqlOffset1 v
cmd forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Integer
toInteger int
val)

sqlLimit :: (MonadState v m, SqlOffsetLimit v, Integral int) => int -> m ()
sqlLimit :: forall v (m :: * -> *) int.
(MonadState v m, SqlOffsetLimit v, Integral int) =>
int -> m ()
sqlLimit int
val = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlOffsetLimit a => a -> Integer -> a
sqlLimit1 v
cmd forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Integer
toInteger int
val)

class SqlDistinct a where
  sqlDistinct1 :: a -> a

instance SqlDistinct SqlSelect where
  sqlDistinct1 :: SqlSelect -> SqlSelect
sqlDistinct1 SqlSelect
cmd = SqlSelect
cmd { sqlSelectDistinct :: Bool
sqlSelectDistinct = Bool
True }

instance SqlDistinct SqlInsertSelect where
  sqlDistinct1 :: SqlInsertSelect -> SqlInsertSelect
sqlDistinct1 SqlInsertSelect
cmd = SqlInsertSelect
cmd { sqlInsertSelectDistinct :: Bool
sqlInsertSelectDistinct = Bool
True }

sqlDistinct :: (MonadState v m, SqlDistinct v) => m ()
sqlDistinct :: forall v (m :: * -> *). (MonadState v m, SqlDistinct v) => m ()
sqlDistinct = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\v
cmd -> forall a. SqlDistinct a => a -> a
sqlDistinct1 v
cmd)