module Database.PostgreSQL.Query.Internal
       ( -- * Low level generators
         buildFields
       , updateTable
       , insertInto
       ) where

import Database.PostgreSQL.Query.SqlBuilder
import Database.PostgreSQL.Query.TH
import Database.PostgreSQL.Query.Types

import qualified Data.List as L

{- $setup
>>> import Database.PostgreSQL.Simple
>>> import Database.PostgreSQL.Simple.ToField
>>> import Database.PostgreSQL.Query.SqlBuilder
>>> import Data.Text ( Text )
>>> con <- connect defaultConnectInfo
>>> run b = fmap fst $ runSqlBuilder con defaultLogMasker b
-}


{-| Generates comma separated list of field names

>>> run $ buildFields ["u" <> "name", "u" <> "phone", "e" <> "email"]
"\"u\".\"name\", \"u\".\"phone\", \"e\".\"email\""
-}
buildFields :: [FN] -> SqlBuilder
buildFields :: [FN] -> SqlBuilder
buildFields [FN]
flds = [SqlBuilder] -> SqlBuilder
forall a. Monoid a => [a] -> a
mconcat
                    ([SqlBuilder] -> SqlBuilder) -> [SqlBuilder] -> SqlBuilder
forall a b. (a -> b) -> a -> b
$ SqlBuilder -> [SqlBuilder] -> [SqlBuilder]
forall a. a -> [a] -> [a]
L.intersperse SqlBuilder
", "
                    ([SqlBuilder] -> [SqlBuilder]) -> [SqlBuilder] -> [SqlBuilder]
forall a b. (a -> b) -> a -> b
$ (FN -> SqlBuilder) -> [FN] -> [SqlBuilder]
forall a b. (a -> b) -> [a] -> [b]
map FN -> SqlBuilder
forall a. ToSqlBuilder a => a -> SqlBuilder
toSqlBuilder [FN]
flds

{- | generates __UPDATE__ query

>>> let name = "%vip%"
>>> run $ updateTable "ships" (MR [("size", mkValue 15)]) [sqlExp|WHERE size > 15 AND name NOT LIKE #{name}|]
"UPDATE \"ships\" SET  \"size\" = 15  WHERE size > 15 AND name NOT LIKE '%vip%'"

-}

updateTable :: (ToSqlBuilder q, ToMarkedRow flds)
            => FN               -- ^ table name
            -> flds             -- ^ fields to update
            -> q                -- ^ condition
            -> SqlBuilder
updateTable :: FN -> flds -> q -> SqlBuilder
updateTable FN
tname flds
flds q
q =
    let mr :: MarkedRow
mr = flds -> MarkedRow
forall a. ToMarkedRow a => a -> MarkedRow
toMarkedRow flds
flds
        setFields :: SqlBuilder
setFields = SqlBuilder -> MarkedRow -> SqlBuilder
mrToBuilder SqlBuilder
", " MarkedRow
mr
    in [sqlExp|UPDATE ^{tname}
               SET ^{setFields} ^{q}|]


{- | Generate INSERT INTO query for entity

>>> run $ insertInto "foo" $ MR [("name", mkValue "vovka"), ("hobby", mkValue "president")]
"INSERT INTO \"foo\" (\"name\", \"hobby\") VALUES ('vovka', 'president')"

-}

insertInto :: (ToMarkedRow b)
           => FN       -- ^ table name
           -> b        -- ^ list of pairs (name, value) to insert into
           -> SqlBuilder
insertInto :: FN -> b -> SqlBuilder
insertInto FN
tname b
b =
    let mr :: MarkedRow
mr = b -> MarkedRow
forall a. ToMarkedRow a => a -> MarkedRow
toMarkedRow b
b
        names :: SqlBuilder
names = [SqlBuilder] -> SqlBuilder
forall a. Monoid a => [a] -> a
mconcat
                ([SqlBuilder] -> SqlBuilder) -> [SqlBuilder] -> SqlBuilder
forall a b. (a -> b) -> a -> b
$ SqlBuilder -> [SqlBuilder] -> [SqlBuilder]
forall a. a -> [a] -> [a]
L.intersperse SqlBuilder
", "
                ([SqlBuilder] -> [SqlBuilder]) -> [SqlBuilder] -> [SqlBuilder]
forall a b. (a -> b) -> a -> b
$ ((FN, SqlBuilder) -> SqlBuilder)
-> [(FN, SqlBuilder)] -> [SqlBuilder]
forall a b. (a -> b) -> [a] -> [b]
map (FN -> SqlBuilder
forall a. ToSqlBuilder a => a -> SqlBuilder
toSqlBuilder (FN -> SqlBuilder)
-> ((FN, SqlBuilder) -> FN) -> (FN, SqlBuilder) -> SqlBuilder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FN, SqlBuilder) -> FN
forall a b. (a, b) -> a
fst)
                ([(FN, SqlBuilder)] -> [SqlBuilder])
-> [(FN, SqlBuilder)] -> [SqlBuilder]
forall a b. (a -> b) -> a -> b
$ MarkedRow -> [(FN, SqlBuilder)]
unMR MarkedRow
mr
        values :: SqlBuilder
values = [SqlBuilder] -> SqlBuilder
forall a. Monoid a => [a] -> a
mconcat
                 ([SqlBuilder] -> SqlBuilder) -> [SqlBuilder] -> SqlBuilder
forall a b. (a -> b) -> a -> b
$ SqlBuilder -> [SqlBuilder] -> [SqlBuilder]
forall a. a -> [a] -> [a]
L.intersperse SqlBuilder
", "
                 ([SqlBuilder] -> [SqlBuilder]) -> [SqlBuilder] -> [SqlBuilder]
forall a b. (a -> b) -> a -> b
$ ((FN, SqlBuilder) -> SqlBuilder)
-> [(FN, SqlBuilder)] -> [SqlBuilder]
forall a b. (a -> b) -> [a] -> [b]
map (FN, SqlBuilder) -> SqlBuilder
forall a b. (a, b) -> b
snd
                 ([(FN, SqlBuilder)] -> [SqlBuilder])
-> [(FN, SqlBuilder)] -> [SqlBuilder]
forall a b. (a -> b) -> a -> b
$ MarkedRow -> [(FN, SqlBuilder)]
unMR MarkedRow
mr
    in [sqlExp|INSERT INTO ^{tname}
               (^{names}) VALUES (^{values})|]