-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Sql interpolating quasiquote plus some kind of primitive ORM -- using it -- -- Sql interpolating quasiquote plus some kind of primitive ORM using it @package postgresql-query @version 3.4.0 module Database.PostgreSQL.Query.SqlBuilder.Types -- | Result if SqlBuilder. Contains separated builder for query and log. data SqlBuilderResult SqlBuilderResult :: Builder -> Builder -> SqlBuilderResult [sbQueryString] :: SqlBuilderResult -> Builder [sbLogString] :: SqlBuilderResult -> Builder builderResultPure :: Builder -> SqlBuilderResult -- | Option for field instructing LogMasker what to do with field -- when logging data FieldOption -- | Do nothing. Field should be pasted as is FieldDefault :: FieldOption -- | Mask field in logs with placeholder. FieldMasked :: FieldOption -- | Function modifying query parameter value before pasting it to log. type LogMasker = FieldOption -> Builder -> Builder -- | Simply replaces masked fields with placeholder. defaultLogMasker :: LogMasker -- | Masks fields which size is bigger than given argument in bytes. hugeFieldsMasker :: Int -> LogMasker instance Language.Haskell.TH.Syntax.Lift Database.PostgreSQL.Query.SqlBuilder.Types.FieldOption instance GHC.Generics.Generic Database.PostgreSQL.Query.SqlBuilder.Types.FieldOption instance GHC.Show.Show Database.PostgreSQL.Query.SqlBuilder.Types.FieldOption instance GHC.Classes.Ord Database.PostgreSQL.Query.SqlBuilder.Types.FieldOption instance GHC.Classes.Eq Database.PostgreSQL.Query.SqlBuilder.Types.FieldOption instance GHC.Generics.Generic Database.PostgreSQL.Query.SqlBuilder.Types.SqlBuilderResult instance Data.Semigroup.Semigroup Database.PostgreSQL.Query.SqlBuilder.Types.SqlBuilderResult instance GHC.Base.Monoid Database.PostgreSQL.Query.SqlBuilder.Types.SqlBuilderResult module Database.PostgreSQL.Query.SqlBuilder.Builder -- | Builder wich can be effectively concatenated. Requires -- Connection inside for string quoting implemented in -- libpq. Builds two strings: query string and log string which -- may differ. newtype SqlBuilder SqlBuilder :: (Connection -> LogMasker -> IO SqlBuilderResult) -> SqlBuilder [sqlBuild] :: SqlBuilder -> Connection -> LogMasker -> IO SqlBuilderResult -- | Returns query string with log bytestring runSqlBuilder :: Connection -> LogMasker -> SqlBuilder -> IO (Query, ByteString) -- | Typed synonym of mempty emptyB :: SqlBuilder -- | Shorthand function to convert single field value to builder mkValue :: (ToField a) => a -> SqlBuilder -- | Shorthand function to convert single masked field value (which should -- not be shown in log) mkMaskedValue :: (ToField a) => a -> SqlBuilder sqlBuilderFromField :: (ToField a) => FieldOption -> a -> SqlBuilder -- | Lift pure bytestring builder to SqlBuilder. This is unsafe to -- use directly in your code. sqlBuilderPure :: Builder -> SqlBuilder -- | Unsafe function to make SqlBuilder from arbitrary ByteString. Does not -- perform any checks. Dont use it directly in your code unless you know -- what you are doing. sqlBuilderFromByteString :: ByteString -> SqlBuilder instance GHC.Generics.Generic Database.PostgreSQL.Query.SqlBuilder.Builder.SqlBuilder instance Data.Semigroup.Semigroup Database.PostgreSQL.Query.SqlBuilder.Builder.SqlBuilder instance GHC.Base.Monoid Database.PostgreSQL.Query.SqlBuilder.Builder.SqlBuilder instance Data.String.IsString Database.PostgreSQL.Query.SqlBuilder.Builder.SqlBuilder module Database.PostgreSQL.Query.SqlBuilder.Class -- | Things which always can be transformed to SqlBuilder class ToSqlBuilder a toSqlBuilder :: ToSqlBuilder a => a -> SqlBuilder instance Database.PostgreSQL.Query.SqlBuilder.Class.ToSqlBuilder Database.PostgreSQL.Query.SqlBuilder.Builder.SqlBuilder instance Database.PostgreSQL.Query.SqlBuilder.Class.ToSqlBuilder Database.PostgreSQL.Simple.Types.Identifier instance Database.PostgreSQL.Query.SqlBuilder.Class.ToSqlBuilder Database.PostgreSQL.Simple.Types.QualifiedIdentifier module Database.PostgreSQL.Query.SqlBuilder module Database.PostgreSQL.Query.TH.Common -- | Return constructor name cName :: (Monad m) => Con -> m Name -- | Return count of constructor fields cArgs :: (Monad m) => Con -> m Int -- | Get field names from record constructor cFieldNames :: Con -> [Name] lookupVNameErr :: String -> Q Name dataConstructors :: Info -> [Con] -- | Helps to map enum types to postgresql enums. module Database.PostgreSQL.Query.TH.Enum -- | derives FromField and ToField instances for a sum-type -- enum like -- --
-- data Entity = Red | Green | Blue --derivePgEnum :: InflectorFunc -> Name -> DecsQ -- | Function to transform constructor name into its PG enum conterpart. type InflectorFunc = String -> String module Database.PostgreSQL.Query.TH.Row -- | Derive FromRow instance. i.e. you have type like that -- --
-- data Entity = Entity
-- { eField :: Text
-- , eField2 :: Int
-- , efield3 :: Bool }
--
--
-- then deriveFromRow will generate this instance: instance
-- FromRow Entity where
--
-- -- instance FromRow Entity where -- fromRow = Entity -- <$> field -- <*> field -- <*> field ---- -- Datatype must have just one constructor with arbitrary count of fields deriveFromRow :: Name -> Q [Dec] -- | derives ToRow instance for datatype like -- --
-- data Entity = Entity
-- { eField :: Text
-- , eField2 :: Int
-- , efield3 :: Bool }
--
--
-- it will derive instance like that:
--
-- -- instance ToRow Entity where -- toRow (Entity e1 e2 e3) = -- [ toField e1 -- , toField e2 -- , toField e3 ] --deriveToRow :: Name -> Q [Dec] module Database.PostgreSQL.Query.TH.SqlExp -- | Maybe the main feature of all library. Quasiquoter which builds -- SqlBuilder from string query. Removes line comments and block -- comments (even nested) and sequences of spaces. Correctly works -- handles string literals and quoted identifiers. Here is examples of -- usage -- --
-- >>> let name = "name"
--
-- >>> let val = "some 'value'"
--
-- >>> runSqlBuilder c [sqlExp|SELECT * FROM tbl WHERE ^{mkIdent name} = #{val}|]
-- "SELECT * FROM tbl WHERE \"name\" = 'some ''value'''"
--
--
-- And more comples example:
--
--
-- >>> let name = Just "name"
--
-- >>> let size = Just 10
--
-- >>> let active = Nothing :: Maybe Bool
--
-- >>> let condlist = catMaybes [ fmap (\a -> [sqlExp|name = #{a}|]) name, fmap (\a -> [sqlExp|size = #{a}|]) size, fmap (\a -> [sqlExp|active = #{a}|]) active]
--
-- >>> let cond = if L.null condlist then mempty else [sqlExp| WHERE ^{mconcat $ L.intersperse " AND " $ condlist} |]
--
-- >>> runSqlBuilder c [sqlExp|SELECT * FROM tbl ^{cond} -- line comment|]
-- "SELECT * FROM tbl WHERE name = 'name' AND size = 10 "
--
sqlExp :: QuasiQuoter
-- | Internal type. Result of parsing sql string
data Rope
-- | Part of raw sql
RLit :: Text -> Rope
-- | Sql comment
RComment :: Text -> Rope
-- | Sequence of spaces
RSpaces :: Int -> Rope
-- | String with haskell expression inside #{..} or #?{..}
RInt :: FieldOption -> Text -> Rope
-- | String with haskell expression inside ^{..}
RPaste :: Text -> Rope
ropeParser :: Parser [Rope]
parseRope :: String -> [Rope]
-- | Removes sequential occurencies of RLit constructors. Also
-- removes commentaries and squash sequences of spaces to single space
-- symbol
squashRope :: [Rope] -> [Rope]
-- | Build expression of type SqlBuilder from SQL query with
-- interpolation
sqlQExp :: String -> Q Exp
-- | Embed sql template and perform interpolation
--
-- -- let name = "name" -- foo = "bar" -- query = $(sqlExpEmbed "sqlfoobar.sql") -- using foo and bar inside --sqlExpEmbed :: String -> Q Exp -- | Just like sqlExpEmbed but uses pattern instead of file name. -- So, code -- --
-- let query = $(sqlExpFile "foo/bar") ---- -- is just the same as -- --
-- let query = $(sqlExpEmbed "sqlfoobar.sql") ---- -- This function inspired by Yesod's widgetFile sqlExpFile :: String -> Q Exp instance GHC.Show.Show Database.PostgreSQL.Query.TH.SqlExp.Rope instance GHC.Classes.Eq Database.PostgreSQL.Query.TH.SqlExp.Rope instance GHC.Classes.Ord Database.PostgreSQL.Query.TH.SqlExp.Rope module Database.PostgreSQL.Query.Types -- | Instances of this typeclass can acquire connection and pass it to -- computation. It can be reader of pool of connections or just reader of -- connection class (MonadBase IO m) => HasPostgres m withPGConnection :: HasPostgres m => (Connection -> m a) -> m a type MonadPostgres m = (HasPostgres m, MonadLogger m) -- | Empty typeclass signing monad in which transaction is safe. i.e. -- PgMonadT have this instance, but some other monad giving -- connection from e.g. connection pool is not. class TransactionSafe (m :: * -> *) -- | Reader of connection. Has instance of HasPostgres. So if you -- have a connection you can run queries in this monad using -- runPgMonadT. Or you can use this transformer to run sequence of -- queries using same connection with launchPG. newtype PgMonadT m a PgMonadT :: ReaderT Connection m a -> PgMonadT m a [unPgMonadT] :: PgMonadT m a -> ReaderT Connection m a runPgMonadT :: Connection -> PgMonadT m a -> m a -- | If your monad have instance of HasPostgres you maybe dont need -- this function, unless your instance use withPGPool which -- acquires connection from pool for each query. If you want to run -- sequence of queries using same connection you need this function launchPG :: (HasPostgres m) => PgMonadT m a -> m a -- | Special constructor to perform old-style query interpolation data Qp Qp :: Query -> row -> Qp -- | type to put and get from db inet and cidr typed -- postgresql fields. This should be in postgresql-simple in fact. newtype InetText InetText :: Text -> InetText [unInetText] :: InetText -> Text -- | Dot-separated field name. Each element in nested list will be properly -- quoted and separated by dot. It also have instance of -- ToSqlBuilder and IsString so you can: -- --
-- >>> let a = "hello" :: FN -- -- >>> a -- FN ["hello"] ---- --
-- >>> let b = "user.name" :: FN -- -- >>> b -- FN ["user","name"] ---- --
-- >>> let n = "u.name" :: FN -- -- >>> runSqlBuilder c $ toSqlBuilder n -- "\"u\".\"name\"" ---- --
-- >>> ("user" <> "name") :: FN
-- FN ["user","name"]
--
--
--
-- >>> let a = "name" :: FN
--
-- >>> let b = "email" :: FN
--
-- >>> runSqlBuilder c [sqlExp|^{"u" <> a} = 'name', ^{"e" <> b} = 'email'|]
-- "\"u\".\"name\" = 'name', \"e\".\"email\" = 'email'"
--
newtype FN
FN :: [Text] -> FN
-- | Single field to FN
--
-- -- >>> textFN "hello" -- FN ["hello"] ---- --
-- >>> textFN "user.name" -- FN ["user.name"] ---- -- Note that it does not split string to parts by point like instance of -- IsString does textFN :: Text -> FN -- | Marked row is list of pairs of field name and some sql expression. -- Used to generate queries like: -- --
-- name = name AND size = 10 AND length = 20 ---- -- or -- --
-- UPDATE tbl SET name = name, size = 10, lenght = 20 --newtype MarkedRow MR :: [(FN, SqlBuilder)] -> MarkedRow [unMR] :: MarkedRow -> [(FN, SqlBuilder)] -- | Turns marked row to query intercalating it with other builder -- --
-- >>> runSqlBuilder c $ mrToBuilder "AND" $ MR [("name", mkValue "petr"), ("email", mkValue "foo@bar.com")]
-- " \"name\" = 'petr' AND \"email\" = 'foo@bar.com' "
--
mrToBuilder :: SqlBuilder -> MarkedRow -> SqlBuilder
class ToMarkedRow a
-- | generate list of pairs (field name, field value)
toMarkedRow :: ToMarkedRow a => a -> MarkedRow
instance Control.Monad.Logger.MonadLogger m => Control.Monad.Logger.MonadLogger (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Cont.Class.MonadCont m => Control.Monad.Cont.Class.MonadCont (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Database.PostgreSQL.Query.Types.PgMonadT m)
instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Database.PostgreSQL.Query.Types.PgMonadT m)
instance GHC.Base.Alternative m => GHC.Base.Alternative (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Trans.Class.MonadTrans Database.PostgreSQL.Query.Types.PgMonadT
instance Control.Monad.Error.Class.MonadError e m => Control.Monad.Error.Class.MonadError e (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Database.PostgreSQL.Query.Types.PgMonadT m)
instance GHC.Base.Monad m => GHC.Base.Monad (Database.PostgreSQL.Query.Types.PgMonadT m)
instance GHC.Base.Applicative m => GHC.Base.Applicative (Database.PostgreSQL.Query.Types.PgMonadT m)
instance GHC.Base.Functor m => GHC.Base.Functor (Database.PostgreSQL.Query.Types.PgMonadT m)
instance GHC.Generics.Generic Database.PostgreSQL.Query.Types.MarkedRow
instance GHC.Base.Monoid Database.PostgreSQL.Query.Types.MarkedRow
instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Trans.Control.MonadTransControl Database.PostgreSQL.Query.Types.PgMonadT
instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.HReader.Class.MonadHReader m => Control.Monad.HReader.Class.MonadHReader (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Control.Monad.Base.MonadBase GHC.Types.IO m => Database.PostgreSQL.Query.Types.HasPostgres (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Database.PostgreSQL.Query.Types.TransactionSafe (Database.PostgreSQL.Query.Types.PgMonadT m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Except.ExceptT e m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Identity.IdentityT m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Maybe.MaybeT m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Reader.ReaderT r m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.State.Lazy.StateT s m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.State.Strict.StateT s m)
instance Database.PostgreSQL.Query.Types.TransactionSafe m => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Cont.ContT r m)
instance (Database.PostgreSQL.Query.Types.TransactionSafe m, GHC.Base.Monoid w) => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Writer.Lazy.WriterT w m)
instance (Database.PostgreSQL.Query.Types.TransactionSafe m, GHC.Base.Monoid w) => Database.PostgreSQL.Query.Types.TransactionSafe (Control.Monad.Trans.Writer.Strict.WriterT w m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Except.ExceptT e m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Identity.IdentityT m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Maybe.MaybeT m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Reader.ReaderT r m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.State.Lazy.StateT s m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.State.Strict.StateT s m)
instance Database.PostgreSQL.Query.Types.HasPostgres m => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Cont.ContT r m)
instance (Database.PostgreSQL.Query.Types.HasPostgres m, GHC.Base.Monoid w) => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Writer.Lazy.WriterT w m)
instance (Database.PostgreSQL.Query.Types.HasPostgres m, GHC.Base.Monoid w) => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.Trans.Writer.Strict.WriterT w m)
instance (Control.Monad.Base.MonadBase GHC.Types.IO m, Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO m, Data.HSet.Get.HGettable els (Data.Pool.Pool Database.PostgreSQL.Simple.Internal.Connection)) => Database.PostgreSQL.Query.Types.HasPostgres (Control.Monad.HReader.HReaderT els m)
instance Database.PostgreSQL.Query.Types.ToMarkedRow Database.PostgreSQL.Query.Types.MarkedRow
instance Language.Haskell.TH.Syntax.Lift Database.PostgreSQL.Query.Types.FN
instance Database.PostgreSQL.Query.SqlBuilder.Class.ToSqlBuilder Database.PostgreSQL.Query.Types.FN
instance Data.String.IsString Database.PostgreSQL.Query.Types.FN
instance GHC.Generics.Generic Database.PostgreSQL.Query.Types.FN
instance GHC.Base.Monoid Database.PostgreSQL.Query.Types.FN
instance GHC.Show.Show Database.PostgreSQL.Query.Types.FN
instance GHC.Classes.Eq Database.PostgreSQL.Query.Types.FN
instance GHC.Classes.Ord Database.PostgreSQL.Query.Types.FN
instance Database.PostgreSQL.Simple.ToField.ToField Database.PostgreSQL.Query.Types.InetText
instance GHC.Base.Monoid Database.PostgreSQL.Query.Types.InetText
instance GHC.Show.Show Database.PostgreSQL.Query.Types.InetText
instance GHC.Read.Read Database.PostgreSQL.Query.Types.InetText
instance GHC.Classes.Ord Database.PostgreSQL.Query.Types.InetText
instance GHC.Classes.Eq Database.PostgreSQL.Query.Types.InetText
instance Data.String.IsString Database.PostgreSQL.Query.Types.InetText
instance Database.PostgreSQL.Simple.FromField.FromField Database.PostgreSQL.Query.Types.InetText
instance Database.PostgreSQL.Query.SqlBuilder.Class.ToSqlBuilder Database.PostgreSQL.Query.Types.Qp
module Database.PostgreSQL.Query.Entity.Class
-- | Auxiliary typeclass for data types which can map to rows of some
-- table. This typeclass is used inside functions like
-- pgSelectEntities to generate queries.
class Entity a where {
data family EntityId a :: *;
}
-- | Table name of this entity
tableName :: Entity a => Proxy a -> FN
-- | Field names without id and created. The order of field
-- names must match with order of fields in ToRow and
-- FromRow instances of this type.
fieldNames :: Entity a => Proxy a -> [FN]
-- | Entity with it's id
type Ent a = (EntityId a, a)
module Database.PostgreSQL.Query.TH.Entity
-- | Options for deriving Entity
data EntityOptions
EntityOptions :: (Text -> FN) -> (Text -> FN) -> [Name] -> Name -> EntityOptions
-- | Type name to table name converter
[eoTableName] :: EntityOptions -> Text -> FN
-- | Record field to column name converter
[eoColumnNames] :: EntityOptions -> Text -> FN
-- | Typeclasses to derive for Id
[eoDeriveClasses] :: EntityOptions -> [Name]
-- | Base type for Id
[eoIdType] :: EntityOptions -> Name
-- | Derives instance for Entity using type name and field names.
-- Also generates type synonim for ID. E.g. code like this:
--
--
-- data Agent = Agent
-- { aName :: !Text
-- , aAttributes :: !HStoreMap
-- , aLongWeirdName :: !Int
-- } deriving (Ord, Eq, Show)
--
-- $(deriveEntity
-- def { eoIdType = ''Id
-- , eoTableName = textFN . toUnderscore'
-- , eoColumnNames = textFN . toUnderscore' . drop 1
-- , eoDeriveClasses =
-- [''Show, ''Read, ''Ord, ''Eq
-- , ''FromField, ''ToField, ''PathPiece]
-- }
-- ''Agent )
--
--
-- Will generate code like this:
--
--
-- instance Database.PostgreSQL.Query.Entity Agent where
-- newtype EntityId Agent
-- = AgentId {getAgentId :: Id}
-- deriving (Show, Read, Ord, Eq, FromField, ToField, PathPiece)
-- tableName _ = "agent"
-- fieldNames _ = ["name", "attributes", "long_weird_name"]
-- type AgentId = EntityId Agent
--
--
-- So, you dont need to write it by hands any more.
--
-- NOTE: toUnderscore is from package inflections here
deriveEntity :: EntityOptions -> Name -> Q [Dec]
instance GHC.Generics.Generic Database.PostgreSQL.Query.TH.Entity.EntityOptions
instance Data.Default.Class.Default Database.PostgreSQL.Query.TH.Entity.EntityOptions
module Database.PostgreSQL.Query.TH
-- | Calls sequently deriveFromRow deriveToRow
-- deriveEntity. E.g. code like this:
--
--
-- data Agent = Agent
-- { aName :: !Text
-- , aAttributes :: !HStoreMap
-- , aLongWeirdName :: !Int
-- } deriving (Ord, Eq, Show)
--
-- $(deriveEverything
-- def { eoIdType = ''Id
-- , eoTableName = textFN . toUnderscore'
-- , eoColumnNames = textFN . toUnderscore' . drop 1
-- , eoDeriveClasses =
-- [''Show, ''Read, ''Ord, ''Eq
-- , ''FromField, ''ToField, ''PathPiece]
-- }
-- ''Agent )
--
--
-- will generate that:
--
--
-- instance ToRow Agent where
-- toRow (Agent a_aE3w a_aE3x a_aE3y)
-- = [toField a_aE3w, toField a_aE3x, toField a_aE3y]
-- instance FromRow Agent where
-- fromRow
-- = Agent $ Database.PostgreSQL.Simple.FromRow.field
-- * Database.PostgreSQL.Simple.FromRow.field
-- * Database.PostgreSQL.Simple.FromRow.field
-- instance Database.PostgreSQL.Query.Entity Agent where
-- newtype EntityId Agent
-- = AgentId {getAgentId :: Id}
-- deriving (Show, Read, Ord, Eq, FromField, ToField, PathPiece)
-- tableName _ = "agent"
-- fieldNames _ = ["name", "attributes", "long_weird_name"]
-- type AgentId = EntityId Agent
--
deriveEverything :: EntityOptions -> Name -> Q [Dec]
module Database.PostgreSQL.Query.Internal
-- | Generates comma separated list of field names
--
-- -- >>> runSqlBuilder con $ buildFields ["u" <> "name", "u" <> "phone", "e" <> "email"] -- "\"u\".\"name\", \"u\".\"phone\", \"e\".\"email\"" --buildFields :: [FN] -> SqlBuilder -- | generates UPDATE query -- --
-- >>> let name = "%vip%"
--
-- >>> runSqlBuilder con $ 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 -> flds -> q -> SqlBuilder
-- | Generate INSERT INTO query for entity
--
--
-- >>> runSqlBuilder con $ insertInto "foo" $ MR [("name", mkValue "vovka"), ("hobby", mkValue "president")]
-- "INSERT INTO \"foo\" (\"name\", \"hobby\") VALUES ('vovka', 'president')"
--
insertInto :: (ToMarkedRow b) => FN -> b -> SqlBuilder
module Database.PostgreSQL.Query.Functions
-- | Execute query generated by SqlBuilder. Typical use case:
--
--
-- let userName = "Vovka Erohin" :: Text
-- pgQuery [sqlExp| SELECT id, name FROM users WHERE name = #{userName}|]
--
--
-- Or
--
-- -- let userName = "Vovka Erohin" :: Text -- pgQuery $ Qp "SELECT id, name FROM users WHERE name = ?" [userName] ---- -- Which is almost the same. In both cases proper value escaping is -- performed so you stay protected from sql injections. pgQuery :: (HasPostgres m, MonadLogger m, ToSqlBuilder q, FromRow r) => q -> m [r] pgQueryWithMasker :: (HasPostgres m, MonadLogger m, ToSqlBuilder q, FromRow r) => LogMasker -> q -> m [r] -- | Execute arbitrary query and return count of affected rows pgExecute :: (HasPostgres m, MonadLogger m, ToSqlBuilder q) => q -> m Int64 pgExecuteWithMasker :: (HasPostgres m, MonadLogger m, ToSqlBuilder q) => LogMasker -> q -> m Int64 -- | Execute all queries inside one transaction. Rollback transaction on -- exceptions pgWithTransaction :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m) => m a -> m a -- | Same as pgWithTransaction but executes queries inside savepoint pgWithSavepoint :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m) => m a -> m a -- | Wrapper for withTransactionMode: Execute an action inside a SQL -- transaction with a given transaction mode. pgWithTransactionMode :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m) => TransactionMode -> m a -> m a -- | Wrapper for withTransactionModeRetry: Like -- pgWithTransactionMode, but also takes a custom callback to -- determine if a transaction should be retried if an SqlError occurs. If -- the callback returns True, then the transaction will be retried. If -- the callback returns False, or an exception other than an SqlError -- occurs then the transaction will be rolled back and the exception -- rethrown. pgWithTransactionModeRetry :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m) => TransactionMode -> (SqlError -> Bool) -> m a -> m a -- | Wrapper for withTransactionSerializable: Execute an action -- inside of a Serializable transaction. If a serialization -- failure occurs, roll back the transaction and try again. Be warned -- that this may execute the IO action multiple times. -- -- A Serializable transaction creates the illusion that your program has -- exclusive access to the database. This means that, even in a -- concurrent setting, you can perform queries in sequence without having -- to worry about what might happen between one statement and the next. pgWithTransactionSerializable :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m) => m a -> m a -- | Perform repsert of the same row, first trying "update where" then -- "insert" with concatenated fields. Which means that if you run -- --
-- pgRepsertRow "emails" (MR [("user_id", mkValue uid)]) (MR [("email", mkValue email)])
--
--
-- Then firstly will be performed
--
-- -- UPDATE "emails" SET email = 'foo@bar.com' WHERE "user_id" = 1234 ---- -- And if no one row is affected (which is returned by pgExecute), -- then -- --
-- INSERT INTO "emails" ("user_id", "email") VALUES (1234, 'foo@bar.com')
--
--
-- will be performed
pgRepsertRow :: (MonadPostgres m, MonadLogger m, ToMarkedRow wrow, ToMarkedRow urow) => FN -> wrow -> urow -> m ()
module Database.PostgreSQL.Query.Entity.Internal
-- | Build entity fields
--
--
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> runSqlBuilder con $ entityFields id id (Proxy :: Proxy Foo)
-- "\"name\", \"size\""
--
--
--
-- >>> runSqlBuilder con $ entityFields ("id":) id (Proxy :: Proxy Foo)
-- "\"id\", \"name\", \"size\""
--
--
--
-- >>> runSqlBuilder con $ entityFields (\l -> ("id":l) ++ ["created"]) id (Proxy :: Proxy Foo)
-- "\"id\", \"name\", \"size\", \"created\""
--
--
--
-- >>> runSqlBuilder con $ entityFields id ("f"<>) (Proxy :: Proxy Foo)
-- "\"f\".\"name\", \"f\".\"size\""
--
--
--
-- >>> runSqlBuilder con $ entityFields ("f.id":) ("f"<>) (Proxy :: Proxy Foo)
-- "\"f\".\"id\", \"f\".\"name\", \"f\".\"size\""
--
entityFields :: (Entity a) => ([FN] -> [FN]) -> (FN -> FN) -> Proxy a -> SqlBuilder
-- | Same as entityFields but prefixes list of names with id
-- field. This is shorthand function for often usage.
--
--
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> runSqlBuilder con $ entityFieldsId id (Proxy :: Proxy Foo)
-- "\"id\", \"name\", \"size\""
--
--
--
-- >>> runSqlBuilder con $ entityFieldsId ("f"<>) (Proxy :: Proxy Foo)
-- "\"f\".\"id\", \"f\".\"name\", \"f\".\"size\""
--
entityFieldsId :: (Entity a) => (FN -> FN) -> Proxy a -> SqlBuilder
-- | Generate SELECT query string for entity
--
--
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> runSqlBuilder con $ selectEntity (entityFieldsId id) (Proxy :: Proxy Foo)
-- "SELECT \"id\", \"name\", \"size\" FROM \"foo\""
--
--
--
-- >>> runSqlBuilder con $ selectEntity (entityFieldsId ("f"<>)) (Proxy :: Proxy Foo)
-- "SELECT \"f\".\"id\", \"f\".\"name\", \"f\".\"size\" FROM \"foo\""
--
--
-- -- >>> runSqlBuilder con $ selectEntity (entityFields id id) (Proxy :: Proxy Foo) -- "SELECT \"name\", \"size\" FROM \"foo\"" --selectEntity :: (Entity a) => (Proxy a -> SqlBuilder) -> Proxy a -> SqlBuilder -- | Generates SELECT FROM WHERE query with most used conditions -- --
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR []
-- "SELECT \"name\", \"size\" FROM \"foo\""
--
--
--
-- >>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR [("name", mkValue "fooname")]
-- "SELECT \"name\", \"size\" FROM \"foo\" WHERE \"name\" = 'fooname' "
--
--
--
-- >>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR [("name", mkValue "fooname"), ("size", mkValue 10)]
-- "SELECT \"name\", \"size\" FROM \"foo\" WHERE \"name\" = 'fooname' AND \"size\" = 10 "
--
selectEntitiesBy :: (Entity a, ToMarkedRow b) => ([FN] -> [FN]) -> Proxy a -> b -> SqlBuilder
-- | Generates INSERT INTO query for any instance of Entity
-- and ToRow
--
--
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
--
-- >>> runSqlBuilder con $ insertEntity $ Foo "Enterprise" 910
-- "INSERT INTO \"foo\" (\"name\", \"size\") VALUES ('Enterprise', 910)"
--
insertEntity :: forall a. (Entity a, ToRow a) => a -> SqlBuilder
-- | Same as insertEntity but generates query to insert many queries
-- at same time
--
--
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
--
-- >>> runSqlBuilder con $ insertManyEntities $ NL.fromList [Foo "meter" 1, Foo "table" 2, Foo "earth" 151930000000]
-- "INSERT INTO \"foo\" (\"name\",\"size\") VALUES ('meter',1),('table',2),('earth',151930000000)"
--
insertManyEntities :: forall a. (Entity a, ToRow a) => NonEmpty a -> SqlBuilder
-- | Convert entity instance to marked row to perform inserts updates and
-- same stuff
--
--
-- >>> data Foo = Foo { fName :: Text, fSize :: Int }
--
-- >>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
--
-- >>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
--
-- >>> runSqlBuilder con $ mrToBuilder ", " $ entityToMR $ Foo "Enterprise" 610
-- " \"name\" = 'Enterprise' , \"size\" = 610 "
--
entityToMR :: forall a. (Entity a, ToRow a) => a -> MarkedRow
module Database.PostgreSQL.Query.Entity.Functions
-- | Insert new entity and return it's id
pgInsertEntity :: forall a m. (MonadPostgres m, MonadLogger m, Entity a, ToRow a, FromField (EntityId a)) => a -> m (EntityId a)
-- | Insert many entities without returning list of id like
-- pgInsertManyEntitiesId does
pgInsertManyEntities :: forall a m. (Entity a, MonadPostgres m, MonadLogger m, ToRow a) => [a] -> m Int64
-- | Same as pgInsertEntity but insert many entities at one action.
-- Returns list of id's of inserted entities
pgInsertManyEntitiesId :: forall a m. (Entity a, MonadPostgres m, MonadLogger m, ToRow a, FromField (EntityId a)) => [a] -> m [EntityId a]
-- | Select entities as pairs of (id, entity).
--
--
-- handler :: Handler [Ent a]
-- handler = do
-- now <- liftIO getCurrentTime
-- let back = addUTCTime (days (-7)) now
-- pgSelectEntities id
-- [sqlExp|WHERE created BETWEEN #{now} AND #{back}
-- ORDER BY created|]
--
-- handler2 :: Text -> Handler [Ent Foo]
-- handler2 fvalue = do
-- pgSelectEntities ("t"<>)
-- [sqlExp|AS t INNER JOIN table2 AS t2
-- ON t.t2_id = t2.id
-- WHERE t.field = #{fvalue}
-- ORDER BY t2.field2|]
-- -- Here the query will be: SELECT ... FROM tbl AS t INNER JOIN ...
--
pgSelectEntities :: forall m a q. (Functor m, MonadPostgres m, MonadLogger m, Entity a, FromRow a, ToSqlBuilder q, FromField (EntityId a)) => (FN -> FN) -> q -> m [Ent a]
-- | Same as pgSelectEntities but do not select id
pgSelectJustEntities :: forall m a q. (Functor m, MonadPostgres m, MonadLogger m, Entity a, FromRow a, ToSqlBuilder q) => (FN -> FN) -> q -> m [a]
-- | Select entities by condition formed from MarkedRow. Usefull
-- function when you know
pgSelectEntitiesBy :: forall a m b. (Functor m, MonadPostgres m, MonadLogger m, Entity a, ToMarkedRow b, FromRow a, FromField (EntityId a)) => b -> m [Ent a]
-- | Select entity by id
--
-- -- getUser :: EntityId User -> Handler User -- getUser uid = do -- pgGetEntity uid -- >>= maybe notFound return --pgGetEntity :: forall m a. (ToField (EntityId a), Entity a, FromRow a, MonadPostgres m, MonadLogger m, Functor m) => EntityId a -> m (Maybe a) -- | Get entity by some fields constraint -- --
-- getUser :: UserName -> Handler User
-- getUser name = do
-- pgGetEntityBy
-- (MR [("name", mkValue name),
-- ("active", mkValue True)])
-- >>= maybe notFound return
--
--
-- The query here will be like
--
--
-- pgQuery [sqlExp|SELECT id, name, phone ... FROM users WHERE name = {True}|]
--
pgGetEntityBy :: forall m a b. (Entity a, MonadPostgres m, MonadLogger m, ToMarkedRow b, FromField (EntityId a), FromRow a, Functor m) => b -> m (Maybe (Ent a))
-- | Select count of entities with given query
--
--
-- activeUsers :: Handler Integer
-- activeUsers = do
-- pgSelectCount (Proxy :: Proxy User)
-- [sqlExp|WHERE active = #{True}|]
--
--
-- Executes arbitrary query and parses it as entities and their ids
pgQueryEntities :: (ToSqlBuilder q, MonadPostgres m, MonadLogger m, Entity a, FromRow a, FromField (EntityId a)) => q -> m [Ent a]
-- | Delete entity.
--
-- -- rmUser :: EntityId User -> Handler () -- rmUser uid = do -- pgDeleteEntity uid ---- -- Return True if row was actually deleted. pgDeleteEntity :: forall a m. (Entity a, MonadPostgres m, MonadLogger m, ToField (EntityId a), Functor m) => EntityId a -> m Bool -- | Update entity using ToMarkedRow instanced value. Requires -- Proxy while EntityId is not a data type. -- --
-- fixUser :: Text -> EntityId User -> Handler ()
-- fixUser username uid = do
-- pgGetEntity uid
-- >>= maybe notFound run
-- where
-- run user =
-- pgUpdateEntity uid
-- $ MR [("active", mkValue True)
-- ("name", mkValue username)]
--
--
-- Returns True if record was actually updated and False if
-- there was not row with such id (or was more than 1, in fact)
pgUpdateEntity :: forall a b m. (ToMarkedRow b, Entity a, MonadPostgres m, MonadLogger m, ToField (EntityId a), Functor m, Typeable a, Typeable b) => EntityId a -> b -> m Bool
pgSelectCount :: forall m a q. (Entity a, MonadPostgres m, MonadLogger m, ToSqlBuilder q) => Proxy a -> q -> m Integer
module Database.PostgreSQL.Query.Entity
module Database.PostgreSQL.Query
data Connection :: *
-- | Connect with the given username to the given database. Will throw an
-- exception if it cannot connect.
connect :: ConnectInfo -> IO Connection
-- | Default information for setting up a connection.
--
-- Defaults are as follows:
--
--
-- connect defaultConnectInfo { connectHost = "db.example.com" }
--
defaultConnectInfo :: ConnectInfo
-- | Attempt to make a connection based on a libpq connection string. See
-- https://www.postgresql.org/docs/9.5/static/libpq-connect.html#LIBPQ-CONNSTRING
-- for more information. Also note that environment variables also affect
-- parameters not provided, parameters provided as the empty string, and
-- a few other things; see
-- https://www.postgresql.org/docs/9.5/static/libpq-envars.html
-- for details. Here is an example with some of the most commonly used
-- parameters:
--
-- -- host='db.somedomain.com' port=5432 ... ---- -- This attempts to connect to db.somedomain.com:5432. Omitting -- the port will normally default to 5432. -- -- On systems that provide unix domain sockets, omitting the host -- parameter will cause libpq to attempt to connect via unix domain -- sockets. The default filesystem path to the socket is constructed from -- the port number and the DEFAULT_PGSOCKET_DIR constant defined -- in the pg_config_manual.h header file. Connecting via unix -- sockets tends to use the peer authentication method, which is -- very secure and does not require a password. -- -- On Windows and other systems without unix domain sockets, omitting the -- host will default to localhost. -- --
-- ... dbname='postgres' user='postgres' password='secret \' \\ pw' ---- -- This attempts to connect to a database named postgres with -- user postgres and password secret ' \ pw. Backslash -- characters will have to be double-quoted in literal Haskell strings, -- of course. Omitting dbname and user will both -- default to the system username that the client process is running as. -- -- Omitting password will default to an appropriate password -- found in the pgpass file, or no password at all if a matching -- line is not found. See -- https://www.postgresql.org/docs/9.5/static/libpq-pgpass.html -- for more information regarding this file. -- -- As all parameters are optional and the defaults are sensible, the -- empty connection string can be useful for development and exploratory -- use, assuming your system is set up appropriately. -- -- On Unix, such a setup would typically consist of a local postgresql -- server listening on port 5432, as well as a system user, database -- user, and database sharing a common name, with permissions granted to -- the user on the database. -- -- On Windows, in addition you will either need pg_hba.conf to -- specify the use of the trust authentication method for the -- connection, which may not be appropriate for multiuser or production -- machines, or you will need to use a pgpass file with the -- password or md5 authentication methods. -- -- See -- https://www.postgresql.org/docs/9.5/static/client-authentication.html -- for more information regarding the authentication process. -- -- SSL/TLS will typically "just work" if your postgresql server supports -- or requires it. However, note that libpq is trivially vulnerable to a -- MITM attack without setting additional SSL connection parameters. In -- particular, sslmode needs to be set to require, -- verify-ca, or verify-full in order to perform -- certificate validation. When sslmode is require, -- then you will also need to specify a sslrootcert file, -- otherwise no validation of the server's identity will be performed. -- Client authentication via certificates is also possible via the -- sslcert and sslkey parameters. See -- https://www.postgresql.org/docs/9.5/static/libpq-ssl.html for -- detailed information regarding libpq and SSL. connectPostgreSQL :: ByteString -> IO Connection data ConnectInfo :: * ConnectInfo :: String -> Word16 -> String -> String -> String -> ConnectInfo [connectHost] :: ConnectInfo -> String [connectPort] :: ConnectInfo -> Word16 [connectUser] :: ConnectInfo -> String [connectPassword] :: ConnectInfo -> String [connectDatabase] :: ConnectInfo -> String -- | A type that may be used as a single parameter to a SQL query. class ToField a -- | Prepare a value for substitution into a query string. toField :: ToField a => a -> Action -- | A collection type that can be turned into a list of rendering -- Actions. -- -- Instances should use the toField method of the ToField -- class to perform conversion of each element of the collection. class ToRow a toRow :: ToRow a => a -> [Action] -- | A type that may be converted from a SQL type. class FromField a -- | Convert a SQL value to a Haskell value. -- -- Returns a list of exceptions if the conversion fails. In the case of -- library instances, this will usually be a single ResultError, -- but may be a UnicodeException. -- -- Note that retaining any reference to the Field argument causes -- the entire LibPQ.Result to be retained. Thus, -- implementations of fromField should return results that do not -- refer to this value after the result have been evaluated to WHNF. -- -- Note that as of postgresql-simple-0.4.0.0, the -- ByteString value has already been copied out of the -- LibPQ.Result before it has been passed to -- fromField. This is because for short strings, it's cheaper to -- copy the string than to set up a finalizer. fromField :: FromField a => FieldParser a -- | A collection type that can be converted from a sequence of fields. -- Instances are provided for tuples up to 10 elements and lists of any -- length. -- -- Note that instances can be defined outside of postgresql-simple, which -- is often useful. For example, here's an instance for a user-defined -- pair: -- --
-- data User = User { name :: String, fileQuota :: Int }
--
-- instance FromRow User where
-- fromRow = User <$> field <*> field
--
--
-- The number of calls to field must match the number of fields
-- returned in a single row of the query result. Otherwise, a
-- ConversionFailed exception will be thrown.
--
-- Note that field evaluates its result to WHNF, so the caveats
-- listed in mysql-simple and very early versions of postgresql-simple no
-- longer apply. Instead, look at the caveats associated with
-- user-defined implementations of fromField.
class FromRow a
fromRow :: FromRow a => RowParser a
-- | A query string. This type is intended to make it difficult to
-- construct a SQL query by concatenating string fragments, as that is an
-- extremely common way to accidentally introduce SQL injection
-- vulnerabilities into an application.
--
-- This type is an instance of IsString, so the easiest way to
-- construct a query is to enable the OverloadedStrings language
-- extension and then simply write the query in double quotes.
--
--
-- {-# LANGUAGE OverloadedStrings #-}
--
-- import Database.PostgreSQL.Simple
--
-- q :: Query
-- q = "select ?"
--
--
-- The underlying type is a ByteString, and literal Haskell
-- strings that contain Unicode characters will be correctly transformed
-- to UTF-8.
newtype Query :: *
Query :: ByteString -> Query
[fromQuery] :: Query -> ByteString
-- | A single-value "collection".
--
-- This is useful if you need to supply a single parameter to a SQL
-- query, or extract a single column from a SQL result.
--
-- Parameter example:
--
-- -- query c "select x from scores where x > ?" (Only (42::Int)) ---- -- Result example: -- --
-- xs <- query_ c "select id from users"
-- forM_ xs $ \(Only id) -> {- ... -}
--
newtype Only a :: * -> *
Only :: a -> Only a
[fromOnly] :: Only a -> a
-- | Wrap a list of values for use in an IN clause. Replaces a
-- single "?" character with a parenthesized list of rendered
-- values.
--
-- Example:
--
-- -- query c "select * from whatever where id in ?" (Only (In [3,4,5])) ---- -- Note that In [] expands to (null), which works as -- expected in the query above, but evaluates to the logical null value -- on every row instead of TRUE. This means that changing the -- query above to ... id NOT in ? and supplying the empty list -- as the parameter returns zero rows, instead of all of them as one -- would expect. -- -- Since postgresql doesn't seem to provide a syntax for actually -- specifying an empty list, which could solve this completely, there are -- two workarounds particularly worth mentioning, namely: -- --
query c "select * from -- whatever where id not in ?" (Only (Values ["int4"] [] :: Values (Only -- Int)))
query c "select * from whatever -- where coalesce(id NOT in ?, TRUE)" (Only (In [] :: In -- [Int]))
query c "select * from whatever where coalesce(id IN -- ?, FALSE)" (Only (In [] :: In [Int]))Note that at as of -- PostgreSQL 9.4, the query planner cannot see inside the -- COALESCE operator, so if you have an index on id -- then you probably don't want to write the last example with -- COALESCE, which would result in a table scan. There are -- further caveats if id can be null or you want null treated -- sensibly as a component of IN or NOT IN.
-- query c [sql|
-- WITH new_thing AS (
-- INSERT INTO thing (name) VALUES (?) RETURNING id
-- ), new_attributes AS (
-- INSERT INTO thing_attributes
-- SELECT new_thing.id, attrs.*
-- FROM new_thing JOIN ? attrs ON TRUE
-- ) SELECT * FROM new_thing
-- |] ("foo", Values [ "int4", "text" ]
-- [ ( 1 , "hello" )
-- , ( 2 , "world" ) ])
--
--
-- (Note this example uses writable common table expressions, which were
-- added in PostgreSQL 9.1)
--
-- The second parameter gets expanded into the following SQL syntax:
--
-- -- (VALUES (1::"int4",'hello'::"text"),(2,'world')) ---- -- When the list of attributes is empty, the second parameter expands to: -- --
-- (VALUES (null::"int4",null::"text") LIMIT 0) ---- -- By contrast, executeMany and returning don't issue -- the query in the empty case, and simply return 0 and -- [] respectively. This behavior is usually correct given their -- intended use cases, but would certainly be wrong in the example above. -- -- The first argument is a list of postgresql type names. Because this is -- turned into a properly quoted identifier, the type name is case -- sensitive and must be as it appears in the pg_type table. -- Thus, you must write timestamptz instead of timestamp -- with time zone, int4 instead of integer or -- serial, _int8 instead of bigint[], -- etcetera. -- -- You may omit the type names, however, if you do so the list of values -- must be non-empty, and postgresql must be able to infer the types of -- the columns from the surrounding context. If the first condition is -- not met, postgresql-simple will throw an exception without issuing the -- query. In the second case, the postgres server will return an error -- which will be turned into a SqlError exception. -- -- See https://www.postgresql.org/docs/9.5/static/sql-values.html -- for more information. data Values a :: * -> * Values :: [QualifiedIdentifier] -> [a] -> Values a -- | A composite type to parse your custom data structures without having -- to define dummy newtype wrappers every time. -- --
-- instance FromRow MyData where ... ---- --
-- instance FromRow MyData2 where ... ---- -- then I can do the following for free: -- --
-- res <- query' c "..."
-- forM res $ \(MyData{..} :. MyData2{..}) -> do
-- ....
--
data (:.) h t :: * -> * -> *
(:.) :: h -> t -> (:.) h t
-- | Wrap a list for use as a PostgreSQL array.
newtype PGArray a :: * -> *
PGArray :: [a] -> PGArray a
[fromPGArray] :: PGArray a -> [a]
newtype HStoreList :: *
HStoreList :: [(Text, Text)] -> HStoreList
[fromHStoreList] :: HStoreList -> [(Text, Text)]
newtype HStoreMap :: *
HStoreMap :: Map Text Text -> HStoreMap
[fromHStoreMap] :: HStoreMap -> Map Text Text
class ToHStore a
toHStore :: ToHStore a => a -> HStoreBuilder
-- | Represents valid hstore syntax.
data HStoreBuilder :: *
hstore :: (ToHStoreText a, ToHStoreText b) => a -> b -> HStoreBuilder
parseHStoreList :: ByteString -> Either String HStoreList
class ToHStoreText a
toHStoreText :: ToHStoreText a => a -> HStoreText
-- | Represents escape text, ready to be the key or value to a hstore value
data HStoreText :: *