packages feed

persistent 2.13.2.2 → 2.13.3.0

raw patch · 13 files changed

+378/−53 lines, 13 filesdep +vaultdep ~mtl

Dependencies added: vault

Dependency ranges changed: mtl

Files

ChangeLog.md view
@@ -1,5 +1,13 @@ # Changelog for persistent +## 2.13.3.0++* [#1341](https://github.com/yesodweb/persistent/pull/1341)+    * Add `SqlBackendHooks` to allow for instrumentation of queries.+* [#1327](https://github.com/yesodweb/persistent/pull/1327)+    * Update `SqlBackend` to use new `StatementCache` interface+      instead of `IORef (Map Text Statement)`+ ## 2.13.2.2  * [#1351](https://github.com/yesodweb/persistent/pull/1351/)
Database/Persist/Sql/Raw.hs view
@@ -1,23 +1,23 @@ module Database.Persist.Sql.Raw where  import Control.Exception (throwIO)-import Control.Monad (when, liftM)+import Control.Monad (liftM, when) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Logger (logDebugNS, runLoggingT)-import Control.Monad.Reader (ReaderT, ask, MonadReader)-import Control.Monad.Trans.Resource (MonadResource,release)-import Data.Acquire (allocateAcquire, Acquire, mkAcquire, with)+import Control.Monad.Reader (MonadReader, ReaderT, ask)+import Control.Monad.Trans.Resource (MonadResource, release)+import Data.Acquire (Acquire, allocateAcquire, mkAcquire, with) import Data.Conduit-import Data.IORef (writeIORef, readIORef, newIORef)-import qualified Data.Map as Map+import Data.IORef (newIORef, readIORef, writeIORef) import Data.Int (Int64) import Data.Text (Text, pack) import qualified Data.Text as T  import Database.Persist+import Database.Persist.Sql.Class import Database.Persist.Sql.Types import Database.Persist.Sql.Types.Internal-import Database.Persist.Sql.Class+import Database.Persist.SqlBackend.Internal.StatementCache  rawQuery :: (MonadResource m, MonadReader env m, BackendCompatible SqlBackend env)          => Text@@ -75,9 +75,10 @@  getStmtConn :: SqlBackend -> Text -> IO Statement getStmtConn conn sql = do-    smap <- liftIO $ readIORef $ connStmtMap conn-    case Map.lookup sql smap of-        Just stmt -> return stmt+    let cacheK = mkCacheKeyFromQuery sql+    mstmt <- statementCacheLookup (connStmtMap conn) cacheK+    stmt <- case mstmt of+        Just stmt -> pure stmt         Nothing -> do             stmt' <- liftIO $ connPrepare conn sql             iactive <- liftIO $ newIORef True@@ -100,8 +101,10 @@                             then stmtQuery stmt' x                             else liftIO $ throwIO $ StatementAlreadyFinalized sql                     }-            liftIO $ writeIORef (connStmtMap conn) $ Map.insert sql stmt smap-            return stmt++            liftIO $ statementCacheInsert (connStmtMap conn) cacheK stmt+            pure stmt+    (hookGetStatement $ connHooks conn) conn sql stmt  -- | Execute a raw SQL statement and return its results as a -- list. If you do not expect a return value, use of
Database/Persist/Sql/Run.hs view
@@ -1,23 +1,25 @@ {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-} module Database.Persist.Sql.Run where  import Control.Monad.IO.Unlift-import qualified UnliftIO.Exception as UE import Control.Monad.Logger.CallStack-import Control.Monad.Reader (MonadReader)+import Control.Monad.Reader (MonadReader, void) import qualified Control.Monad.Reader as MonadReader import Control.Monad.Trans.Reader hiding (local) import Control.Monad.Trans.Resource import Data.Acquire (Acquire, ReleaseType(..), mkAcquireType, with)-import Data.IORef (readIORef) import Data.Pool as P-import qualified Data.Map as Map import qualified Data.Text as T+import qualified UnliftIO.Exception as UE  import Database.Persist.Class.PersistStore+import Database.Persist.Sql.Raw import Database.Persist.Sql.Types import Database.Persist.Sql.Types.Internal-import Database.Persist.Sql.Raw+import Database.Persist.SqlBackend.Internal.StatementCache+import Database.Persist.SqlBackend.Internal.SqlPoolHooks  -- | Get a connection from the pool, run the given action, and then return the -- connection to the pool.@@ -93,15 +95,36 @@     -- cleanup function is complete.     -> m a runSqlPoolWithHooks r pconn i before after onException =+    runSqlPoolWithExtensibleHooks r pconn i $ SqlPoolHooks+        { alterBackend = pure+        , runBefore = \conn _ -> void $ before conn+        , runAfter = \conn _ -> void $ after conn+        , runOnException = \b _ e -> void $ onException b e+        }++-- | This function is how 'runSqlPoolWithHooks' is defined.+--+-- It's currently the most general function for using a SQL pool.+--+-- @since 2.13.0.0+runSqlPoolWithExtensibleHooks+    :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend)+    => ReaderT backend m a+    -> Pool backend+    -> Maybe IsolationLevel+    -> SqlPoolHooks m backend+    -> m a+runSqlPoolWithExtensibleHooks r pconn i SqlPoolHooks{..} =     withRunInIO $ \runInIO ->     withResource pconn $ \conn ->     UE.mask $ \restore -> do-        _ <- restore $ runInIO $ before conn-        a <- restore (runInIO (runReaderT r conn))+        conn' <- restore $ runInIO $ alterBackend conn+        _ <- restore $ runInIO $ runBefore conn' i+        a <- restore (runInIO (runReaderT r conn'))             `UE.catchAny` \e -> do-                _ <- restore $ runInIO $ onException conn e+                _ <- restore $ runInIO $ runOnException conn' i e                 UE.throwIO e-        _ <- restore $ runInIO $ after conn+        _ <- restore $ runInIO $ runAfter conn' i         pure a  rawAcquireSqlConn@@ -296,5 +319,6 @@  close' :: (BackendCompatible SqlBackend backend) => backend -> IO () close' conn = do-    readIORef (connStmtMap $ projectBackend conn) >>= mapM_ stmtFinalize . Map.elems-    connClose $ projectBackend conn+    let backend = projectBackend conn+    statementCacheClear $ connStmtMap backend+    connClose backend
Database/Persist/Sql/Types.hs view
@@ -12,9 +12,8 @@ import Control.Monad.Logger (NoLoggingT) import Control.Monad.Trans.Reader (ReaderT(..)) import Control.Monad.Trans.Resource (ResourceT)-import Control.Monad.Trans.Writer (WriterT) import Data.Pool (Pool)-import Data.Text (Text, unpack)+import Data.Text (Text)  import Data.Time (NominalDiffTime) import Database.Persist.Sql.Types.Internal
Database/Persist/Sql/Types/Internal.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE RankNTypes #-}-{-# language RecordWildCards #-}-{-# language DuplicateRecordFields #-}+{-# LANGUAGE RecordWildCards #-}  -- | Breaking changes to this module are not reflected in the major version -- number. Prefer to import from "Database.Persist.Sql" instead. If you neeed@@ -25,24 +25,28 @@     , SqlReadT     , SqlWriteT     , IsSqlBackend+    , SqlBackendHooks (..)     ) where  import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.Reader (ReaderT, runReaderT, ask)+import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)  import Database.Persist.Class-    ( HasPersistBackend (..)-    , PersistQueryRead, PersistQueryWrite-    , PersistStoreRead, PersistStoreWrite-    , PersistUniqueRead, PersistUniqueWrite-    , BackendCompatible(..)-    )-import Database.Persist.Class.PersistStore (IsPersistBackend (..))+       ( BackendCompatible(..)+       , HasPersistBackend(..)+       , PersistQueryRead+       , PersistQueryWrite+       , PersistStoreRead+       , PersistStoreWrite+       , PersistUniqueRead+       , PersistUniqueWrite+       )+import Database.Persist.Class.PersistStore (IsPersistBackend(..)) import Database.Persist.SqlBackend.Internal import Database.Persist.SqlBackend.Internal.InsertSqlResult+import Database.Persist.SqlBackend.Internal.IsolationLevel import Database.Persist.SqlBackend.Internal.MkSqlBackend import Database.Persist.SqlBackend.Internal.Statement-import Database.Persist.SqlBackend.Internal.IsolationLevel  -- | An SQL backend which can only handle read queries --
Database/Persist/SqlBackend.hs view
@@ -6,35 +6,46 @@       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.MkSqlBackend as Mk (MkSqlBackendArgs(..))-import Database.Persist.Types.Base-import Database.Persist.Names import Database.Persist.SqlBackend.Internal.InsertSqlResult-import Data.List.NonEmpty (NonEmpty)+import Database.Persist.SqlBackend.Internal.MkSqlBackend as Mk+       (MkSqlBackendArgs(..))+import Database.Persist.Types.Base  -- $utilities --@@ -129,7 +140,35 @@ 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. --@@ -188,3 +227,24 @@     -> 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 }
Database/Persist/SqlBackend/Internal.hs view
@@ -1,19 +1,21 @@-{-# language RecordWildCards #-}-{-# language RankNTypes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}  module Database.Persist.SqlBackend.Internal where -import Data.Map (Map) import Data.List.NonEmpty (NonEmpty) import Data.Text (Text)+import Data.Vault.Strict (Vault)+import qualified Data.Vault.Strict as Vault import Database.Persist.Class.PersistStore-import Database.Persist.Types.Base import Database.Persist.Names-import Data.IORef-import Database.Persist.SqlBackend.Internal.MkSqlBackend-import Database.Persist.SqlBackend.Internal.Statement import Database.Persist.SqlBackend.Internal.InsertSqlResult import Database.Persist.SqlBackend.Internal.IsolationLevel+import Database.Persist.SqlBackend.Internal.MkSqlBackend+import Database.Persist.SqlBackend.Internal.Statement+import Database.Persist.SqlBackend.Internal.StatementCache (StatementCache)+import Database.Persist.SqlBackend.StatementCache+import Database.Persist.Types.Base  -- | A 'SqlBackend' represents a handle or connection to a database. It -- contains functions and values that allow databases to have more@@ -69,7 +71,7 @@     -- When left as 'Nothing', we default to using 'defaultPutMany'.     --     -- @since 2.8.1-    , connStmtMap :: IORef (Map Text Statement)+    , connStmtMap :: StatementCache     -- ^ A reference to the cache of statements. 'Statement's are keyed by     -- the 'Text' queries that generated them.     , connClose :: IO ()@@ -132,8 +134,23 @@     -- When left as 'Nothing', we default to using 'defaultRepsertMany'.     --     -- @since 2.9.0+    , connVault :: Vault+    -- ^ Carry arbitrary payloads for the connection that+    -- may be used to propagate information into hooks.+    , connHooks :: SqlBackendHooks+    -- ^ Instrumentation hooks that may be used to track the+    -- behaviour of a backend.     } +newtype SqlBackendHooks = SqlBackendHooks+    { hookGetStatement :: SqlBackend -> Text -> Statement -> IO Statement+    }++emptySqlBackendHooks :: SqlBackendHooks+emptySqlBackendHooks = SqlBackendHooks+    { hookGetStatement = \_ _ s -> pure s+    }+ -- | A function for creating a value of the 'SqlBackend' type. You should prefer -- to use this instead of the constructor for 'SqlBackend', because default -- values for this will be provided for new fields on the record when new@@ -148,6 +165,9 @@         , connPutManySql = Nothing         , connUpsertSql = Nothing         , connInsertManySql = Nothing+        , connVault = Vault.empty+        , connHooks = emptySqlBackendHooks+        , connStmtMap = mkStatementCache $ mkSimpleStatementCache connStmtMap         , ..         } 
Database/Persist/SqlBackend/Internal/MkSqlBackend.hs view
@@ -3,14 +3,14 @@ module Database.Persist.SqlBackend.Internal.MkSqlBackend where  import Control.Monad.Logger (Loc, LogLevel, LogSource, LogStr)-import Data.IORef-import Data.Map (Map) import Data.Text (Text)-import Database.Persist.SqlBackend.Internal.Statement+import Database.Persist.Names import Database.Persist.SqlBackend.Internal.InsertSqlResult import Database.Persist.SqlBackend.Internal.IsolationLevel+import Database.Persist.SqlBackend.Internal.Statement import Database.Persist.Types.Base-import Database.Persist.Names+import Data.Map (Map)+import Data.IORef (IORef)  -- | This type shares many of the same field names as the 'SqlBackend' type. -- It's useful for library authors to use this when migrating from using the
+ Database/Persist/SqlBackend/Internal/SqlPoolHooks.hs view
@@ -0,0 +1,21 @@+module Database.Persist.SqlBackend.Internal.SqlPoolHooks+  ( SqlPoolHooks(..)+  ) where+import Control.Exception (SomeException)+import Database.Persist.SqlBackend.Internal.IsolationLevel++-- | A set of hooks that may be used to alter the behaviour+-- of @runSqlPoolWithExtensibleHooks@ in a backwards-compatible+-- fashion.+data SqlPoolHooks m backend = SqlPoolHooks+    { alterBackend :: backend -> m backend+    -- ^ Alter the backend prior to executing any actions with it.+    , runBefore :: backend -> Maybe IsolationLevel -> m ()+    -- ^ Run this action immediately before the action is performed.+    , runAfter :: backend -> Maybe IsolationLevel -> m ()+    -- ^ Run this action immediately after the action is completed.+    , runOnException :: backend -> Maybe IsolationLevel -> SomeException -> m ()+    -- ^ This action is performed when an exception is received. The+    -- exception is provided as a convenience - it is rethrown once this+    -- cleanup function is complete.+    }
+ Database/Persist/SqlBackend/Internal/StatementCache.hs view
@@ -0,0 +1,23 @@+module Database.Persist.SqlBackend.Internal.StatementCache where++import Data.Text (Text)+import Database.Persist.SqlBackend.Internal.Statement++-- | A statement cache used to lookup statements that have already been prepared+-- for a given query.+--+-- @since 2.13.3+data StatementCache = StatementCache+    { statementCacheLookup :: StatementCacheKey -> IO (Maybe Statement)+    , statementCacheInsert :: StatementCacheKey -> Statement -> IO ()+    , statementCacheClear :: IO ()+    , statementCacheSize :: IO Int+    }++newtype StatementCacheKey = StatementCacheKey { cacheKey :: Text }+-- Wrapping around this to allow for more efficient keying mechanisms+-- in the future, perhaps.++-- | Construct a `StatementCacheKey` from a raw SQL query.+mkCacheKeyFromQuery :: Text -> StatementCacheKey+mkCacheKeyFromQuery = StatementCacheKey
+ Database/Persist/SqlBackend/SqlPoolHooks.hs view
@@ -0,0 +1,92 @@+module Database.Persist.SqlBackend.SqlPoolHooks+  ( SqlPoolHooks+  , defaultSqlPoolHooks+  , getAlterBackend+  , modifyAlterBackend+  , setAlterBackend+  , getRunBefore+  , modifyRunBefore+  , setRunBefore+  , getRunAfter+  , modifyRunAfter+  , setRunAfter+  , getRunOnException+  )+  where++import Control.Exception+import Control.Monad.IO.Class+import Database.Persist.Sql.Raw+import Database.Persist.SqlBackend.Internal+import Database.Persist.SqlBackend.Internal.SqlPoolHooks+import Database.Persist.SqlBackend.Internal.IsolationLevel+import Database.Persist.Class.PersistStore++-- | Lifecycle hooks that may be altered to extend SQL pool behavior+-- in a backwards compatible fashion.+--+-- By default, the hooks have the following semantics:+--+-- - 'alterBackend' has no effect+-- - 'runBefore' begins a transaction+-- - 'runAfter' commits the current transaction+-- - 'runOnException' rolls back the current transaction+--+-- @since 2.13.3.0+defaultSqlPoolHooks :: (MonadIO m, BackendCompatible SqlBackend backend) => SqlPoolHooks m backend+defaultSqlPoolHooks = SqlPoolHooks+    { alterBackend = pure+    , runBefore = \conn mi -> do+        let sqlBackend = projectBackend conn+        let getter = getStmtConn sqlBackend+        liftIO $ connBegin sqlBackend getter mi+    , runAfter = \conn _ -> do+        let sqlBackend = projectBackend conn+        let getter = getStmtConn sqlBackend+        liftIO $ connCommit sqlBackend getter+    , runOnException = \conn _ _ -> do+        let sqlBackend = projectBackend conn+        let getter = getStmtConn sqlBackend+        liftIO $ connRollback sqlBackend getter+    }++getAlterBackend :: SqlPoolHooks m backend -> (backend -> m backend)+getAlterBackend = alterBackend++modifyAlterBackend :: SqlPoolHooks m backend -> ((backend -> m backend) -> (backend -> m backend)) -> SqlPoolHooks m backend+modifyAlterBackend hooks f = hooks { alterBackend = f $ alterBackend hooks }++setAlterBackend :: SqlPoolHooks m backend -> (backend -> m backend) -> SqlPoolHooks m backend+setAlterBackend hooks f = hooks { alterBackend = f }+++getRunBefore :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ())+getRunBefore = runBefore++modifyRunBefore :: SqlPoolHooks m backend -> ((backend -> Maybe IsolationLevel -> m ()) -> (backend -> Maybe IsolationLevel -> m ())) -> SqlPoolHooks m backend+modifyRunBefore hooks f = hooks { runBefore = f $ runBefore hooks }++setRunBefore :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ()) -> SqlPoolHooks m backend+setRunBefore h f = h { runBefore = f }+++getRunAfter :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ())+getRunAfter = runAfter++modifyRunAfter :: SqlPoolHooks m backend -> ((backend -> Maybe IsolationLevel -> m ()) -> (backend -> Maybe IsolationLevel -> m ())) -> SqlPoolHooks m backend+modifyRunAfter hooks f = hooks { runAfter = f $ runAfter hooks }++setRunAfter :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ()) -> SqlPoolHooks m backend+setRunAfter hooks f = hooks { runAfter = f }+++getRunOnException :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> SomeException -> m ())+getRunOnException = runOnException++modifyRunOnException :: SqlPoolHooks m backend -> ((backend -> Maybe IsolationLevel -> SomeException -> m ()) -> (backend -> Maybe IsolationLevel -> SomeException -> m ())) -> SqlPoolHooks m backend+modifyRunOnException hooks f = hooks { runOnException = f $ runOnException hooks }++setRunOnException :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> SomeException -> m ()) -> SqlPoolHooks m backend+setRunOnException hooks f = hooks { runOnException = f }++
+ Database/Persist/SqlBackend/StatementCache.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE RecordWildCards #-}+module Database.Persist.SqlBackend.StatementCache+  ( StatementCache+  , StatementCacheKey+  , mkCacheKeyFromQuery+  , MkStatementCache(..)+  , mkSimpleStatementCache+  , mkStatementCache+  ) where++import Data.Foldable+import Data.IORef+import qualified Data.Map as Map+import Database.Persist.SqlBackend.Internal.Statement+import Database.Persist.SqlBackend.Internal.StatementCache+import Data.Map (Map)+import Data.Text (Text)++-- | Configuration parameters for creating a custom statement cache+--+-- @since 2.13.3+data MkStatementCache = MkStatementCache+    { statementCacheLookup :: StatementCacheKey -> IO (Maybe Statement)+    -- ^ Retrieve a statement from the cache, or return nothing if it is not found.+    --+    -- @since 2.13.3+    , statementCacheInsert :: StatementCacheKey -> Statement -> IO ()+    -- ^ Put a new statement into the cache. An immediate lookup of+    -- the statement MUST return the inserted statement for the given+    -- cache key. Depending on the implementation, the statement cache MAY+    -- choose to evict other statements from the cache within this function.+    --+    -- @since 2.13.3+    , statementCacheClear :: IO ()+    -- ^ Remove all statements from the cache. Implementations of this+    -- should be sure to call `stmtFinalize` on all statements removed+    -- from the cache.+    --+    -- @since 2.13.3+    , statementCacheSize :: IO Int+    -- ^ Get the current size of the cache.+    --+    -- @since 2.13.3+    }+++-- | Make a simple statement cache that will cache statements if they are not currently cached.+--+-- @since 2.13.3+mkSimpleStatementCache :: IORef (Map Text Statement) -> MkStatementCache+mkSimpleStatementCache stmtMap =+    MkStatementCache+        { statementCacheLookup = \sql -> Map.lookup (cacheKey sql) <$> readIORef stmtMap+        , statementCacheInsert = \sql stmt ->+            modifyIORef' stmtMap (Map.insert (cacheKey sql) stmt)+        , statementCacheClear = do+            oldStatements <- atomicModifyIORef' stmtMap (\oldStatements -> (Map.empty, oldStatements))+            traverse_ stmtFinalize oldStatements+        , statementCacheSize = Map.size <$> readIORef stmtMap+        }++-- | Create a statement cache.+--+-- @since 2.13.0+mkStatementCache :: MkStatementCache -> StatementCache+mkStatementCache MkStatementCache{..} = StatementCache { .. }
persistent.cabal view
@@ -1,5 +1,5 @@ name:            persistent-version:         2.13.2.2+version:         2.13.3.0 license:         MIT license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>@@ -42,6 +42,7 @@       , unliftio       , unliftio-core       , unordered-containers+      , vault       , vector      default-extensions: @@ -72,10 +73,14 @@         Database.Persist.Sql.Util          Database.Persist.SqlBackend+        Database.Persist.SqlBackend.StatementCache+        Database.Persist.SqlBackend.SqlPoolHooks         Database.Persist.SqlBackend.Internal         Database.Persist.SqlBackend.Internal.InsertSqlResult         Database.Persist.SqlBackend.Internal.IsolationLevel+        Database.Persist.SqlBackend.Internal.SqlPoolHooks         Database.Persist.SqlBackend.Internal.Statement+        Database.Persist.SqlBackend.Internal.StatementCache         Database.Persist.SqlBackend.Internal.MkSqlBackend          Database.Persist.Class