diff --git a/.travis.yml b/.travis.yml index 9b7a9b303..3334c46de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,6 @@ addons: apt: packages: - libgmp-dev - - cabal-install-1.24 - sources: - - hvr-ghc postgresql: "9.6" services: @@ -17,37 +14,28 @@ services: matrix: include: - - env: ARGS="--resolver lts-2" BACKEND=none - - env: ARGS="--resolver lts-2" BACKEND=sqlite - - env: ARGS="--resolver lts-2" BACKEND=mongodb - - env: ARGS="--resolver lts-2" BACKEND=postgresql - - env: ARGS="--resolver lts-2" BACKEND=mysql - - env: ARGS="--resolver lts-6" BACKEND=none - - env: ARGS="--resolver lts-6" BACKEND=sqlite - - env: ARGS="--resolver lts-6" BACKEND=mongodb - - env: ARGS="--resolver lts-6" BACKEND=postgresql - - env: ARGS="--resolver lts-6" BACKEND=mysql + - env: ARGS="--resolver lts-7" BACKEND=none + - env: ARGS="--resolver lts-9" BACKEND=none + - env: ARGS="--resolver lts-10" BACKEND=none + + - env: ARGS="--resolver lts-9" BACKEND=sqlite + - env: ARGS="--resolver lts-9" BACKEND=mongodb + - env: ARGS="--resolver lts-9" BACKEND=postgresql + - env: ARGS="--resolver lts-9" BACKEND=mysql - - env: ARGS="" BACKEND=none - - env: ARGS="" BACKEND=sqlite - - env: ARGS="" BACKEND=mongodb - - env: ARGS="" BACKEND=postgresql - - env: ARGS="" BACKEND=mysql + - env: ARGS="--resolver lts-10" BACKEND=sqlite + - env: ARGS="--resolver lts-10" BACKEND=mongodb + - env: ARGS="--resolver lts-10" BACKEND=postgresql + - env: ARGS="--resolver lts-10" BACKEND=mysql before_install: # Download and unpack the stack executable - mkdir -p ~/.local/bin -- export PATH=$HOME/.local/bin:/opt/cabal/1.24/bin:$PATH +- export PATH=$HOME/.local/bin:$PATH - travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' -# *TEMPORARY* A proposed change #717 uses haskell-src-meta, which requires -# `happy` to build haskell-src-exts. This fails in lts-2. Revert to the -# commented out line if #717 is not merged, or when testing lts-2 is dropped. -# script: travis/run.sh -script: -- if [[ $ARGS =~ lts-2 ]]; then stack $ARGS --install-ghc install happy; fi -- travis/run.sh +script: travis/run.sh cache: directories: @@ -60,7 +48,3 @@ cache: # packages: # - libzookeeper-mt-dev # - zookeeperd - -after_failure: -- cat ~/.cabal/logs/*log - diff --git a/persistent-mongoDB/ChangeLog.md b/persistent-mongoDB/ChangeLog.md index a067008e5..c22956ef2 100644 --- a/persistent-mongoDB/ChangeLog.md +++ b/persistent-mongoDB/ChangeLog.md @@ -1,3 +1,7 @@ +## 2.8.0 + +* Switch from `MonadBaseControl` to `MonadUnliftIO` + ## 2.6.0 * Fix upsert behavior [#613](https://github.com/yesodweb/persistent/issues/613) diff --git a/persistent-mongoDB/Database/Persist/MongoDB.hs b/persistent-mongoDB/Database/Persist/MongoDB.hs index 0d3374921..cde2d4c3f 100644 --- a/persistent-mongoDB/Database/Persist/MongoDB.hs +++ b/persistent-mongoDB/Database/Persist/MongoDB.hs @@ -152,7 +152,7 @@ import Data.Bits (shiftR) import Data.Word (Word16) import Data.Monoid (mappend) import Control.Monad.Trans.Reader (ask, runReaderT) -import Control.Monad.Trans.Control (MonadBaseControl) +import Control.Monad.IO.Unlift (MonadUnliftIO, withRunInIO) import Numeric (readHex) import Unsafe.Coerce (unsafeCoerce) @@ -362,17 +362,21 @@ withMongoDBPool dbname hostname port mauth poolStripes stripeConnections connect connectionReader pool -- | run a pool created with 'createMongoDBPipePool' -runMongoDBPipePool :: (Trans.MonadIO m, MonadBaseControl IO m) => DB.AccessMode -> Database -> DB.Action m a -> PipePool -> m a +runMongoDBPipePool :: MonadUnliftIO m => DB.AccessMode -> Database -> DB.Action m a -> PipePool -> m a runMongoDBPipePool accessMode db action pool = - Pool.withResource pool $ \pipe -> DB.access pipe accessMode db action + withRunInIO $ \run -> + Pool.withResource pool $ \pipe -> + run $ DB.access pipe accessMode db action -runMongoDBPool :: (Trans.MonadIO m, MonadBaseControl IO m) => DB.AccessMode -> DB.Action m a -> ConnectionPool -> m a +runMongoDBPool :: MonadUnliftIO m => DB.AccessMode -> DB.Action m a -> ConnectionPool -> m a runMongoDBPool accessMode action pool = - Pool.withResource pool $ \(Connection pipe db) -> DB.access pipe accessMode db action + withRunInIO $ \run -> + Pool.withResource pool $ \(Connection pipe db) -> + run $ DB.access pipe accessMode db action -- | use default 'AccessMode' -runMongoDBPoolDef :: (Trans.MonadIO m, MonadBaseControl IO m) => DB.Action m a -> ConnectionPool -> m a +runMongoDBPoolDef :: MonadUnliftIO m => DB.Action m a -> ConnectionPool -> m a runMongoDBPoolDef = runMongoDBPool defaultAccessMode queryByKey :: (PersistEntity record, PersistEntityBackend record ~ DB.MongoContext) diff --git a/persistent-mongoDB/persistent-mongoDB.cabal b/persistent-mongoDB/persistent-mongoDB.cabal index 8740ca964..29f4d11c6 100644 --- a/persistent-mongoDB/persistent-mongoDB.cabal +++ b/persistent-mongoDB/persistent-mongoDB.cabal @@ -1,5 +1,5 @@ name: persistent-mongoDB -version: 2.6.0 +version: 2.8.0 license: MIT license-file: LICENSE author: Greg Weber @@ -19,8 +19,8 @@ Flag high_precision_date Default: False library - build-depends: base >= 4.6 && < 5 - , persistent >= 2.5 && < 3 + build-depends: base >= 4.8 && < 5 + , persistent >= 2.8 && < 3 , text >= 0.8 , transformers >= 0.2.1 , containers >= 0.2 @@ -33,12 +33,12 @@ library , cereal >= 0.3.0.0 , path-pieces >= 0.1 , http-api-data >= 0.2 && < 0.4 - , monad-control >= 0.3 , aeson >= 0.6.2 , attoparsec , time , bytestring , resource-pool < 0.3 + , unliftio-core exposed-modules: Database.Persist.MongoDB ghc-options: -Wall diff --git a/persistent-mysql/ChangeLog.md b/persistent-mysql/ChangeLog.md index dc8e6be41..414f6a451 100644 --- a/persistent-mysql/ChangeLog.md +++ b/persistent-mysql/ChangeLog.md @@ -1,9 +1,13 @@ -## Unreleased +## 2.8.0 (Unreleased) +* Switch from `MonadBaseControl` to `MonadUnliftIO` * Fix duplicate migrations when using `mediumtext`, `longtext`, `mediumblob`, `longblob`, and `double`s using a custom precision. [#754](https://github.com/yesodweb/persistent/pull/754) -- This can be released as a minor change on the next update. Currently persistent-mysql can't be released because 2.6.2.2 depends on persistent-2.7.2 being released. +* The `SomeField` type was renamed to `HandleUpdateCollision` and deprecated. Please migrate to using `HandleUpdateCollision`. +* The `SomeField` constructor was deprecated, and a temporary pattern synonym introduced. Please migrate to using `copyField`. + ## 2.6.2.2 [UNRELEASED ON HACKAGE] -- This version depends on persistent 2.7.2, which introduced breaking changes and is deprecated on hackage. diff --git a/persistent-mysql/Database/Persist/MySQL.hs b/persistent-mysql/Database/Persist/MySQL.hs index 3cf1aeed3..c5112e15e 100644 --- a/persistent-mysql/Database/Persist/MySQL.hs +++ b/persistent-mysql/Database/Persist/MySQL.hs @@ -1,4 +1,6 @@ {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} @@ -16,9 +18,17 @@ module Database.Persist.MySQL , MySQLBase.defaultSSLInfo , MySQLConf(..) , mockMigration + -- * @ON DUPLICATE KEY UPDATE@ Functionality , insertOnDuplicateKeyUpdate , insertManyOnDuplicateKeyUpdate - , SomeField(SomeField) +#if MIN_VERSION_base(4,7,0) + , HandleUpdateCollision + , pattern SomeField +#elif MIN_VERSION_base(4,9,0) + , HandleUpdateCollision(SomeField) +#endif + , SomeField + , copyField , copyUnlessNull , copyUnlessEmpty , copyUnlessEq @@ -29,7 +39,7 @@ import Control.Monad.Logger (MonadLogger, runNoLoggingT) import Control.Monad.IO.Class (MonadIO (..)) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Except (runExceptT) -import Control.Monad.Trans.Reader (runReaderT, ReaderT, withReaderT) +import Control.Monad.Trans.Reader (runReaderT, ReaderT) import Control.Monad.Trans.Writer (runWriterT) import Data.Either (partitionEithers) import Data.Monoid ((<>)) @@ -67,8 +77,7 @@ import qualified Database.MySQL.Simple.Types as MySQL import qualified Database.MySQL.Base as MySQLBase import qualified Database.MySQL.Base.Types as MySQLBase -import Control.Monad.Trans.Control (MonadBaseControl) -import Control.Monad.Trans.Resource (runResourceT) +import Control.Monad.IO.Unlift (MonadUnliftIO) import Prelude @@ -76,7 +85,7 @@ import Prelude -- The pool is properly released after the action finishes using -- it. Note that you should not use the given 'ConnectionPool' -- outside the action since it may be already been released. -withMySQLPool :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, IsSqlBackend backend) +withMySQLPool :: (MonadLogger m, MonadUnliftIO m, IsSqlBackend backend) => MySQL.ConnectInfo -- ^ Connection information. -> Int @@ -90,7 +99,7 @@ withMySQLPool ci = withSqlPool $ open' ci -- | Create a MySQL connection pool. Note that it's your -- responsibility to properly close the connection pool when -- unneeded. Use 'withMySQLPool' for automatic resource control. -createMySQLPool :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, IsSqlBackend backend) +createMySQLPool :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => MySQL.ConnectInfo -- ^ Connection information. -> Int @@ -101,7 +110,7 @@ createMySQLPool ci = createSqlPool $ open' ci -- | Same as 'withMySQLPool', but instead of opening a pool -- of connections, only one connection is opened. -withMySQLConn :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, IsSqlBackend backend) +withMySQLConn :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => MySQL.ConnectInfo -- ^ Connection information. -> (backend -> m a) @@ -178,7 +187,7 @@ withStmt' :: MonadIO m => MySQL.Connection -> MySQL.Query -> [PersistValue] - -> Acquire (Source m [PersistValue]) + -> Acquire (ConduitM () [PersistValue] m ()) withStmt' conn query vals = do result <- mkAcquire createResult MySQLBase.freeResult return $ fetchRows result >>= CL.sourceList @@ -465,45 +474,51 @@ getColumns :: MySQL.ConnectInfo ) getColumns connectInfo getter def = do -- Find out ID column. - stmtIdClmn <- getter "SELECT COLUMN_NAME, \ - \IS_NULLABLE, \ - \DATA_TYPE, \ - \COLUMN_DEFAULT \ - \FROM INFORMATION_SCHEMA.COLUMNS \ - \WHERE TABLE_SCHEMA = ? \ - \AND TABLE_NAME = ? \ - \AND COLUMN_NAME = ?" - inter1 <- with (stmtQuery stmtIdClmn vals) ($$ CL.consume) - ids <- runResourceT $ CL.sourceList inter1 $$ helperClmns -- avoid nested queries + stmtIdClmn <- getter $ T.concat + [ "SELECT COLUMN_NAME, " + , "IS_NULLABLE, " + , "DATA_TYPE, " + , "COLUMN_DEFAULT " + , "FROM INFORMATION_SCHEMA.COLUMNS " + , "WHERE TABLE_SCHEMA = ? " + , "AND TABLE_NAME = ? " + , "AND COLUMN_NAME = ?" + ] + inter1 <- with (stmtQuery stmtIdClmn vals) (\src -> runConduit $ src .| CL.consume) + ids <- runConduitRes $ CL.sourceList inter1 .| helperClmns -- avoid nested queries -- Find out all columns. - stmtClmns <- getter "SELECT COLUMN_NAME, \ - \IS_NULLABLE, \ - \DATA_TYPE, \ - \COLUMN_TYPE, \ - \CHARACTER_MAXIMUM_LENGTH, \ - \NUMERIC_PRECISION, \ - \NUMERIC_SCALE, \ - \COLUMN_DEFAULT \ - \FROM INFORMATION_SCHEMA.COLUMNS \ - \WHERE TABLE_SCHEMA = ? \ - \AND TABLE_NAME = ? \ - \AND COLUMN_NAME <> ?" - inter2 <- with (stmtQuery stmtClmns vals) ($$ CL.consume) - cs <- runResourceT $ CL.sourceList inter2 $$ helperClmns -- avoid nested queries + stmtClmns <- getter $ T.concat + [ "SELECT COLUMN_NAME, " + , "IS_NULLABLE, " + , "DATA_TYPE, " + , "COLUMN_TYPE, " + , "CHARACTER_MAXIMUM_LENGTH, " + , "NUMERIC_PRECISION, " + , "NUMERIC_SCALE, " + , "COLUMN_DEFAULT " + , "FROM INFORMATION_SCHEMA.COLUMNS " + , "WHERE TABLE_SCHEMA = ? " + , "AND TABLE_NAME = ? " + , "AND COLUMN_NAME <> ?" + ] + inter2 <- with (stmtQuery stmtClmns vals) (\src -> runConduitRes $ src .| CL.consume) + cs <- runConduitRes $ CL.sourceList inter2 .| helperClmns -- avoid nested queries -- Find out the constraints. - stmtCntrs <- getter "SELECT CONSTRAINT_NAME, \ - \COLUMN_NAME \ - \FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE \ - \WHERE TABLE_SCHEMA = ? \ - \AND TABLE_NAME = ? \ - \AND COLUMN_NAME <> ? \ - \AND CONSTRAINT_NAME <> 'PRIMARY' \ - \AND REFERENCED_TABLE_SCHEMA IS NULL \ - \ORDER BY CONSTRAINT_NAME, \ - \COLUMN_NAME" - us <- with (stmtQuery stmtCntrs vals) ($$ helperCntrs) + stmtCntrs <- getter $ T.concat + [ "SELECT CONSTRAINT_NAME, " + , "COLUMN_NAME " + , "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE " + , "WHERE TABLE_SCHEMA = ? " + , "AND TABLE_NAME = ? " + , "AND COLUMN_NAME <> ? " + , "AND CONSTRAINT_NAME <> 'PRIMARY' " + , "AND REFERENCED_TABLE_SCHEMA IS NULL " + , "ORDER BY CONSTRAINT_NAME, " + , "COLUMN_NAME" + ] + us <- with (stmtQuery stmtCntrs vals) (\src -> runConduitRes $ src .| helperCntrs) -- Return both return (ids, cs ++ us) @@ -512,7 +527,7 @@ getColumns connectInfo getter def = do , PersistText $ unDBName $ entityDB def , PersistText $ unDBName $ fieldDB $ entityId def ] - helperClmns = CL.mapM getIt =$ CL.consume + helperClmns = CL.mapM getIt .| CL.consume where getIt = fmap (either Left (Right . Left)) . liftIO . @@ -556,21 +571,23 @@ getColumn connectInfo getter tname [ PersistText cname _ -> fail $ "Invalid default column: " ++ show default' -- Foreign key (if any) - stmt <- lift $ getter "SELECT REFERENCED_TABLE_NAME, \ - \CONSTRAINT_NAME, \ - \ORDINAL_POSITION \ - \FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE \ - \WHERE TABLE_SCHEMA = ? \ - \AND TABLE_NAME = ? \ - \AND COLUMN_NAME = ? \ - \AND REFERENCED_TABLE_SCHEMA = ? \ - \ORDER BY CONSTRAINT_NAME, \ - \COLUMN_NAME" + stmt <- lift . getter $ T.concat + [ "SELECT REFERENCED_TABLE_NAME, " + , "CONSTRAINT_NAME, " + , "ORDINAL_POSITION " + , "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE " + , "WHERE TABLE_SCHEMA = ? " + , "AND TABLE_NAME = ? " + , "AND COLUMN_NAME = ? " + , "AND REFERENCED_TABLE_SCHEMA = ? " + , "ORDER BY CONSTRAINT_NAME, " + , "COLUMN_NAME" + ] let vars = [ PersistText $ pack $ MySQL.connectDatabase connectInfo , PersistText $ unDBName $ tname , PersistText cname , PersistText $ pack $ MySQL.connectDatabase connectInfo ] - cntrs <- with (stmtQuery stmt vars) ($$ CL.consume) + cntrs <- liftIO $ with (stmtQuery stmt vars) (\src -> runConduit $ src .| CL.consume) ref <- case cntrs of [] -> return Nothing [[PersistText tab, PersistText ref, PersistInt64 pos]] -> @@ -1026,8 +1043,10 @@ mockMigration mig = do resp <- result sqlbackend mapM_ T.putStrLn $ map snd $ snd resp --- | MySQL specific 'upsert'. This will prevent multiple queries, when one will --- do. +-- | MySQL specific 'upsert_'. This will prevent multiple queries, when one will +-- do. The record will be inserted into the database. In the event that the +-- record already exists in the database, the record will have the +-- relevant updates performed. insertOnDuplicateKeyUpdate :: ( backend ~ PersistEntityBackend record , PersistEntity record @@ -1042,45 +1061,64 @@ insertOnDuplicateKeyUpdate record = insertManyOnDuplicateKeyUpdate [record] [] -- | This type is used to determine how to update rows using MySQL's --- @INSERT ON DUPLICATE KEY UPDATE@ functionality, exposed via --- 'insertManyOnDuplicateKeyUpdate' in the library. +-- @INSERT ... ON DUPLICATE KEY UPDATE@ functionality, exposed via +-- 'insertManyOnDuplicateKeyUpdate' in this library. -- --- @since 2.6.2 -data SomeField record where +-- @since 3.0.0 +data HandleUpdateCollision record where -- | Copy the field directly from the record. - SomeField :: EntityField record typ -> SomeField record + CopyField :: EntityField record typ -> HandleUpdateCollision record -- | Only copy the field if it is not equal to the provided value. - CopyUnlessEq :: PersistField typ => EntityField record typ -> typ -> SomeField record + CopyUnlessEq :: PersistField typ => EntityField record typ -> typ -> HandleUpdateCollision record + +-- | An alias for 'HandleUpdateCollision'. The type previously was only +-- used to copy a single value, but was expanded to be handle more complex +-- queries. +-- +-- @since 2.6.2 +type SomeField = HandleUpdateCollision + +#if MIN_VERSION_base(4,8,0) +pattern SomeField :: EntityField record typ -> SomeField record +#endif +pattern SomeField x = CopyField x +{-# DEPRECATED SomeField "The type SomeField is deprecated. Use the type HandleUpdateCollision instead, and use the function copyField instead of the data constructor." #-} -- | Copy the field into the database only if the value in the -- corresponding record is non-@NULL@. -- -- @since 2.6.2 -copyUnlessNull :: PersistField typ => EntityField record (Maybe typ) -> SomeField record +copyUnlessNull :: PersistField typ => EntityField record (Maybe typ) -> HandleUpdateCollision record copyUnlessNull field = CopyUnlessEq field Nothing -- | Copy the field into the database only if the value in the -- corresponding record is non-empty, where "empty" means the Monoid -- definition for 'mempty'. Useful for 'Text', 'String', 'ByteString', etc. -- --- The resulting 'SomeField' type is useful for the +-- The resulting 'HandleUpdateCollision' type is useful for the -- 'insertManyOnDuplicateKeyUpdate' function. -- -- @since 2.6.2 -copyUnlessEmpty :: (Monoid.Monoid typ, PersistField typ) => EntityField record typ -> SomeField record +copyUnlessEmpty :: (Monoid.Monoid typ, PersistField typ) => EntityField record typ -> HandleUpdateCollision record copyUnlessEmpty field = CopyUnlessEq field Monoid.mempty -- | Copy the field into the database only if the field is not equal to the -- provided value. This is useful to avoid copying weird nullary data into -- the database. -- --- The resulting 'SomeField' type is useful for the +-- The resulting 'HandleUpdateCollision' type is useful for the -- 'insertManyOnDuplicateKeyUpdate' function. -- -- @since 2.6.2 -copyUnlessEq :: PersistField typ => EntityField record typ -> typ -> SomeField record +copyUnlessEq :: PersistField typ => EntityField record typ -> typ -> HandleUpdateCollision record copyUnlessEq = CopyUnlessEq +-- | Copy the field directly from the record. +-- +-- @since 3.0 +copyField :: PersistField typ => EntityField record typ -> HandleUpdateCollision record +copyField = CopyField + -- | Do a bulk insert on the given records in the first parameter. In the event -- that a key conflicts with a record currently in the database, the second and -- third parameters determine what will happen. @@ -1093,9 +1131,9 @@ copyUnlessEq = CopyUnlessEq -- the value that is provided. You can use this to increment a counter value. -- These updates only occur if the original record is present in the database. -- --- === __More details on 'SomeField' usage__ +-- === __More details on 'HandleUpdateCollision' usage__ -- --- The @['SomeField']@ parameter allows you to specify which fields (and +-- The @['HandleUpdateCollision']@ parameter allows you to specify which fields (and -- under which conditions) will be copied from the inserted rows. For -- a brief example, consider the following data model and existing data set: -- @@ -1177,13 +1215,12 @@ insertManyOnDuplicateKeyUpdate , MonadIO m ) => [record] -- ^ A list of the records you want to insert, or update - -> [SomeField record] -- ^ A list of the fields you want to copy over. + -> [HandleUpdateCollision record] -- ^ A list of the fields you want to copy over. -> [Update record] -- ^ A list of the updates to apply that aren't dependent on the record being inserted. -> ReaderT backend m () insertManyOnDuplicateKeyUpdate [] _ _ = return () insertManyOnDuplicateKeyUpdate records fieldValues updates = - withReaderT projectBackend - . uncurry rawExecute + uncurry rawExecute $ mkBulkInsertQuery records fieldValues updates -- | This creates the query for 'bulkInsertOnDuplicateKeyUpdate'. If you @@ -1193,14 +1230,14 @@ insertManyOnDuplicateKeyUpdate records fieldValues updates = mkBulkInsertQuery :: PersistEntity record => [record] -- ^ A list of the records you want to insert, or update - -> [SomeField record] -- ^ A list of the fields you want to copy over. + -> [HandleUpdateCollision record] -- ^ A list of the fields you want to copy over. -> [Update record] -- ^ A list of the updates to apply that aren't dependent on the record being inserted. -> (Text, [PersistValue]) mkBulkInsertQuery records fieldValues updates = (q, recordValues <> updsValues <> copyUnlessValues) where mfieldDef x = case x of - SomeField rec -> Right (fieldDbToText (persistFieldDef rec)) + CopyField rec -> Right (fieldDbToText (persistFieldDef rec)) CopyUnlessEq rec val -> Left (fieldDbToText (persistFieldDef rec), toPersistValue val) (fieldsToMaybeCopy, updateFieldNames) = partitionEithers $ map mfieldDef fieldValues fieldDbToText = T.pack . escapeDBName . fieldDB diff --git a/persistent-mysql/persistent-mysql.cabal b/persistent-mysql/persistent-mysql.cabal index ef41a1b8b..8dde82153 100644 --- a/persistent-mysql/persistent-mysql.cabal +++ b/persistent-mysql/persistent-mysql.cabal @@ -1,5 +1,5 @@ name: persistent-mysql -version: 2.6.2.1 +version: 2.8.0 license: MIT license-file: LICENSE author: Felipe Lessa , Michael Snoyman @@ -27,18 +27,18 @@ description: extra-source-files: ChangeLog.md library - build-depends: base >= 4.6 && < 5 + build-depends: base >= 4.8 && < 5 , transformers >= 0.2.1 , mysql-simple >= 0.4.3 && < 0.5 , mysql >= 0.1.1.3 && < 0.2 , blaze-builder - , persistent >= 2.6.1 && < 3 + , persistent >= 2.8.0 && < 3 , containers >= 0.2 , bytestring >= 0.9 , text >= 0.11.0.6 - , monad-control >= 0.2 + , unliftio-core , aeson >= 0.6.2 - , conduit >= 0.5.3 + , conduit >= 1.2.8 , resourcet >= 0.4.10 , monad-logger , resource-pool diff --git a/persistent-postgresql/ChangeLog.md b/persistent-postgresql/ChangeLog.md index efa5b0084..c8effba6f 100644 --- a/persistent-postgresql/ChangeLog.md +++ b/persistent-postgresql/ChangeLog.md @@ -1,3 +1,7 @@ +## 2.8.0 + +* Switch from `MonadBaseControl` to `MonadUnliftIO` + ## 2.6.3 * Added new function `migrateEnableExtension`, to enable Postgres extensions in migrations. diff --git a/persistent-postgresql/Database/Persist/Postgresql.hs b/persistent-postgresql/Database/Persist/Postgresql.hs index e5467314e..93d3c1a31 100644 --- a/persistent-postgresql/Database/Persist/Postgresql.hs +++ b/persistent-postgresql/Database/Persist/Postgresql.hs @@ -45,9 +45,8 @@ import Database.PostgreSQL.Simple.Ok (Ok (..)) import qualified Database.PostgreSQL.LibPQ as LibPQ -import Control.Monad.Trans.Resource import Control.Exception (throw) -import Control.Monad.IO.Class (MonadIO (..)) +import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO) import Data.Data import Data.Typeable (Typeable) import Data.IORef @@ -107,7 +106,7 @@ instance Exception PostgresServerVersionError -- finishes using it. Note that you should not use the given -- 'ConnectionPool' outside the action since it may be already -- been released. -withPostgresqlPool :: (MonadBaseControl IO m, MonadLogger m, MonadIO m, IsSqlBackend backend) +withPostgresqlPool :: (MonadLogger m, MonadUnliftIO m, IsSqlBackend backend) => ConnectionString -- ^ Connection string to the database. -> Int @@ -123,7 +122,7 @@ withPostgresqlPool ci = withPostgresqlPoolWithVersion getServerVersion ci -- the server version (to workaround an Amazon Redshift bug). -- -- @since 2.6.2 -withPostgresqlPoolWithVersion :: (MonadBaseControl IO m, MonadLogger m, MonadIO m, IsSqlBackend backend) +withPostgresqlPoolWithVersion :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => (PG.Connection -> IO (Maybe Double)) -- ^ action to perform to get the server version -> ConnectionString @@ -141,7 +140,7 @@ withPostgresqlPoolWithVersion getVer ci = withSqlPool $ open' (const $ return () -- responsibility to properly close the connection pool when -- unneeded. Use 'withPostgresqlPool' for an automatic resource -- control. -createPostgresqlPool :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, IsSqlBackend backend) +createPostgresqlPool :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => ConnectionString -- ^ Connection string to the database. -> Int @@ -159,7 +158,7 @@ createPostgresqlPool = createPostgresqlPoolModified (const $ return ()) -- -- @since 2.1.3 createPostgresqlPoolModified - :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, IsSqlBackend backend) + :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => (PG.Connection -> IO ()) -- ^ action to perform after connection is created -> ConnectionString -- ^ Connection string to the database. -> Int -- ^ Number of connections to be kept open in the pool. @@ -172,7 +171,7 @@ createPostgresqlPoolModified = createPostgresqlPoolModifiedWithVersion getServer -- -- @since 2.6.2 createPostgresqlPoolModifiedWithVersion - :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, IsSqlBackend backend) + :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => (PG.Connection -> IO (Maybe Double)) -- ^ action to perform to get the server version -> (PG.Connection -> IO ()) -- ^ action to perform after connection is created -> ConnectionString -- ^ Connection string to the database. @@ -183,7 +182,7 @@ createPostgresqlPoolModifiedWithVersion getVer modConn ci = -- | Same as 'withPostgresqlPool', but instead of opening a pool -- of connections, only one connection is opened. -withPostgresqlConn :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, IsSqlBackend backend) +withPostgresqlConn :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => ConnectionString -> (backend -> m a) -> m a withPostgresqlConn = withPostgresqlConnWithVersion getServerVersion @@ -191,13 +190,13 @@ withPostgresqlConn = withPostgresqlConnWithVersion getServerVersion -- the server version (to workaround an Amazon Redshift bug). -- -- @since 2.6.2 -withPostgresqlConnWithVersion :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, IsSqlBackend backend) +withPostgresqlConnWithVersion :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => (PG.Connection -> IO (Maybe Double)) - -> ConnectionString + -> ConnectionString -> (backend -> m a) -> m a withPostgresqlConnWithVersion getVer = withSqlConn . open' (const $ return ()) getVer - + open' :: (IsSqlBackend backend) => (PG.Connection -> IO ()) @@ -340,7 +339,7 @@ withStmt' :: MonadIO m => PG.Connection -> PG.Query -> [PersistValue] - -> Acquire (Source m [PersistValue]) + -> Acquire (ConduitM () [PersistValue] m ()) withStmt' conn query vals = pull `fmap` mkAcquire openS closeS where @@ -530,7 +529,7 @@ doesTableExist :: (Text -> IO Statement) -> IO Bool doesTableExist getter (DBName name) = do stmt <- getter sql - with (stmtQuery stmt vals) ($$ start) + with (stmtQuery stmt vals) (\src -> runConduit $ src .| start) where sql = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE schemaname != 'pg_catalog'" <> " AND schemaname != 'information_schema' AND tablename=?" @@ -664,7 +663,7 @@ getColumns getter def = do [ PersistText $ unDBName $ entityDB def , PersistText $ unDBName $ fieldDB (entityId def) ] - cs <- with (stmtQuery stmt vals) ($$ helper) + cs <- with (stmtQuery stmt vals) (\src -> runConduit $ src .| helper) let sqlc = T.concat ["SELECT " ,"c.constraint_name, " ,"c.column_name " @@ -683,7 +682,7 @@ getColumns getter def = do stmt' <- getter sqlc - us <- with (stmtQuery stmt' vals) ($$ helperU) + us <- with (stmtQuery stmt' vals) (\src -> runConduit $ src .| helperU) return $ cs ++ us where getAll front = do @@ -799,7 +798,7 @@ getColumn getter tname [PersistText x, PersistText y, PersistText z, d, npre, ns with (stmtQuery stmt [ PersistText $ unDBName tname , PersistText $ unDBName ref - ]) ($$ do + ]) (\src -> runConduit $ src .| do Just [PersistInt64 i] <- CL.head return $ if i == 0 then Nothing else Just (DBName "", ref)) d' = case d of diff --git a/persistent-postgresql/persistent-postgresql.cabal b/persistent-postgresql/persistent-postgresql.cabal index 696edc67d..fbf1ab45f 100644 --- a/persistent-postgresql/persistent-postgresql.cabal +++ b/persistent-postgresql/persistent-postgresql.cabal @@ -1,5 +1,5 @@ name: persistent-postgresql -version: 2.6.3 +version: 2.8.0 license: MIT license-file: LICENSE author: Felipe Lessa, Michael Snoyman @@ -15,19 +15,19 @@ bug-reports: https://github.com/yesodweb/persistent/issues extra-source-files: ChangeLog.md library - build-depends: base >= 4.6 && < 5 + build-depends: base >= 4.8 && < 5 , transformers >= 0.2.1 , postgresql-simple >= 0.4.0 && < 0.6 , postgresql-libpq >= 0.6.1 && < 0.10 - , persistent >= 2.6.1 && < 3 + , persistent >= 2.8.0 && < 3 , containers >= 0.2 , bytestring >= 0.9 , text >= 0.7 - , monad-control >= 0.2 + , unliftio-core , blaze-builder , time >= 1.1 , aeson >= 0.6.2 - , conduit >= 0.5.3 + , conduit >= 1.2.8 , resourcet >= 1.1 , monad-logger >= 0.3.4 , resource-pool diff --git a/persistent-sqlite/ChangeLog.md b/persistent-sqlite/ChangeLog.md index cbb9fc9fd..31f3c6b04 100644 --- a/persistent-sqlite/ChangeLog.md +++ b/persistent-sqlite/ChangeLog.md @@ -1,3 +1,7 @@ +## 2.8.0 + +* Switch from `MonadBaseControl` to `MonadUnliftIO` + ## 2.6.4 * Adds a new function `stepConn`, which uses an additional parameter to give more detailed error messages [#750](https://github.com/yesodweb/persistent/pull/750) diff --git a/persistent-sqlite/Database/Persist/Sqlite.hs b/persistent-sqlite/Database/Persist/Sqlite.hs index 89afa4db4..a406b61c3 100644 --- a/persistent-sqlite/Database/Persist/Sqlite.hs +++ b/persistent-sqlite/Database/Persist/Sqlite.hs @@ -39,12 +39,10 @@ import qualified Database.Sqlite as Sqlite import Control.Applicative as A import qualified Control.Exception as E import Control.Monad (when) -import Control.Monad.IO.Class (MonadIO (..)) +import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO, withUnliftIO, unliftIO) import Control.Monad.Logger (NoLoggingT, runNoLoggingT, MonadLogger) -import Control.Monad.Trans.Control (control) -import Control.Monad.Trans.Control (MonadBaseControl) import Control.Monad.Trans.Reader (ReaderT, runReaderT) -import Control.Monad.Trans.Resource (ResourceT, runResourceT) +import UnliftIO.Resource (ResourceT, runResourceT) import Control.Monad.Trans.Writer (runWriterT) import Data.Acquire (Acquire, mkAcquire, with) import Data.Aeson @@ -67,7 +65,7 @@ import Lens.Micro.TH (makeLenses) -- Note that this should not be used with the @:memory:@ connection string, as -- the pool will regularly remove connections, destroying your database. -- Instead, use 'withSqliteConn'. -createSqlitePool :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, IsSqlBackend backend) +createSqlitePool :: (MonadLogger m, MonadUnliftIO m, IsSqlBackend backend) => Text -> Int -> m (Pool backend) createSqlitePool = createSqlitePoolFromInfo . conStringToInfo @@ -78,14 +76,14 @@ createSqlitePool = createSqlitePoolFromInfo . conStringToInfo -- Instead, use 'withSqliteConn'. -- -- @since 2.6.2 -createSqlitePoolFromInfo :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, IsSqlBackend backend) +createSqlitePoolFromInfo :: (MonadLogger m, MonadUnliftIO m, IsSqlBackend backend) => SqliteConnectionInfo -> Int -> m (Pool backend) createSqlitePoolFromInfo connInfo = createSqlPool $ open' connInfo -- | Run the given action with a connection pool. -- -- Like 'createSqlitePool', this should not be used with @:memory:@. -withSqlitePool :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, IsSqlBackend backend) +withSqlitePool :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => Text -> Int -- ^ number of connections to open -> (Pool backend -> m a) -> m a @@ -96,18 +94,18 @@ withSqlitePool connInfo = withSqlPool . open' $ conStringToInfo connInfo -- Like 'createSqlitePool', this should not be used with @:memory:@. -- -- @since 2.6.2 -withSqlitePoolInfo :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, IsSqlBackend backend) +withSqlitePoolInfo :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => SqliteConnectionInfo -> Int -- ^ number of connections to open -> (Pool backend -> m a) -> m a withSqlitePoolInfo connInfo = withSqlPool $ open' connInfo -withSqliteConn :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, IsSqlBackend backend) +withSqliteConn :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => Text -> (backend -> m a) -> m a withSqliteConn = withSqliteConnInfo . conStringToInfo -- | @since 2.6.2 -withSqliteConnInfo :: (MonadBaseControl IO m, MonadIO m, MonadLogger m, IsSqlBackend backend) +withSqliteConnInfo :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => SqliteConnectionInfo -> (backend -> m a) -> m a withSqliteConnInfo = withSqlConn . open' @@ -179,7 +177,7 @@ wrapConnectionInfo connInfo conn logFunc = do -- that all log messages are discarded. -- -- @since 1.1.4 -runSqlite :: (MonadBaseControl IO m, MonadIO m, IsSqlBackend backend) +runSqlite :: (MonadUnliftIO m, IsSqlBackend backend) => Text -- ^ connection string -> ReaderT backend (NoLoggingT (ResourceT m)) a -- ^ database action -> m a @@ -193,7 +191,7 @@ runSqlite connstr = runResourceT -- that all log messages are discarded. -- -- @since 2.6.2 -runSqliteInfo :: (MonadBaseControl IO m, MonadIO m, IsSqlBackend backend) +runSqliteInfo :: (MonadUnliftIO m, IsSqlBackend backend) => SqliteConnectionInfo -> ReaderT backend (NoLoggingT (ResourceT m)) a -- ^ database action -> m a @@ -261,7 +259,7 @@ withStmt' => Sqlite.Connection -> Sqlite.Statement -> [PersistValue] - -> Acquire (Source m [PersistValue]) + -> Acquire (ConduitM () [PersistValue] m ()) withStmt' conn stmt vals = do _ <- mkAcquire (Sqlite.bind stmt vals >> return stmt) @@ -298,7 +296,8 @@ migrate' allDefs getter val = do let (cols, uniqs, _) = mkColumns allDefs val let newSql = mkCreateTable False def (filter (not . safeToRemove val . cName) cols, uniqs) stmt <- getter "SELECT sql FROM sqlite_master WHERE type='table' AND name=?" - oldSql' <- with (stmtQuery stmt [PersistText $ unDBName table]) ($$ go) + oldSql' <- with (stmtQuery stmt [PersistText $ unDBName table]) + (\src -> runConduit $ src .| go) case oldSql' of Nothing -> return $ Right [(False, newSql)] Just oldSql -> do @@ -371,7 +370,7 @@ getCopyTable :: [EntityDef] -> IO [(Bool, Text)] getCopyTable allDefs getter def = do stmt <- getter $ T.concat [ "PRAGMA table_info(", escape table, ")" ] - oldCols' <- with (stmtQuery stmt []) ($$ getCols) + oldCols' <- with (stmtQuery stmt []) (\src -> runConduit $ src .| getCols) let oldCols = map DBName $ filter (/= "id") oldCols' -- need to update for table id attribute ? let newCols = filter (not . safeToRemove def) $ map cName cols let common = filter (`elem` oldCols) newCols @@ -515,13 +514,13 @@ instance PersistConfig SqliteConf where runPool _ = runSqlPool loadConfig = parseJSON -finally :: MonadBaseControl IO m +finally :: MonadUnliftIO m => m a -- ^ computation to run first -> m b -- ^ computation to run afterward (even if an exception was raised) -> m a -finally a sequel = control $ \runInIO -> - E.finally (runInIO a) - (runInIO sequel) +finally a sequel = withUnliftIO $ \u -> + E.finally (unliftIO u a) + (unliftIO u sequel) {-# INLINABLE finally #-} -- | Creates a SqliteConnectionInfo from a connection string, with the -- default settings. diff --git a/persistent-sqlite/persistent-sqlite.cabal b/persistent-sqlite/persistent-sqlite.cabal index 50b6c50e5..a4feab85b 100644 --- a/persistent-sqlite/persistent-sqlite.cabal +++ b/persistent-sqlite/persistent-sqlite.cabal @@ -1,5 +1,5 @@ name: persistent-sqlite -version: 2.6.4 +version: 2.8.0 license: MIT license-file: LICENSE author: Michael Snoyman @@ -25,15 +25,15 @@ flag build-sanity-exe default: False library - build-depends: base >= 4.6 && < 5 + build-depends: base >= 4.8 && < 5 , bytestring >= 0.9.1 , transformers >= 0.2.1 - , persistent >= 2.6.1 && < 3 - , monad-control >= 0.2 + , persistent >= 2.8.0 && < 3 + , unliftio-core , containers >= 0.2 , text >= 0.7 , aeson >= 0.6.2 - , conduit >= 0.5.3 + , conduit >= 1.2.8 , monad-logger >= 0.2.4 , microlens-th >= 0.4.1.1 , resourcet >= 1.1 diff --git a/persistent-test/persistent-test.cabal b/persistent-test/persistent-test.cabal index b664c8852..a254559b3 100644 --- a/persistent-test/persistent-test.cabal +++ b/persistent-test/persistent-test.cabal @@ -102,7 +102,8 @@ library , http-api-data >= 0.2 , text >= 0.8 , transformers >= 0.2.1 - , monad-control >= 0.3 + , unliftio-core + , unliftio , containers >= 0.2 , bytestring >= 0.9 , base64-bytestring diff --git a/persistent-test/src/CompositeTest.hs b/persistent-test/src/CompositeTest.hs index 25a8d7cc7..3eec20571 100644 --- a/persistent-test/src/CompositeTest.hs +++ b/persistent-test/src/CompositeTest.hs @@ -19,8 +19,6 @@ module CompositeTest where import Test.Hspec.Expectations () -import qualified Control.Monad.Trans.Control -import qualified Control.Exception as E import Init #ifndef WITH_NOSQL @@ -311,11 +309,3 @@ matchParentK = (\(a:b:c:[]) -> (,,) <$> fromPersistValue a <*> fromPersistValue matchCitizenAddressK :: Key CitizenAddress -> Either Text (Int64, Int64) matchCitizenAddressK = (\(a:b:[]) -> (,) <$> fromPersistValue a <*> fromPersistValue b) . keyToValues - -catch' :: (Control.Monad.Trans.Control.MonadBaseControl IO m, E.Exception e) - => m a -- ^ The computation to run - -> (e -> m a) -- ^ Handler to invoke if an exception is raised - -> m a -catch' a handler = Control.Monad.Trans.Control.control $ \runInIO -> - E.catch (runInIO a) - (\e -> runInIO $ handler e) diff --git a/persistent-test/src/Init.hs b/persistent-test/src/Init.hs index 33ade1676..d0fffd956 100644 --- a/persistent-test/src/Init.hs +++ b/persistent-test/src/Init.hs @@ -110,7 +110,7 @@ import System.IO.Unsafe (unsafePerformIO) #endif import Control.Monad (unless, (>=>)) -import Control.Monad.Trans.Control (MonadBaseControl) +import Control.Monad.IO.Unlift (MonadUnliftIO) -- Data types import Data.Int (Int32, Int64) @@ -191,7 +191,7 @@ dbName = "persistent" type BackendMonad = Context #ifdef WITH_MONGODB -runConn :: (MonadIO m, MonadBaseControl IO m) => Action m backend -> m () +runConn :: MonadUnliftIO m => Action m backend -> m () runConn f = do conf <- liftIO $ applyDockerEnv $ defaultMongoConf dbName -- { mgRsPrimary = Just "replicaset" } void $ withMongoPool conf $ runMongoDBPool MongoDB.master f @@ -201,7 +201,7 @@ setupMongo = void $ MongoDB.dropDatabase dbName #endif #ifdef WITH_ZOOKEEPER -runConn :: (MonadIO m, MonadBaseControl IO m) => Action m backend -> m () +runConn :: MonadUnliftIO m => Action m backend -> m () runConn f = do let conf = defaultZookeeperConf {zCoord = "localhost:2181/" ++ T.unpack dbName} void $ withZookeeperPool conf $ runZookeeperPool f @@ -234,7 +234,7 @@ sqlite_database_file = error "Sqlite tests disabled" sqlite_database :: () sqlite_database = error "Sqlite tests disabled" # endif -runConn :: (MonadIO m, MonadBaseControl IO m) => SqlPersistT (LoggingT m) t -> m () +runConn :: MonadUnliftIO m => SqlPersistT (LoggingT m) t -> m () runConn f = do travis <- liftIO isTravis let debugPrint = not travis && _debugOn diff --git a/persistent-test/src/InsertDuplicateUpdate.hs b/persistent-test/src/InsertDuplicateUpdate.hs index 06b9761e6..ef9bee8e2 100644 --- a/persistent-test/src/InsertDuplicateUpdate.hs +++ b/persistent-test/src/InsertDuplicateUpdate.hs @@ -60,7 +60,7 @@ specs = describe "DuplicateKeyUpdate" $ do let newItem = Item "item3" "fresh" Nothing Nothing insertManyOnDuplicateKeyUpdate (newItem : items) - [SomeField ItemDescription] + [copyField ItemDescription] [] dbItems <- map entityVal <$> selectList [] [] sort dbItems @== sort (newItem : items) @@ -79,7 +79,7 @@ specs = describe "DuplicateKeyUpdate" $ do insertManyOnDuplicateKeyUpdate newItems [ copyUnlessEq ItemQuantity (Just 0) - , SomeField ItemPrice + , copyField ItemPrice ] [] dbItems <- sort . fmap entityVal <$> selectList [] [] diff --git a/persistent-test/src/PersistentTest.hs b/persistent-test/src/PersistentTest.hs index cd5c61a55..5f04ad69a 100644 --- a/persistent-test/src/PersistentTest.hs +++ b/persistent-test/src/PersistentTest.hs @@ -21,6 +21,7 @@ import Test.HUnit hiding (Test) import Control.Monad.Trans.Resource (runResourceT) import Test.Hspec.Expectations () import Test.Hspec.QuickCheck(prop) +import UnliftIO (MonadUnliftIO, catch) import Database.Persist @@ -34,7 +35,6 @@ import Database.Persist.MongoDB (toInsertDoc, docToEntityThrow, collectionName, import Database.Persist.TH (mkDeleteCascade, mkSave) import qualified Data.Text as T -import qualified Control.Exception as E # ifdef WITH_POSTGRESQL import Data.List (sort) @@ -45,9 +45,6 @@ import Database.Persist.MySQL() #endif -import qualified Control.Monad.Trans.Control -import Control.Exception.Lifted (catch) - import Control.Monad.IO.Class import Web.PathPieces (PathPiece (..)) @@ -186,7 +183,7 @@ db :: Action IO () -> Assertion db = db' cleanDB #endif -catchPersistException :: Control.Monad.Trans.Control.MonadBaseControl IO m => m a -> b -> m b +catchPersistException :: MonadUnliftIO m => m a -> b -> m b catchPersistException action errValue = do Left res <- (Right `fmap` action) `catch` @@ -1189,14 +1186,6 @@ caseCommitRollback = db $ do c4 <- count filt c4 @== 4 -catch' :: (Control.Monad.Trans.Control.MonadBaseControl IO m, E.Exception e) - => m a -- ^ The computation to run - -> (e -> m a) -- ^ Handler to invoke if an exception is raised - -> m a -catch' a handler = Control.Monad.Trans.Control.control $ \runInIO -> - E.catch (runInIO a) - (\e -> runInIO $ handler e) - #endif -- Test proper polymorphism diff --git a/persistent/ChangeLog.md b/persistent/ChangeLog.md index 8346feb7a..88eaeef6b 100644 --- a/persistent/ChangeLog.md +++ b/persistent/ChangeLog.md @@ -1,3 +1,8 @@ +## 2.8.0 + +* Switch from `MonadBaseControl` to `MonadUnliftIO` +* Reapplies [#723](https://github.com/yesodweb/persistent/pull/723), which was reverted in version 2.7.3. + ## 2.7.3.1 * Improve error messages when failing to parse database results into Persistent records. [#741](https://github.com/yesodweb/persistent/pull/741) diff --git a/persistent/Database/Persist/Class/DeleteCascade.hs b/persistent/Database/Persist/Class/DeleteCascade.hs index c40dfb0b3..82690ffdf 100644 --- a/persistent/Database/Persist/Class/DeleteCascade.hs +++ b/persistent/Database/Persist/Class/DeleteCascade.hs @@ -9,7 +9,7 @@ import Database.Persist.Class.PersistStore import Database.Persist.Class.PersistQuery import Database.Persist.Class.PersistEntity -import qualified Data.Conduit as C +import Data.Conduit import qualified Data.Conduit.List as CL import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Reader (ReaderT, ask, runReaderT) @@ -31,4 +31,4 @@ deleteCascadeWhere :: (MonadIO m, DeleteCascade record backend, PersistQueryWrit deleteCascadeWhere filts = do srcRes <- selectKeysRes filts [] conn <- ask - liftIO $ with srcRes (C.$$ CL.mapM_ (flip runReaderT conn . deleteCascade)) + liftIO $ with srcRes (\src -> runConduit $ src .| CL.mapM_ (flip runReaderT conn . deleteCascade)) diff --git a/persistent/Database/Persist/Class/PersistConfig.hs b/persistent/Database/Persist/Class/PersistConfig.hs index ad2bf1bf5..f5a8b7a4d 100644 --- a/persistent/Database/Persist/Class/PersistConfig.hs +++ b/persistent/Database/Persist/Class/PersistConfig.hs @@ -7,8 +7,7 @@ module Database.Persist.Class.PersistConfig import Data.Aeson (Value (Object)) import Data.Aeson.Types (Parser) -import Control.Monad.IO.Class (MonadIO) -import Control.Monad.Trans.Control (MonadBaseControl) +import Control.Monad.IO.Unlift (MonadUnliftIO) import Control.Applicative as A ((<$>)) import qualified Data.HashMap.Strict as HashMap @@ -31,7 +30,7 @@ class PersistConfig c where createPoolConfig :: c -> IO (PersistConfigPool c) -- | Run a database action by taking a connection from the pool. - runPool :: (MonadBaseControl IO m, MonadIO m) + runPool :: MonadUnliftIO m => c -> PersistConfigBackend c m a -> PersistConfigPool c diff --git a/persistent/Database/Persist/Class/PersistEntity.hs b/persistent/Database/Persist/Class/PersistEntity.hs index 9b8412054..cabe6ccae 100644 --- a/persistent/Database/Persist/Class/PersistEntity.hs +++ b/persistent/Database/Persist/Class/PersistEntity.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-} @@ -43,6 +44,7 @@ import Data.Monoid (mappend) import qualified Data.HashMap.Strict as HM import Data.Typeable (Typeable) import Data.Maybe (isJust) +import GHC.Generics -- | Persistent serialized Haskell records to the database. -- A Database 'Entity' (A row in SQL, a document in MongoDB, etc) @@ -170,17 +172,16 @@ data Filter record = forall typ. PersistField typ => Filter -- your query returns two entities (i.e. @(Entity backend a, -- Entity backend b)@), then you must you use @SELECT ??, ?? -- WHERE ...@, and so on. -data Entity record = PersistEntity record => +data Entity record = Entity { entityKey :: Key record , entityVal :: record } + deriving Typeable -deriving instance (PersistEntity record, Eq (Key record), Eq record) => Eq (Entity record) -deriving instance (PersistEntity record, Ord (Key record), Ord record) => Ord (Entity record) -deriving instance (PersistEntity record, Show (Key record), Show record) => Show (Entity record) -deriving instance (PersistEntity record, Read (Key record), Read record) => Read (Entity record) -#if MIN_VERSION_base(4,7,0) -deriving instance Typeable Entity -#endif +deriving instance (Generic (Key record), Generic record) => Generic (Entity record) +deriving instance (Eq (Key record), Eq record) => Eq (Entity record) +deriving instance (Ord (Key record), Ord record) => Ord (Entity record) +deriving instance (Show (Key record), Show record) => Show (Entity record) +deriving instance (Read (Key record), Read record) => Read (Entity record) -- | Get list of values corresponding to given entity. entityValues :: PersistEntity record => Entity record -> [PersistValue] diff --git a/persistent/Database/Persist/Class/PersistQuery.hs b/persistent/Database/Persist/Class/PersistQuery.hs index 322841d08..96a99d6bd 100644 --- a/persistent/Database/Persist/Class/PersistQuery.hs +++ b/persistent/Database/Persist/Class/PersistQuery.hs @@ -15,7 +15,7 @@ import Database.Persist.Types import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Reader (ReaderT, MonadReader) -import qualified Data.Conduit as C +import Data.Conduit (ConduitM, (.|), await, runConduit) import qualified Data.Conduit.List as CL import Database.Persist.Class.PersistStore import Database.Persist.Class.PersistEntity @@ -30,7 +30,7 @@ class (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backen :: (PersistRecordBackend record backend, MonadIO m1, MonadIO m2) => [Filter record] -> [SelectOpt record] - -> ReaderT backend m1 (Acquire (C.Source m2 (Entity record))) + -> ReaderT backend m1 (Acquire (ConduitM () (Entity record) m2 ())) -- | Get just the first record for the criterion. selectFirst :: (MonadIO m, PersistRecordBackend record backend) @@ -39,14 +39,14 @@ class (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backen -> ReaderT backend m (Maybe (Entity record)) selectFirst filts opts = do srcRes <- selectSourceRes filts (LimitTo 1 : opts) - liftIO $ with srcRes (C.$$ CL.head) + liftIO $ with srcRes (\src -> runConduit $ src .| await) -- | Get the 'Key's of all records matching the given criterion. selectKeysRes :: (MonadIO m1, MonadIO m2, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] - -> ReaderT backend m1 (Acquire (C.Source m2 (Key record))) + -> ReaderT backend m1 (Acquire (ConduitM () (Key record) m2 ())) -- | The total number of records fulfilling the given criterion. count :: (MonadIO m, PersistRecordBackend record backend) @@ -68,7 +68,7 @@ selectSource :: (PersistQueryRead (BaseBackend backend), MonadResource m, PersistEntity record, PersistEntityBackend record ~ BaseBackend (BaseBackend backend), MonadReader backend m, HasPersistBackend backend) => [Filter record] -> [SelectOpt record] - -> C.Source m (Entity record) + -> ConduitM () (Entity record) m () selectSource filts opts = do srcRes <- liftPersist $ selectSourceRes filts opts (releaseKey, src) <- allocateAcquire srcRes @@ -79,7 +79,7 @@ selectSource filts opts = do selectKeys :: (PersistQueryRead (BaseBackend backend), MonadResource m, PersistEntity record, BaseBackend (BaseBackend backend) ~ PersistEntityBackend record, MonadReader backend m, HasPersistBackend backend) => [Filter record] -> [SelectOpt record] - -> C.Source m (Key record) + -> ConduitM () (Key record) m () selectKeys filts opts = do srcRes <- liftPersist $ selectKeysRes filts opts (releaseKey, src) <- allocateAcquire srcRes @@ -93,7 +93,7 @@ selectList :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record -> ReaderT backend m [Entity record] selectList filts opts = do srcRes <- selectSourceRes filts opts - liftIO $ with srcRes (C.$$ CL.consume) + liftIO $ with srcRes (\src -> runConduit $ src .| CL.consume) -- | Call 'selectKeys' but return the result as a list. selectKeysList :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend) @@ -102,4 +102,4 @@ selectKeysList :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend rec -> ReaderT backend m [Key record] selectKeysList filts opts = do srcRes <- selectKeysRes filts opts - liftIO $ with srcRes (C.$$ CL.consume) + liftIO $ with srcRes (\src -> runConduit $ src .| CL.consume) diff --git a/persistent/Database/Persist/Class/PersistStore.hs b/persistent/Database/Persist/Class/PersistStore.hs index 8fc8471e6..30d4bcc66 100644 --- a/persistent/Database/Persist/Class/PersistStore.hs +++ b/persistent/Database/Persist/Class/PersistStore.hs @@ -23,7 +23,7 @@ module Database.Persist.Class.PersistStore import qualified Data.Text as T import Control.Monad.IO.Class (MonadIO, liftIO) -import Control.Exception.Lifted (throwIO) +import Control.Exception (throwIO) import Control.Monad.Trans.Reader (ReaderT) import Control.Monad.Reader (MonadReader (ask), runReaderT) import Database.Persist.Class.PersistEntity diff --git a/persistent/Database/Persist/Sql/Migration.hs b/persistent/Database/Persist/Sql/Migration.hs index 16287341d..52a33540d 100644 --- a/persistent/Database/Persist/Sql/Migration.hs +++ b/persistent/Database/Persist/Sql/Migration.hs @@ -13,9 +13,8 @@ module Database.Persist.Sql.Migration ) where -import Control.Monad.Trans.Control (MonadBaseControl) import Control.Monad.Trans.Class (MonadTrans (..)) -import Control.Monad.IO.Class +import Control.Monad.IO.Unlift import Control.Monad.Trans.Writer import Control.Monad.Trans.Reader (ReaderT (..), ask) import Control.Monad (liftM, unless) @@ -23,10 +22,10 @@ import Data.Text (Text, unpack, snoc, isPrefixOf, pack) import qualified Data.Text.IO import System.IO import System.IO.Silently (hSilence) -import Control.Monad.Trans.Control (liftBaseOp_) import Database.Persist.Sql.Types import Database.Persist.Sql.Raw import Database.Persist.Types +import Database.Persist.Sql.Orphan.PersistStore() allSql :: CautiousMigration -> [Sql] allSql = map snd @@ -79,10 +78,11 @@ runMigration m = runMigration' m False >> return () -- | Same as 'runMigration', but returns a list of the SQL commands executed -- instead of printing them to stderr. -runMigrationSilent :: (MonadBaseControl IO m, MonadIO m) +runMigrationSilent :: (MonadUnliftIO m, MonadIO m) => Migration -> ReaderT SqlBackend m [Text] -runMigrationSilent m = liftBaseOp_ (hSilence [stderr]) $ runMigration' m True +runMigrationSilent m = withRunInIO $ \run -> + hSilence [stderr] $ run $ runMigration' m True -- | Run the given migration against the database. If the migration fails -- to parse, or there are any unsafe migrations, then this will error at diff --git a/persistent/Database/Persist/Sql/Orphan/PersistQuery.hs b/persistent/Database/Persist/Sql/Orphan/PersistQuery.hs index 017463360..9e9976cd2 100644 --- a/persistent/Database/Persist/Sql/Orphan/PersistQuery.hs +++ b/persistent/Database/Persist/Sql/Orphan/PersistQuery.hs @@ -57,7 +57,7 @@ instance PersistQueryRead SqlBackend where selectSourceRes filts opts = do conn <- ask srcRes <- rawQueryRes (sql conn) (getFiltsValues conn filts) - return $ fmap ($= CL.mapM parse) srcRes + return $ fmap (.| CL.mapM parse) srcRes where (limit, offset, orders) = limitOffsetOrder opts @@ -85,7 +85,7 @@ instance PersistQueryRead SqlBackend where selectKeysRes filts opts = do conn <- ask srcRes <- rawQueryRes (sql conn) (getFiltsValues conn filts) - return $ fmap ($= CL.mapM parse) srcRes + return $ fmap (.| CL.mapM parse) srcRes where t = entityDef $ dummyFromFilts filts cols conn = T.intercalate "," $ dbIdColumns conn t diff --git a/persistent/Database/Persist/Sql/Orphan/PersistStore.hs b/persistent/Database/Persist/Sql/Orphan/PersistStore.hs index 84699c54a..93a555030 100644 --- a/persistent/Database/Persist/Sql/Orphan/PersistStore.hs +++ b/persistent/Database/Persist/Sql/Orphan/PersistStore.hs @@ -23,7 +23,7 @@ import Database.Persist import Database.Persist.Sql.Types import Database.Persist.Sql.Raw import Database.Persist.Sql.Util (dbIdColumns, keyAndEntityColumnNames) -import qualified Data.Conduit as C +import Data.Conduit import qualified Data.Conduit.List as CL import qualified Data.Text as T import Data.Text (Text, unpack) @@ -32,6 +32,7 @@ import Control.Monad.IO.Class import Data.ByteString.Char8 (readInteger) import Data.Maybe (isJust) import Data.List (find) +import Data.Void (Void) import Control.Monad.Trans.Reader (ReaderT, ask, withReaderT) import Data.Acquire (with) import Data.Int (Int64) @@ -39,17 +40,17 @@ import Web.PathPieces (PathPiece) import Web.HttpApiData (ToHttpApiData, FromHttpApiData) import Database.Persist.Sql.Class (PersistFieldSql) import qualified Data.Aeson as A -import Control.Exception.Lifted (throwIO) +import Control.Exception (throwIO) import Database.Persist.Class () withRawQuery :: MonadIO m => Text -> [PersistValue] - -> C.Sink [PersistValue] IO a + -> ConduitM [PersistValue] Void IO a -> ReaderT SqlBackend m a withRawQuery sql vals sink = do srcRes <- rawQueryRes sql vals - liftIO $ with srcRes (C.$$ sink) + liftIO $ with srcRes (\src -> runConduit $ src .| sink) toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record toSqlKey = fromBackendKey . SqlBackendKey diff --git a/persistent/Database/Persist/Sql/Raw.hs b/persistent/Database/Persist/Sql/Raw.hs index 804c7cb1b..b3d777b18 100644 --- a/persistent/Database/Persist/Sql/Raw.hs +++ b/persistent/Database/Persist/Sql/Raw.hs @@ -24,7 +24,7 @@ import Control.Monad.Trans.Resource (MonadResource,release) rawQuery :: (MonadResource m, MonadReader env m, HasPersistBackend env, BaseBackend env ~ SqlBackend) => Text -> [PersistValue] - -> Source m [PersistValue] + -> ConduitM () [PersistValue] m () rawQuery sql vals = do srcRes <- liftPersist $ rawQueryRes sql vals (releaseKey, src) <- allocateAcquire srcRes @@ -35,7 +35,7 @@ rawQueryRes :: (MonadIO m1, MonadIO m2, IsSqlBackend env) => Text -> [PersistValue] - -> ReaderT env m1 (Acquire (Source m2 [PersistValue])) + -> ReaderT env m1 (Acquire (ConduitM () [PersistValue] m2 ())) rawQueryRes sql vals = do conn <- persistBackend `liftM` ask let make = do @@ -47,20 +47,20 @@ rawQueryRes sql vals = do stmtQuery stmt vals -- | Execute a raw SQL statement -rawExecute :: MonadIO m +rawExecute :: (MonadIO m, BackendCompatible SqlBackend backend) => Text -- ^ SQL statement, possibly with placeholders. -> [PersistValue] -- ^ Values to fill the placeholders. - -> ReaderT SqlBackend m () + -> ReaderT backend m () rawExecute x y = liftM (const ()) $ rawExecuteCount x y -- | Execute a raw SQL statement and return the number of -- rows it has modified. -rawExecuteCount :: (MonadIO m, IsSqlBackend backend) +rawExecuteCount :: (MonadIO m, BackendCompatible SqlBackend backend) => Text -- ^ SQL statement, possibly with placeholders. -> [PersistValue] -- ^ Values to fill the placeholders. -> ReaderT backend m Int64 rawExecuteCount sql vals = do - conn <- persistBackend `liftM` ask + conn <- projectBackend `liftM` ask runLoggingT (logDebugNS (pack "SQL") $ T.append sql $ pack $ "; " ++ show vals) (connLogFunc conn) stmt <- getStmt sql @@ -69,10 +69,10 @@ rawExecuteCount sql vals = do return res getStmt - :: (MonadIO m, IsSqlBackend backend) + :: (MonadIO m, BackendCompatible SqlBackend backend) => Text -> ReaderT backend m Statement getStmt sql = do - conn <- persistBackend `liftM` ask + conn <- projectBackend `liftM` ask liftIO $ getStmtConn conn sql getStmtConn :: SqlBackend -> Text -> IO Statement @@ -218,7 +218,7 @@ rawSql stmt = run withStmt' colSubsts params sink = do srcRes <- rawQueryRes sql params - liftIO $ with srcRes ($$ sink) + liftIO $ with srcRes (\src -> runConduit $ src .| sink) where sql = T.concat $ makeSubsts colSubsts $ T.splitOn placeholder stmt placeholder = "??" diff --git a/persistent/Database/Persist/Sql/Run.hs b/persistent/Database/Persist/Sql/Run.hs index bd63ec251..e7c0636fd 100644 --- a/persistent/Database/Persist/Sql/Run.hs +++ b/persistent/Database/Persist/Sql/Run.hs @@ -7,17 +7,15 @@ module Database.Persist.Sql.Run where import Database.Persist.Class.PersistStore import Database.Persist.Sql.Types import Database.Persist.Sql.Raw -import Control.Monad.Trans.Control import Data.Pool as P import Control.Monad.Trans.Reader hiding (local) import Control.Monad.Trans.Resource import Control.Monad.Logger -import Control.Monad.Base -import Control.Exception.Lifted (onException, bracket) -import Control.Monad.IO.Class +import Control.Exception (onException, bracket) +import Control.Monad.IO.Unlift import Control.Exception (mask) import System.Timeout (timeout) -import Data.IORef (readIORef, writeIORef, newIORef) +import Data.IORef (readIORef) import qualified Data.Map as Map import Control.Monad (liftM) @@ -28,22 +26,22 @@ import Control.Monad (liftM) -- was buggy and caused more problems than it solved. Since version 2.1.2, it -- performs no timeout checks. runSqlPool - :: (MonadBaseControl IO m, IsSqlBackend backend) + :: (MonadUnliftIO m, IsSqlBackend backend) => ReaderT backend m a -> Pool backend -> m a -runSqlPool r pconn = withResource pconn $ runSqlConn r +runSqlPool r pconn = withRunInIO $ \run -> withResource pconn $ run . runSqlConn r -- | Like 'withResource', but times out the operation if resource -- allocation does not complete within the given timeout period. -- -- @since 2.0.0 withResourceTimeout - :: forall a m b. (MonadBaseControl IO m) + :: forall a m b. (MonadUnliftIO m) => Int -- ^ Timeout period in microseconds -> Pool a -> (a -> m b) -> m (Maybe b) {-# SPECIALIZE withResourceTimeout :: Int -> Pool a -> (a -> IO b) -> IO (Maybe b) #-} -withResourceTimeout ms pool act = control $ \runInIO -> mask $ \restore -> do +withResourceTimeout ms pool act = withRunInIO $ \runInIO -> mask $ \restore -> do mres <- timeout ms $ takeResource pool case mres of Nothing -> runInIO $ return (Nothing :: Maybe b) @@ -54,8 +52,8 @@ withResourceTimeout ms pool act = control $ \runInIO -> mask $ \restore -> do return ret {-# INLINABLE withResourceTimeout #-} -runSqlConn :: (MonadBaseControl IO m, IsSqlBackend backend) => ReaderT backend m a -> backend -> m a -runSqlConn r conn = control $ \runInIO -> mask $ \restore -> do +runSqlConn :: (MonadUnliftIO m, IsSqlBackend backend) => ReaderT backend m a -> backend -> m a +runSqlConn r conn = withRunInIO $ \runInIO -> mask $ \restore -> do let conn' = persistBackend conn getter = getStmtConn conn' restore $ connBegin conn' getter @@ -81,16 +79,18 @@ liftSqlPersistMPool liftSqlPersistMPool x pool = liftIO (runSqlPersistMPool x pool) withSqlPool - :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, IsSqlBackend backend) + :: (MonadLogger m, MonadUnliftIO m, IsSqlBackend backend) => (LogFunc -> IO backend) -- ^ create a new connection -> Int -- ^ connection count -> (Pool backend -> m a) -> m a -withSqlPool mkConn connCount f = - bracket (createSqlPool mkConn connCount) (liftIO . destroyAllResources) f +withSqlPool mkConn connCount f = withUnliftIO $ \u -> bracket + (unliftIO u $ createSqlPool mkConn connCount) + destroyAllResources + (unliftIO u . f) createSqlPool - :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, IsSqlBackend backend) + :: (MonadLogger m, MonadUnliftIO m, IsSqlBackend backend) => (LogFunc -> IO backend) -> Int -> m (Pool backend) @@ -104,21 +104,19 @@ createSqlPool mkConn size = do -- FIXME: in a future release, switch over to the new askLoggerIO function -- added in monad-logger 0.3.10. That function was not available at the time -- this code was written. -askLogFunc :: forall m. (MonadBaseControl IO m, MonadLogger m) => m LogFunc -askLogFunc = do - ref <- liftBase $ newIORef undefined - liftBaseWith $ \run -> writeIORef ref run - runInBase <- liftBase $ readIORef ref - return $ \a b c d -> do - _ <- runInBase (monadLoggerLog a b c d) - return () +askLogFunc :: forall m. (MonadUnliftIO m, MonadLogger m) => m LogFunc +askLogFunc = withRunInIO $ \run -> + return $ \a b c d -> run (monadLoggerLog a b c d) withSqlConn - :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, IsSqlBackend backend) + :: (MonadUnliftIO m, MonadLogger m, IsSqlBackend backend) => (LogFunc -> IO backend) -> (backend -> m a) -> m a withSqlConn open f = do logFunc <- askLogFunc - bracket (liftIO $ open logFunc) (liftIO . close') f + withRunInIO $ \run -> bracket + (open logFunc) + close' + (run . f) close' :: (IsSqlBackend backend) => backend -> IO () close' conn = do diff --git a/persistent/Database/Persist/Sql/Types/Internal.hs b/persistent/Database/Persist/Sql/Types/Internal.hs index 4fd486c08..998ffc37f 100644 --- a/persistent/Database/Persist/Sql/Types/Internal.hs +++ b/persistent/Database/Persist/Sql/Types/Internal.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -28,7 +29,7 @@ import Control.Monad.Logger (LogSource, LogLevel) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Reader (ReaderT, runReaderT, ask) import Data.Acquire (Acquire) -import Data.Conduit (Source) +import Data.Conduit (ConduitM) import Data.Int (Int64) import Data.IORef (IORef) import Data.Map (Map) @@ -39,6 +40,7 @@ import Database.Persist.Class , PersistQueryRead, PersistQueryWrite , PersistStoreRead, PersistStoreWrite , PersistUniqueRead, PersistUniqueWrite + , BackendCompatible(..) ) import Database.Persist.Class.PersistStore (IsPersistBackend (..)) import Database.Persist.Types @@ -57,7 +59,7 @@ data Statement = Statement , stmtExecute :: [PersistValue] -> IO Int64 , stmtQuery :: forall m. MonadIO m => [PersistValue] - -> Acquire (Source m [PersistValue]) + -> Acquire (ConduitM () [PersistValue] m ()) } data SqlBackend = SqlBackend @@ -130,7 +132,7 @@ readToUnknown ma = do -- | A constraint synonym which witnesses that a backend is SQL and can run read queries. type SqlBackendCanRead backend = - ( IsSqlBackend backend + ( BackendCompatible SqlBackend backend , PersistQueryRead backend, PersistStoreRead backend, PersistUniqueRead backend ) -- | A constraint synonym which witnesses that a backend is SQL and can run read and write queries. diff --git a/persistent/persistent.cabal b/persistent/persistent.cabal index 929fe4d9c..4a8e2cd28 100644 --- a/persistent/persistent.cabal +++ b/persistent/persistent.cabal @@ -1,5 +1,5 @@ name: persistent -version: 2.7.3.1 +version: 2.8.0 license: MIT license-file: LICENSE author: Michael Snoyman @@ -29,17 +29,13 @@ library , old-locale , text >= 0.8 , containers >= 0.2 - , conduit >= 1.0 - , resourcet >= 1.1 - , exceptions >= 0.6 - , monad-control >= 0.3 - , lifted-base >= 0.1 + , conduit >= 1.2.8 + , resourcet >= 1.1.10 , resource-pool >= 0.2.2.0 , path-pieces >= 0.1 , http-api-data >= 0.2 && < 0.4 , aeson >= 0.5 - , monad-logger >= 0.3 - , transformers-base + , monad-logger >= 0.3.28 , base64-bytestring , unordered-containers , vector @@ -53,6 +49,8 @@ library , fast-logger >= 2.1 , scientific , tagged + , unliftio-core + , void exposed-modules: Database.Persist Database.Persist.Quasi @@ -89,7 +87,7 @@ test-suite test type: exitcode-stdio-1.0 main-is: test/main.hs - build-depends: base >= 4.6 && < 5 + build-depends: base >= 4.8 && < 5 , hspec >= 1.3 , containers , text @@ -112,7 +110,6 @@ test-suite test , scientific , tagged , fast-logger >= 2.1 - , lifted-base >= 0.1 , mtl , template-haskell , resource-pool diff --git a/stack.yaml b/stack.yaml index f87b07dab..4d42efc35 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-8.2 +resolver: lts-10.4 packages: - ./persistent - ./persistent-template @@ -8,3 +8,13 @@ packages: - ./persistent-mysql - ./persistent-postgresql - ./persistent-redis +extra-deps: +- monad-logger-0.3.28.1 +- mysql-simple-0.4.4 + +- mono-traversable-1.0.8.1 +- unliftio-0.2.4.0 +- unliftio-core-0.1.1.0 +- async-2.1.1.1 +- typed-process-0.2.1.0 +- resourcet-1.1.11 diff --git a/travis/run.sh b/travis/run.sh index 917089a9b..3de12da9e 100755 --- a/travis/run.sh +++ b/travis/run.sh @@ -2,13 +2,19 @@ set -euxo pipefail -ARGS="$ARGS --no-terminal --install-ghc" -stack $ARGS solver --update-config - if [ "$BACKEND" = "none" ] then PACKAGES=$(stack --install-ghc query locals | grep '^ *path' | sed 's@^ *path:@@' | grep -v 'persistent-test' ) - exec stack $ARGS test --pedantic $PACKAGES + + PEDANTIC="--pedantic" + # Turn off pedantic for lts-7, due to the sometimes invalid + # redundant constraint warnings. + if [ "$ARGS" = "--resolver lts-7" ] + then + PEDANTIC="" + fi + + exec stack $ARGS --no-terminal test $PEDANTIC $PACKAGES else if [ "$BACKEND" = "postgresql" ] then @@ -19,5 +25,5 @@ else fi cd persistent-test - exec stack $ARGS test --pedantic --fast persistent-test --flag persistent-test:$BACKEND --exec persistent-test + exec stack $ARGS --no-terminal test --pedantic --fast persistent-test --flag persistent-test:$BACKEND --exec persistent-test fi