persistent-2.18.1.0: Database/Persist/SqlBackend.hs
-- | This module contains types and information necessary for a SQL database.
-- Database support libraries, like @persistent-postgresql@, will be responsible
-- for constructing these values.
module Database.Persist.SqlBackend
( -- * The type and construction
SqlBackend
, mkSqlBackend
, MkSqlBackendArgs (..)
, SqlBackendHooks
, emptySqlBackendHooks
-- * Utilities
-- $utilities
-- ** SqlBackend Getters
, getRDBMS
, getEscapedFieldName
, getEscapedRawName
, getEscapeRawNameFunction
, getConnLimitOffset
, getConnUpsertSql
, getConnVault
, getConnHooks
-- ** SqlBackend Setters
, setConnMaxParams
, setConnRepsertManySql
, setConnInsertManySql
, setConnUpsertSql
, setConnPutManySql
, setConnVault
, modifyConnVault
, setConnHooks
-- ** SqlBackendHooks
) where
import Control.Monad.Reader
import Data.List.NonEmpty (NonEmpty)
import Data.Text (Text)
import Data.Vault.Strict (Vault)
import Database.Persist.Class.PersistStore (BackendCompatible (..))
import Database.Persist.Names
import Database.Persist.SqlBackend.Internal
import qualified Database.Persist.SqlBackend.Internal as SqlBackend
( SqlBackend (..)
)
import Database.Persist.SqlBackend.Internal.InsertSqlResult
import Database.Persist.SqlBackend.Internal.MkSqlBackend as Mk
( MkSqlBackendArgs (..)
)
import Database.Persist.Types.Base
-- $utilities
--
-- The functions exported here are a bit more general than the record accessors.
-- The easiest way to use them is to provide the 'SqlBackend' directly to the
-- function. However, you can also use them in a 'ReaderT' context, and you can
-- even use them with any @backend@ type tht has a @'BackendCompatible'
-- 'SqlBackend' backend@ instance.
-- | This function can be used directly with a 'SqlBackend' to escape
-- a 'FieldNameDB'.
--
-- @
-- let conn :: SqlBackend
-- getEscapedFieldName (FieldNameDB "asdf") conn
-- @
--
-- Alternatively, you can use it in a @'ReaderT' 'SqlBackend'@ context, like
-- 'SqlPersistT':
--
-- @
-- query :: SqlPersistM Text
-- query = do
-- field <- getEscapedFieldName (FieldNameDB "asdf")
-- pure field
-- @
--
-- @since 2.13.0.0
getEscapedFieldName
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> FieldNameDB -> m Text
getEscapedFieldName fieldName = do
func <- asks (SqlBackend.connEscapeFieldName . projectBackend)
pure (func fieldName)
-- | This function can be used directly with a 'SqlBackend' to escape
-- a raw 'Text'.
--
-- @
-- let conn :: SqlBackend
-- getEscapedRawName (FieldNameDB "asdf") conn
-- @
--
-- Alternatively, you can use it in a @'ReaderT' 'SqlBackend'@ context, like
-- 'SqlPersistT':
--
-- @
-- query :: SqlPersistM Text
-- query = do
-- field <- getEscapedRawName (FieldNameDB "asdf")
-- pure field
-- @
--
-- @since 2.13.0.0
getEscapedRawName
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> Text -> m Text
getEscapedRawName name = do
func <- getEscapeRawNameFunction
pure (func name)
-- | Return the function for escaping a raw name.
--
-- @since 2.13.0.0
getEscapeRawNameFunction
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> m (Text -> Text)
getEscapeRawNameFunction = do
asks (SqlBackend.connEscapeRawName . projectBackend)
-- | Decorate the given SQL query with the @(LIMIT, OFFSET)@ specified.
--
-- @since 2.13.0.0
getConnLimitOffset
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> (Int, Int)
-- ^ The @(LIMIT, OFFSET)@ to put on the query.
-> Text
-- ^ The SQL query that the LIMIT/OFFSET clause will be attached to.
-> m Text
getConnLimitOffset limitOffset sql = do
func <- asks (SqlBackend.connLimitOffset . projectBackend)
pure $ func limitOffset sql
-- | Retrieve the function for generating an upsert statement, if the backend
-- supports it.
--
-- @since 2.13.0.0
getConnUpsertSql
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> m (Maybe (EntityDef -> NonEmpty (FieldNameHS, FieldNameDB) -> Text -> Text))
getConnUpsertSql = do
asks (SqlBackend.connUpsertSql . projectBackend)
-- | Retrieve the vault from the provided database backend.
--
-- @since 2.13.3.0
getConnVault
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> m Vault
getConnVault = do
asks (SqlBackend.connVault . projectBackend)
-- | Retrieve instrumentation hooks from the provided database backend.
--
-- @since 2.13.3.0
getConnHooks
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> m SqlBackendHooks
getConnHooks = do
asks (SqlBackend.connHooks . projectBackend)
-- | Get a tag displaying what database the 'SqlBackend' is for. Can be
-- used to differentiate features in downstream libraries for different
-- database backends.
-- @since 2.13.3.0
getRDBMS
:: (BackendCompatible SqlBackend backend, MonadReader backend m)
=> m Text
getRDBMS = do
asks (SqlBackend.connRDBMS . projectBackend)
-- | Set the maximum parameters that may be issued in a given SQL query. This
-- should be used only if the database backend have this limitation.
--
-- @since 2.13.0.0
setConnMaxParams
:: Int
-> SqlBackend
-> SqlBackend
setConnMaxParams i sb =
sb{connMaxParams = Just i}
-- | Set the 'connRepsertManySql' field on the 'SqlBackend'. This should only be
-- set by the database backend library. If this is not set, a slow default will
-- be used.
--
-- @since 2.13.0.0
setConnRepsertManySql
:: (EntityDef -> Int -> Text)
-> SqlBackend
-> SqlBackend
setConnRepsertManySql mkQuery sb =
sb{connRepsertManySql = Just mkQuery}
-- | Set the 'connInsertManySql' field on the 'SqlBackend'. This should only be
-- used by the database backend library to provide an efficient implementation
-- of a bulk insert function. If this is not set, a slow default will be used.
--
-- @since 2.13.0.0
setConnInsertManySql
:: (EntityDef -> [[PersistValue]] -> InsertSqlResult)
-> SqlBackend
-> SqlBackend
setConnInsertManySql mkQuery sb =
sb{connInsertManySql = Just mkQuery}
-- | Set the 'connUpsertSql' field on the 'SqlBackend'. This should only be used
-- by the database backend library to provide an efficient implementation of
-- a bulk insert function. If this is not set, a slow default will be used.
--
-- @since 2.13.0.0
setConnUpsertSql
:: (EntityDef -> NonEmpty (FieldNameHS, FieldNameDB) -> Text -> Text)
-> SqlBackend
-> SqlBackend
setConnUpsertSql mkQuery sb =
sb{connUpsertSql = Just mkQuery}
-- | Set the 'connPutManySql field on the 'SqlBackend'. This should only be used
-- by the database backend library to provide an efficient implementation of
-- a bulk insert function. If this is not set, a slow default will be used.
--
-- @since 2.13.0.0
setConnPutManySql
:: (EntityDef -> Int -> Text)
-> SqlBackend
-> SqlBackend
setConnPutManySql mkQuery sb =
sb{connPutManySql = Just mkQuery}
-- | Set the vault on the provided database backend.
--
-- @since 2.13.0
setConnVault :: Vault -> SqlBackend -> SqlBackend
setConnVault vault sb =
sb{connVault = vault}
-- | Modify the vault on the provided database backend.
--
-- @since 2.13.0
modifyConnVault :: (Vault -> Vault) -> SqlBackend -> SqlBackend
modifyConnVault f sb =
sb{connVault = f $ connVault sb}
-- | Set hooks on the provided database backend.
--
-- @since 2.13.0
setConnHooks :: SqlBackendHooks -> SqlBackend -> SqlBackend
setConnHooks hooks sb =
sb{connHooks = hooks}