packages feed

persistent-mtl 0.4.0.0 → 0.5.0.0

raw patch · 32 files changed

+2415/−2546 lines, 32 filesdep +tasty-autocollectdep ~basedep ~conduitdep ~containersPVP ok

version bump matches the API change (PVP)

Dependencies added: tasty-autocollect

Dependency ranges changed: base, conduit, containers, exceptions, monad-logger, persistent, resourcet, text, transformers, unliftio, unliftio-core, unliftio-pool

API changes (from Hackage documentation)

- Database.Persist.Monad: data SqlQueryT m a
- Database.Persist.Monad: instance ((TypeError ...), GHC.Base.Monad m) => Control.Monad.IO.Class.MonadIO (Database.Persist.Monad.SqlTransaction m)
- Database.Persist.Monad: instance (Database.Persist.Monad.Class.MonadSqlQuery m, Control.Monad.IO.Unlift.MonadUnliftIO m) => Database.Persist.Monad.Class.MonadSqlQuery (Database.Persist.Monad.SqlTransaction m)
- Database.Persist.Monad: instance Control.Monad.IO.Rerunnable.MonadRerunnableIO m => Control.Monad.IO.Rerunnable.MonadRerunnableIO (Database.Persist.Monad.SqlTransaction m)
- Database.Persist.Monad: instance GHC.Base.Applicative m => GHC.Base.Applicative (Database.Persist.Monad.SqlTransaction m)
- Database.Persist.Monad: instance GHC.Base.Functor m => GHC.Base.Functor (Database.Persist.Monad.SqlTransaction m)
- Database.Persist.Monad: instance GHC.Base.Monad m => GHC.Base.Monad (Database.Persist.Monad.SqlTransaction m)
- Database.Persist.Monad: rerunnableLift :: MonadUnliftIO m => m a -> SqlTransaction m a
+ Control.Monad.Trans.Rerunnable: class MonadRerunnableTrans t
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.Except.ExceptT e)
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.Reader.ReaderT r)
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.State.Lazy.StateT s)
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.State.Strict.StateT s)
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans Control.Monad.Trans.Identity.IdentityT
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans Control.Monad.Trans.Maybe.MaybeT
+ Control.Monad.Trans.Rerunnable: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans Control.Monad.Trans.Resource.Internal.ResourceT
+ Control.Monad.Trans.Rerunnable: instance GHC.Base.Monoid w => Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.RWS.Lazy.RWST r w s)
+ Control.Monad.Trans.Rerunnable: instance GHC.Base.Monoid w => Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.RWS.Strict.RWST r w s)
+ Control.Monad.Trans.Rerunnable: instance GHC.Base.Monoid w => Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.Writer.Lazy.WriterT w)
+ Control.Monad.Trans.Rerunnable: instance GHC.Base.Monoid w => Control.Monad.Trans.Rerunnable.MonadRerunnableTrans (Control.Monad.Trans.Writer.Strict.WriterT w)
+ Control.Monad.Trans.Rerunnable: rerunnableLift :: (MonadRerunnableTrans t, Monad m) => m a -> t m a
+ Database.Persist.Monad: SqlQueryT :: ReaderT SqlQueryEnv m a -> SqlQueryT m a
+ Database.Persist.Monad: [retryCallback] :: SqlQueryEnv -> SomeException -> IO ()
+ Database.Persist.Monad: [unSqlQueryT] :: SqlQueryT m a -> ReaderT SqlQueryEnv m a
+ Database.Persist.Monad: catchSqlTransaction :: (MonadUnliftIO m, Exception e) => SqlTransaction m a -> (e -> SqlTransaction m a) -> SqlTransaction m a
+ Database.Persist.Monad: getSqlBackendPool :: Monad m => SqlQueryT m (Pool SqlBackend)
+ Database.Persist.Monad: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Database.Persist.Monad.SqlQueryT m)
+ Database.Persist.Monad: newtype SqlQueryT m a
+ Database.Persist.Monad.Internal.PersistentShim: class SafeToInsert a
+ Database.Persist.Monad.Internal.SqlTransaction: SqlTransactionEnv :: SqlBackend -> (SomeException -> Bool) -> SqlTransactionEnv
+ Database.Persist.Monad.Internal.SqlTransaction: UnsafeSqlTransaction :: ReaderT SqlTransactionEnv m a -> SqlTransaction m a
+ Database.Persist.Monad.Internal.SqlTransaction: [ignoreCatch] :: SqlTransactionEnv -> SomeException -> Bool
+ Database.Persist.Monad.Internal.SqlTransaction: [sqlBackend] :: SqlTransactionEnv -> SqlBackend
+ Database.Persist.Monad.Internal.SqlTransaction: [unSqlTransaction] :: SqlTransaction m a -> ReaderT SqlTransactionEnv m a
+ Database.Persist.Monad.Internal.SqlTransaction: catchSqlTransaction :: (MonadUnliftIO m, Exception e) => SqlTransaction m a -> (e -> SqlTransaction m a) -> SqlTransaction m a
+ Database.Persist.Monad.Internal.SqlTransaction: data SqlTransactionEnv
+ Database.Persist.Monad.Internal.SqlTransaction: instance ((TypeError ...), GHC.Base.Monad m) => Control.Monad.IO.Class.MonadIO (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: instance (Database.Persist.Monad.Class.MonadSqlQuery m, Control.Monad.IO.Unlift.MonadUnliftIO m) => Database.Persist.Monad.Class.MonadSqlQuery (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: instance Control.Monad.IO.Rerunnable.MonadRerunnableIO m => Control.Monad.IO.Rerunnable.MonadRerunnableIO (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: instance Control.Monad.Trans.Rerunnable.MonadRerunnableTrans Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction
+ Database.Persist.Monad.Internal.SqlTransaction: instance GHC.Base.Applicative m => GHC.Base.Applicative (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: instance GHC.Base.Functor m => GHC.Base.Functor (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: instance GHC.Base.Monad m => GHC.Base.Monad (Database.Persist.Monad.Internal.SqlTransaction.SqlTransaction m)
+ Database.Persist.Monad.Internal.SqlTransaction: newtype SqlTransaction m a
+ Database.Persist.Monad.Internal.SqlTransaction: runSqlTransaction :: MonadUnliftIO m => SqlTransactionEnv -> SqlTransaction m a -> m a
+ Database.Persist.Sql.Shim: (!=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v
+ Database.Persist.Sql.Shim: (*=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v
+ Database.Persist.Sql.Shim: (+=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v
+ Database.Persist.Sql.Shim: (-=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v
+ Database.Persist.Sql.Shim: (/<-.) :: forall v typ. PersistField typ => EntityField v typ -> [typ] -> Filter v
+ Database.Persist.Sql.Shim: (/=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v
+ Database.Persist.Sql.Shim: (<-.) :: forall v typ. PersistField typ => EntityField v typ -> [typ] -> Filter v
+ Database.Persist.Sql.Shim: (<.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v
+ Database.Persist.Sql.Shim: (<=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v
+ Database.Persist.Sql.Shim: (=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Update v
+ Database.Persist.Sql.Shim: (==.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v
+ Database.Persist.Sql.Shim: (>.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v
+ Database.Persist.Sql.Shim: (>=.) :: forall v typ. PersistField typ => EntityField v typ -> typ -> Filter v
+ Database.Persist.Sql.Shim: (||.) :: [Filter v] -> [Filter v] -> [Filter v]
+ Database.Persist.Sql.Shim: --
+ Database.Persist.Sql.Shim: -- <a>EntityField</a> values polymorphically. See the documentation on
+ Database.Persist.Sql.Shim: -- <a>SymbolToField</a> for more information.
+ Database.Persist.Sql.Shim: -- <tt>OverloadedLabels</tt> language extension to refer to
+ Database.Persist.Sql.Shim: -- As of <tt>persistent-2.11.0.0</tt>, it's possible to use the
+ Database.Persist.Sql.Shim: -- belongs to and the additional type of that field.
+ Database.Persist.Sql.Shim: -- can specify a Primary key made up of unique values.
+ Database.Persist.Sql.Shim: -- | Unique keys besides the <a>Key</a>.
+ Database.Persist.Sql.Shim: Active :: Checkmark
+ Database.Persist.Sql.Shim: Add :: PersistUpdate
+ Database.Persist.Sql.Shim: Asc :: EntityField record typ -> SelectOpt record
+ Database.Persist.Sql.Shim: Assign :: PersistUpdate
+ Database.Persist.Sql.Shim: BackendFilter :: BackendSpecificFilter (PersistEntityBackend record) record -> Filter record
+ Database.Persist.Sql.Shim: BackendSpecificFilter :: Text -> PersistFilter
+ Database.Persist.Sql.Shim: BackendSpecificUpdate :: Text -> PersistUpdate
+ Database.Persist.Sql.Shim: BackendUpdate :: BackendSpecificUpdate (PersistEntityBackend record) record -> Update record
+ Database.Persist.Sql.Shim: ByMaybeAttr :: WhyNullable
+ Database.Persist.Sql.Shim: ByNullableAttr :: WhyNullable
+ Database.Persist.Sql.Shim: Cascade :: CascadeAction
+ Database.Persist.Sql.Shim: Column :: !FieldNameDB -> !Bool -> !SqlType -> !Maybe Text -> !Maybe Text -> !Maybe ConstraintNameDB -> !Maybe Integer -> !Maybe ColumnReference -> Column
+ Database.Persist.Sql.Shim: ColumnReference :: !EntityNameDB -> !ConstraintNameDB -> !FieldCascade -> ColumnReference
+ Database.Persist.Sql.Shim: CompositeDef :: !NonEmpty FieldDef -> ![Attr] -> CompositeDef
+ Database.Persist.Sql.Shim: ConnectionPoolConfig :: Int -> NominalDiffTime -> Int -> ConnectionPoolConfig
+ Database.Persist.Sql.Shim: ConstraintNameDB :: Text -> ConstraintNameDB
+ Database.Persist.Sql.Shim: ConstraintNameHS :: Text -> ConstraintNameHS
+ Database.Persist.Sql.Shim: Couldn'tGetSQLConnection :: PersistentSqlException
+ Database.Persist.Sql.Shim: DbSpecific :: LiteralType
+ Database.Persist.Sql.Shim: Desc :: EntityField record typ -> SelectOpt record
+ Database.Persist.Sql.Shim: Divide :: PersistUpdate
+ Database.Persist.Sql.Shim: EmbedEntityDef :: EntityNameHS -> [EmbedFieldDef] -> EmbedEntityDef
+ Database.Persist.Sql.Shim: EmbedFieldDef :: FieldNameDB -> Maybe (Either SelfEmbed EntityNameHS) -> EmbedFieldDef
+ Database.Persist.Sql.Shim: EmbedRef :: EntityNameHS -> ReferenceDef
+ Database.Persist.Sql.Shim: Entity :: Key record -> record -> Entity record
+ Database.Persist.Sql.Shim: EntityIdField :: !FieldDef -> EntityIdDef
+ Database.Persist.Sql.Shim: EntityIdNaturalKey :: !CompositeDef -> EntityIdDef
+ Database.Persist.Sql.Shim: EntityNameDB :: Text -> EntityNameDB
+ Database.Persist.Sql.Shim: EntityNameHS :: Text -> EntityNameHS
+ Database.Persist.Sql.Shim: EntityWithPrefix :: Entity record -> EntityWithPrefix (prefix :: Symbol) record
+ Database.Persist.Sql.Shim: Eq :: PersistFilter
+ Database.Persist.Sql.Shim: Escaped :: LiteralType
+ Database.Persist.Sql.Shim: FTApp :: FieldType -> FieldType -> FieldType
+ Database.Persist.Sql.Shim: FTList :: FieldType -> FieldType
+ Database.Persist.Sql.Shim: FTLit :: FieldTypeLit -> FieldType
+ Database.Persist.Sql.Shim: FTTypeCon :: Maybe Text -> Text -> FieldType
+ Database.Persist.Sql.Shim: FTTypePromoted :: Text -> FieldType
+ Database.Persist.Sql.Shim: FieldAttrConstraint :: Text -> FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrDefault :: Text -> FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrMaxlen :: Integer -> FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrMaybe :: FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrMigrationOnly :: FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrNoreference :: FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrNullable :: FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrOther :: Text -> FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrReference :: Text -> FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrSafeToRemove :: FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrSql :: Text -> FieldAttr
+ Database.Persist.Sql.Shim: FieldAttrSqltype :: Text -> FieldAttr
+ Database.Persist.Sql.Shim: FieldCascade :: !Maybe CascadeAction -> !Maybe CascadeAction -> FieldCascade
+ Database.Persist.Sql.Shim: FieldDef :: !FieldNameHS -> !FieldNameDB -> !FieldType -> !SqlType -> ![FieldAttr] -> !Bool -> !ReferenceDef -> !FieldCascade -> !Maybe Text -> !Maybe Text -> !Bool -> FieldDef
+ Database.Persist.Sql.Shim: FieldNameDB :: Text -> FieldNameDB
+ Database.Persist.Sql.Shim: FieldNameHS :: Text -> FieldNameHS
+ Database.Persist.Sql.Shim: Filter :: EntityField record typ -> FilterValue typ -> PersistFilter -> Filter record
+ Database.Persist.Sql.Shim: FilterAnd :: [Filter record] -> Filter record
+ Database.Persist.Sql.Shim: FilterOr :: [Filter record] -> Filter record
+ Database.Persist.Sql.Shim: ForeignDef :: !EntityNameHS -> !EntityNameDB -> !ConstraintNameHS -> !ConstraintNameDB -> !FieldCascade -> ![(ForeignFieldDef, ForeignFieldDef)] -> ![Attr] -> Bool -> Bool -> ForeignDef
+ Database.Persist.Sql.Shim: ForeignRef :: !EntityNameHS -> ReferenceDef
+ Database.Persist.Sql.Shim: Ge :: PersistFilter
+ Database.Persist.Sql.Shim: Gt :: PersistFilter
+ Database.Persist.Sql.Shim: ISRInsertGet :: Text -> Text -> InsertSqlResult
+ Database.Persist.Sql.Shim: ISRManyKeys :: Text -> [PersistValue] -> InsertSqlResult
+ Database.Persist.Sql.Shim: ISRSingle :: Text -> InsertSqlResult
+ Database.Persist.Sql.Shim: In :: PersistFilter
+ Database.Persist.Sql.Shim: Inactive :: Checkmark
+ Database.Persist.Sql.Shim: KeyNotFound :: String -> UpdateException
+ Database.Persist.Sql.Shim: Le :: PersistFilter
+ Database.Persist.Sql.Shim: LimitTo :: Int -> SelectOpt record
+ Database.Persist.Sql.Shim: Lt :: PersistFilter
+ Database.Persist.Sql.Shim: Multiply :: PersistUpdate
+ Database.Persist.Sql.Shim: Ne :: PersistFilter
+ Database.Persist.Sql.Shim: NoReference :: ReferenceDef
+ Database.Persist.Sql.Shim: NotIn :: PersistFilter
+ Database.Persist.Sql.Shim: NotNullable :: IsNullable
+ Database.Persist.Sql.Shim: Nullable :: !WhyNullable -> IsNullable
+ Database.Persist.Sql.Shim: OffsetBy :: Int -> SelectOpt record
+ Database.Persist.Sql.Shim: OverflowNatural :: Natural -> OverflowNatural
+ Database.Persist.Sql.Shim: PersistArray :: [PersistValue] -> PersistValue
+ Database.Persist.Sql.Shim: PersistBool :: Bool -> PersistValue
+ Database.Persist.Sql.Shim: PersistByteString :: ByteString -> PersistValue
+ Database.Persist.Sql.Shim: PersistDay :: Day -> PersistValue
+ Database.Persist.Sql.Shim: PersistDouble :: Double -> PersistValue
+ Database.Persist.Sql.Shim: PersistError :: Text -> PersistException
+ Database.Persist.Sql.Shim: PersistForeignConstraintUnmet :: Text -> PersistException
+ Database.Persist.Sql.Shim: PersistInt64 :: Int64 -> PersistValue
+ Database.Persist.Sql.Shim: PersistInvalidField :: Text -> PersistException
+ Database.Persist.Sql.Shim: PersistList :: [PersistValue] -> PersistValue
+ Database.Persist.Sql.Shim: PersistLiteral_ :: LiteralType -> ByteString -> PersistValue
+ Database.Persist.Sql.Shim: PersistMap :: [(Text, PersistValue)] -> PersistValue
+ Database.Persist.Sql.Shim: PersistMarshalError :: Text -> PersistException
+ Database.Persist.Sql.Shim: PersistMongoDBError :: Text -> PersistException
+ Database.Persist.Sql.Shim: PersistMongoDBUnsupported :: Text -> PersistException
+ Database.Persist.Sql.Shim: PersistNull :: PersistValue
+ Database.Persist.Sql.Shim: PersistObjectId :: ByteString -> PersistValue
+ Database.Persist.Sql.Shim: PersistRational :: Rational -> PersistValue
+ Database.Persist.Sql.Shim: PersistText :: Text -> PersistValue
+ Database.Persist.Sql.Shim: PersistTimeOfDay :: TimeOfDay -> PersistValue
+ Database.Persist.Sql.Shim: PersistUTCTime :: UTCTime -> PersistValue
+ Database.Persist.Sql.Shim: PersistUnsafeMigrationException :: [(Bool, Sql)] -> PersistUnsafeMigrationException
+ Database.Persist.Sql.Shim: PrefixExcluded :: FilterTablePrefix
+ Database.Persist.Sql.Shim: PrefixTableName :: FilterTablePrefix
+ Database.Persist.Sql.Shim: ReadCommitted :: IsolationLevel
+ Database.Persist.Sql.Shim: ReadUncommitted :: IsolationLevel
+ Database.Persist.Sql.Shim: RepeatableRead :: IsolationLevel
+ Database.Persist.Sql.Shim: Restrict :: CascadeAction
+ Database.Persist.Sql.Shim: SelfReference :: ReferenceDef
+ Database.Persist.Sql.Shim: Serializable :: IsolationLevel
+ Database.Persist.Sql.Shim: SetDefault :: CascadeAction
+ Database.Persist.Sql.Shim: SetNull :: CascadeAction
+ Database.Persist.Sql.Shim: Single :: a -> Single a
+ Database.Persist.Sql.Shim: SqlBlob :: SqlType
+ Database.Persist.Sql.Shim: SqlBool :: SqlType
+ Database.Persist.Sql.Shim: SqlDay :: SqlType
+ Database.Persist.Sql.Shim: SqlDayTime :: SqlType
+ Database.Persist.Sql.Shim: SqlInt32 :: SqlType
+ Database.Persist.Sql.Shim: SqlInt64 :: SqlType
+ Database.Persist.Sql.Shim: SqlNumeric :: Word32 -> Word32 -> SqlType
+ Database.Persist.Sql.Shim: SqlOther :: Text -> SqlType
+ Database.Persist.Sql.Shim: SqlReadBackend :: SqlBackend -> SqlReadBackend
+ Database.Persist.Sql.Shim: SqlReal :: SqlType
+ Database.Persist.Sql.Shim: SqlString :: SqlType
+ Database.Persist.Sql.Shim: SqlTime :: SqlType
+ Database.Persist.Sql.Shim: SqlWriteBackend :: SqlBackend -> SqlWriteBackend
+ Database.Persist.Sql.Shim: Statement :: IO () -> IO () -> ([PersistValue] -> IO Int64) -> (forall (m :: Type -> Type). MonadIO m => [PersistValue] -> Acquire (ConduitM () [PersistValue] m ())) -> Statement
+ Database.Persist.Sql.Shim: StatementAlreadyFinalized :: Text -> PersistentSqlException
+ Database.Persist.Sql.Shim: Subtract :: PersistUpdate
+ Database.Persist.Sql.Shim: Unescaped :: LiteralType
+ Database.Persist.Sql.Shim: UniqueDef :: !ConstraintNameHS -> !ConstraintNameDB -> !NonEmpty (FieldNameHS, FieldNameDB) -> ![Attr] -> UniqueDef
+ Database.Persist.Sql.Shim: Update :: EntityField record typ -> typ -> PersistUpdate -> Update record
+ Database.Persist.Sql.Shim: UpsertError :: String -> UpdateException
+ Database.Persist.Sql.Shim: [$sel:unSqlReadBackend:SqlReadBackend] :: SqlReadBackend -> SqlBackend
+ Database.Persist.Sql.Shim: [$sel:unSqlWriteBackend:SqlWriteBackend] :: SqlWriteBackend -> SqlBackend
+ Database.Persist.Sql.Shim: [FilterValue] :: forall typ. typ -> FilterValue typ
+ Database.Persist.Sql.Shim: [FilterValues] :: forall typ. [typ] -> FilterValue typ
+ Database.Persist.Sql.Shim: [UnsafeValue] :: forall a typ. PersistField a => a -> FilterValue typ
+ Database.Persist.Sql.Shim: [cDefaultConstraintName] :: Column -> !Maybe ConstraintNameDB
+ Database.Persist.Sql.Shim: [cDefault] :: Column -> !Maybe Text
+ Database.Persist.Sql.Shim: [cGenerated] :: Column -> !Maybe Text
+ Database.Persist.Sql.Shim: [cMaxLen] :: Column -> !Maybe Integer
+ Database.Persist.Sql.Shim: [cName] :: Column -> !FieldNameDB
+ Database.Persist.Sql.Shim: [cNull] :: Column -> !Bool
+ Database.Persist.Sql.Shim: [cReference] :: Column -> !Maybe ColumnReference
+ Database.Persist.Sql.Shim: [cSqlType] :: Column -> !SqlType
+ Database.Persist.Sql.Shim: [compositeAttrs] :: CompositeDef -> ![Attr]
+ Database.Persist.Sql.Shim: [compositeFields] :: CompositeDef -> !NonEmpty FieldDef
+ Database.Persist.Sql.Shim: [connectionPoolConfigIdleTimeout] :: ConnectionPoolConfig -> NominalDiffTime
+ Database.Persist.Sql.Shim: [connectionPoolConfigSize] :: ConnectionPoolConfig -> Int
+ Database.Persist.Sql.Shim: [connectionPoolConfigStripes] :: ConnectionPoolConfig -> Int
+ Database.Persist.Sql.Shim: [crConstraintName] :: ColumnReference -> !ConstraintNameDB
+ Database.Persist.Sql.Shim: [crFieldCascade] :: ColumnReference -> !FieldCascade
+ Database.Persist.Sql.Shim: [crTableName] :: ColumnReference -> !EntityNameDB
+ Database.Persist.Sql.Shim: [emFieldDB] :: EmbedFieldDef -> FieldNameDB
+ Database.Persist.Sql.Shim: [emFieldEmbed] :: EmbedFieldDef -> Maybe (Either SelfEmbed EntityNameHS)
+ Database.Persist.Sql.Shim: [embeddedFields] :: EmbedEntityDef -> [EmbedFieldDef]
+ Database.Persist.Sql.Shim: [embeddedHaskell] :: EmbedEntityDef -> EntityNameHS
+ Database.Persist.Sql.Shim: [entityKey] :: Entity record -> Key record
+ Database.Persist.Sql.Shim: [entityVal] :: Entity record -> record
+ Database.Persist.Sql.Shim: [fcOnDelete] :: FieldCascade -> !Maybe CascadeAction
+ Database.Persist.Sql.Shim: [fcOnUpdate] :: FieldCascade -> !Maybe CascadeAction
+ Database.Persist.Sql.Shim: [fieldAttrs] :: FieldDef -> ![FieldAttr]
+ Database.Persist.Sql.Shim: [fieldCascade] :: FieldDef -> !FieldCascade
+ Database.Persist.Sql.Shim: [fieldComments] :: FieldDef -> !Maybe Text
+ Database.Persist.Sql.Shim: [fieldDB] :: FieldDef -> !FieldNameDB
+ Database.Persist.Sql.Shim: [fieldGenerated] :: FieldDef -> !Maybe Text
+ Database.Persist.Sql.Shim: [fieldHaskell] :: FieldDef -> !FieldNameHS
+ Database.Persist.Sql.Shim: [fieldIsImplicitIdColumn] :: FieldDef -> !Bool
+ Database.Persist.Sql.Shim: [fieldReference] :: FieldDef -> !ReferenceDef
+ Database.Persist.Sql.Shim: [fieldSqlType] :: FieldDef -> !SqlType
+ Database.Persist.Sql.Shim: [fieldStrict] :: FieldDef -> !Bool
+ Database.Persist.Sql.Shim: [fieldType] :: FieldDef -> !FieldType
+ Database.Persist.Sql.Shim: [filterField] :: Filter record -> EntityField record typ
+ Database.Persist.Sql.Shim: [filterFilter] :: Filter record -> PersistFilter
+ Database.Persist.Sql.Shim: [filterValue] :: Filter record -> FilterValue typ
+ Database.Persist.Sql.Shim: [foreignAttrs] :: ForeignDef -> ![Attr]
+ Database.Persist.Sql.Shim: [foreignConstraintNameDBName] :: ForeignDef -> !ConstraintNameDB
+ Database.Persist.Sql.Shim: [foreignConstraintNameHaskell] :: ForeignDef -> !ConstraintNameHS
+ Database.Persist.Sql.Shim: [foreignFieldCascade] :: ForeignDef -> !FieldCascade
+ Database.Persist.Sql.Shim: [foreignFields] :: ForeignDef -> ![(ForeignFieldDef, ForeignFieldDef)]
+ Database.Persist.Sql.Shim: [foreignNullable] :: ForeignDef -> Bool
+ Database.Persist.Sql.Shim: [foreignRefTableDBName] :: ForeignDef -> !EntityNameDB
+ Database.Persist.Sql.Shim: [foreignRefTableHaskell] :: ForeignDef -> !EntityNameHS
+ Database.Persist.Sql.Shim: [foreignToPrimary] :: ForeignDef -> Bool
+ Database.Persist.Sql.Shim: [stmtExecute] :: Statement -> [PersistValue] -> IO Int64
+ Database.Persist.Sql.Shim: [stmtFinalize] :: Statement -> IO ()
+ Database.Persist.Sql.Shim: [stmtQuery] :: Statement -> forall (m :: Type -> Type). MonadIO m => [PersistValue] -> Acquire (ConduitM () [PersistValue] m ())
+ Database.Persist.Sql.Shim: [stmtReset] :: Statement -> IO ()
+ Database.Persist.Sql.Shim: [unConstraintNameDB] :: ConstraintNameDB -> Text
+ Database.Persist.Sql.Shim: [unConstraintNameHS] :: ConstraintNameHS -> Text
+ Database.Persist.Sql.Shim: [unEntityNameDB] :: EntityNameDB -> Text
+ Database.Persist.Sql.Shim: [unEntityNameHS] :: EntityNameHS -> Text
+ Database.Persist.Sql.Shim: [unEntityWithPrefix] :: EntityWithPrefix (prefix :: Symbol) record -> Entity record
+ Database.Persist.Sql.Shim: [unFieldNameDB] :: FieldNameDB -> Text
+ Database.Persist.Sql.Shim: [unFieldNameHS] :: FieldNameHS -> Text
+ Database.Persist.Sql.Shim: [unOverflowNatural] :: OverflowNatural -> Natural
+ Database.Persist.Sql.Shim: [unSingle] :: Single a -> a
+ Database.Persist.Sql.Shim: [uniqueAttrs] :: UniqueDef -> ![Attr]
+ Database.Persist.Sql.Shim: [uniqueDBName] :: UniqueDef -> !ConstraintNameDB
+ Database.Persist.Sql.Shim: [uniqueFields] :: UniqueDef -> !NonEmpty (FieldNameHS, FieldNameDB)
+ Database.Persist.Sql.Shim: [uniqueHaskell] :: UniqueDef -> !ConstraintNameHS
+ Database.Persist.Sql.Shim: [updateField] :: Update record -> EntityField record typ
+ Database.Persist.Sql.Shim: [updateUpdate] :: Update record -> PersistUpdate
+ Database.Persist.Sql.Shim: [updateValue] :: Update record -> typ
+ Database.Persist.Sql.Shim: acquireSqlConn :: (MonadReader backend m, BackendCompatible SqlBackend backend) => m (Acquire backend)
+ Database.Persist.Sql.Shim: acquireSqlConnWithIsolation :: (MonadReader backend m, BackendCompatible SqlBackend backend) => IsolationLevel -> m (Acquire backend)
+ Database.Persist.Sql.Shim: addFieldAttr :: FieldAttr -> FieldDef -> FieldDef
+ Database.Persist.Sql.Shim: addMigration :: Bool -> Sql -> Migration
+ Database.Persist.Sql.Shim: addMigrations :: CautiousMigration -> Migration
+ Database.Persist.Sql.Shim: applyEnv :: PersistConfig c => c -> IO c
+ Database.Persist.Sql.Shim: belongsTo :: (PersistEntity record1, PersistRecordBackend record2 SqlBackend, Typeable record1, Typeable record2, MonadSqlQuery m) => (record1 -> Maybe (Key record2)) -> record1 -> m (Maybe record2)
+ Database.Persist.Sql.Shim: belongsToJust :: (PersistEntity record1, PersistRecordBackend record2 SqlBackend, Typeable record1, Typeable record2, MonadSqlQuery m) => (record1 -> Key record2) -> record1 -> m record2
+ Database.Persist.Sql.Shim: checkUnique :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Unique record))
+ Database.Persist.Sql.Shim: checkUniqueUpdateable :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Entity record -> m (Maybe (Unique record))
+ Database.Persist.Sql.Shim: class PersistEntity record => AtLeastOneUniqueKey record
+ Database.Persist.Sql.Shim: class BackendCompatible sup sub
+ Database.Persist.Sql.Shim: class DatabaseName a
+ Database.Persist.Sql.Shim: class HasPersistBackend backend where {
+ Database.Persist.Sql.Shim: class HasPersistBackend backend => IsPersistBackend backend
+ Database.Persist.Sql.Shim: class PersistEntity record => OnlyOneUniqueKey record
+ Database.Persist.Sql.Shim: class PersistConfig c where {
+ Database.Persist.Sql.Shim: class PersistCore backend where {
+ Database.Persist.Sql.Shim: class (PersistField Key record, ToJSON Key record, FromJSON Key record, Show Key record, Read Key record, Eq Key record, Ord Key record) => PersistEntity record where {
+ Database.Persist.Sql.Shim: class PersistField a
+ Database.Persist.Sql.Shim: class PersistField a => PersistFieldSql a
+ Database.Persist.Sql.Shim: class (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend
+ Database.Persist.Sql.Shim: class (PersistQueryRead backend, PersistStoreWrite backend) => PersistQueryWrite backend
+ Database.Persist.Sql.Shim: class (Show BackendKey backend, Read BackendKey backend, Eq BackendKey backend, Ord BackendKey backend, PersistCore backend, PersistField BackendKey backend, ToJSON BackendKey backend, FromJSON BackendKey backend) => PersistStoreRead backend
+ Database.Persist.Sql.Shim: class (Show BackendKey backend, Read BackendKey backend, Eq BackendKey backend, Ord BackendKey backend, PersistStoreRead backend, PersistField BackendKey backend, ToJSON BackendKey backend, FromJSON BackendKey backend) => PersistStoreWrite backend
+ Database.Persist.Sql.Shim: class PersistStoreRead backend => PersistUniqueRead backend
+ Database.Persist.Sql.Shim: class (PersistUniqueRead backend, PersistStoreWrite backend) => PersistUniqueWrite backend
+ Database.Persist.Sql.Shim: class RawSql a
+ Database.Persist.Sql.Shim: class SafeToInsert a
+ Database.Persist.Sql.Shim: class SymbolToField (sym :: Symbol) rec typ | sym rec -> typ
+ Database.Persist.Sql.Shim: class (PersistEntity record, PersistEntityBackend record ~ backend, PersistCore backend) => ToBackendKey backend record
+ Database.Persist.Sql.Shim: close' :: BackendCompatible SqlBackend backend => backend -> IO ()
+ Database.Persist.Sql.Shim: count :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> m Int
+ Database.Persist.Sql.Shim: createPoolConfig :: PersistConfig c => c -> IO (PersistConfigPool c)
+ Database.Persist.Sql.Shim: createSqlPool :: forall backend m. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> Int -> m (Pool backend)
+ Database.Persist.Sql.Shim: createSqlPoolWithConfig :: (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> ConnectionPoolConfig -> m (Pool backend)
+ Database.Persist.Sql.Shim: data BackendSpecificOverrides
+ Database.Persist.Sql.Shim: data CascadeAction
+ Database.Persist.Sql.Shim: data Checkmark
+ Database.Persist.Sql.Shim: data Column
+ Database.Persist.Sql.Shim: data ColumnReference
+ Database.Persist.Sql.Shim: data CompositeDef
+ Database.Persist.Sql.Shim: data ConnectionPoolConfig
+ Database.Persist.Sql.Shim: data EmbedEntityDef
+ Database.Persist.Sql.Shim: data EmbedFieldDef
+ Database.Persist.Sql.Shim: data Entity record
+ Database.Persist.Sql.Shim: data EntityDef
+ Database.Persist.Sql.Shim: data EntityIdDef
+ Database.Persist.Sql.Shim: data FieldAttr
+ Database.Persist.Sql.Shim: data FieldCascade
+ Database.Persist.Sql.Shim: data FieldDef
+ Database.Persist.Sql.Shim: data FieldType
+ Database.Persist.Sql.Shim: data Filter record
+ Database.Persist.Sql.Shim: data FilterTablePrefix
+ Database.Persist.Sql.Shim: data FilterValue typ
+ Database.Persist.Sql.Shim: data ForeignDef
+ Database.Persist.Sql.Shim: data InsertSqlResult
+ Database.Persist.Sql.Shim: data IsNullable
+ Database.Persist.Sql.Shim: data IsolationLevel
+ Database.Persist.Sql.Shim: data LiteralType
+ Database.Persist.Sql.Shim: data PersistException
+ Database.Persist.Sql.Shim: data PersistFilter
+ Database.Persist.Sql.Shim: data PersistUpdate
+ Database.Persist.Sql.Shim: data PersistValue
+ Database.Persist.Sql.Shim: data PersistentSqlException
+ Database.Persist.Sql.Shim: data ReferenceDef
+ Database.Persist.Sql.Shim: data SelectOpt record
+ Database.Persist.Sql.Shim: data SqlBackend
+ Database.Persist.Sql.Shim: data SqlType
+ Database.Persist.Sql.Shim: data Statement
+ Database.Persist.Sql.Shim: data UniqueDef
+ Database.Persist.Sql.Shim: data Update record
+ Database.Persist.Sql.Shim: data UpdateException
+ Database.Persist.Sql.Shim: data WhyNullable
+ Database.Persist.Sql.Shim: data family Unique record;
+ Database.Persist.Sql.Shim: decorateSQLWithLimitOffset :: Text -> (Int, Int) -> Text -> Text
+ Database.Persist.Sql.Shim: defaultAttribute :: [FieldAttr] -> Maybe Text
+ Database.Persist.Sql.Shim: defaultConnectionPoolConfig :: ConnectionPoolConfig
+ Database.Persist.Sql.Shim: delete :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> m ()
+ Database.Persist.Sql.Shim: deleteBy :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Unique record -> m ()
+ Database.Persist.Sql.Shim: deleteWhere :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> m ()
+ Database.Persist.Sql.Shim: deleteWhereCount :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> m Int64
+ Database.Persist.Sql.Shim: emptyBackendSpecificOverrides :: BackendSpecificOverrides
+ Database.Persist.Sql.Shim: entitiesPrimary :: EntityDef -> NonEmpty FieldDef
+ Database.Persist.Sql.Shim: entityDef :: PersistEntity record => proxy record -> EntityDef
+ Database.Persist.Sql.Shim: entityIdFromJSON :: (PersistEntity record, FromJSON record) => Value -> Parser (Entity record)
+ Database.Persist.Sql.Shim: entityIdToJSON :: (PersistEntity record, ToJSON record) => Entity record -> Value
+ Database.Persist.Sql.Shim: entityPrimary :: EntityDef -> Maybe CompositeDef
+ Database.Persist.Sql.Shim: entityValues :: PersistEntity record => Entity record -> [PersistValue]
+ Database.Persist.Sql.Shim: escapeWith :: DatabaseName a => (Text -> str) -> a -> str
+ Database.Persist.Sql.Shim: exists :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> m Bool
+ Database.Persist.Sql.Shim: fieldAttrsContainsNullable :: [FieldAttr] -> IsNullable
+ Database.Persist.Sql.Shim: fieldDBName :: PersistEntity record => EntityField record typ -> FieldNameDB
+ Database.Persist.Sql.Shim: fieldLens :: PersistEntity record => EntityField record field -> forall (f :: Type -> Type). Functor f => (field -> f field) -> Entity record -> f (Entity record)
+ Database.Persist.Sql.Shim: filterClause :: PersistEntity val => Maybe FilterTablePrefix -> SqlBackend -> [Filter val] -> Text
+ Database.Persist.Sql.Shim: filterClauseWithVals :: PersistEntity val => Maybe FilterTablePrefix -> SqlBackend -> [Filter val] -> (Text, [PersistValue])
+ Database.Persist.Sql.Shim: fromBackendKey :: ToBackendKey backend record => BackendKey backend -> Key record
+ Database.Persist.Sql.Shim: fromPersistValue :: PersistField a => PersistValue -> Either Text a
+ Database.Persist.Sql.Shim: fromPersistValueJSON :: FromJSON a => PersistValue -> Either Text a
+ Database.Persist.Sql.Shim: fromPersistValueText :: PersistValue -> Either Text Text
+ Database.Persist.Sql.Shim: fromPersistValues :: PersistEntity record => [PersistValue] -> Either Text record
+ Database.Persist.Sql.Shim: fromSqlKey :: ToBackendKey SqlBackend record => Key record -> Int64
+ Database.Persist.Sql.Shim: get :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> m (Maybe record)
+ Database.Persist.Sql.Shim: getBackendSpecificForeignKeyName :: BackendSpecificOverrides -> Maybe (EntityNameDB -> FieldNameDB -> ConstraintNameDB)
+ Database.Persist.Sql.Shim: getBy :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Unique record -> m (Maybe (Entity record))
+ Database.Persist.Sql.Shim: getByValue :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Entity record))
+ Database.Persist.Sql.Shim: getEntity :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> m (Maybe (Entity record))
+ Database.Persist.Sql.Shim: getEntityComments :: EntityDef -> Maybe Text
+ Database.Persist.Sql.Shim: getEntityDBName :: EntityDef -> EntityNameDB
+ Database.Persist.Sql.Shim: getEntityExtra :: EntityDef -> Map Text [[Text]]
+ Database.Persist.Sql.Shim: getEntityFields :: EntityDef -> [FieldDef]
+ Database.Persist.Sql.Shim: getEntityFieldsDatabase :: EntityDef -> [FieldDef]
+ Database.Persist.Sql.Shim: getEntityForeignDefs :: EntityDef -> [ForeignDef]
+ Database.Persist.Sql.Shim: getEntityHaskellName :: EntityDef -> EntityNameHS
+ Database.Persist.Sql.Shim: getEntityId :: EntityDef -> EntityIdDef
+ Database.Persist.Sql.Shim: getEntityIdField :: EntityDef -> Maybe FieldDef
+ Database.Persist.Sql.Shim: getEntityKeyFields :: EntityDef -> NonEmpty FieldDef
+ Database.Persist.Sql.Shim: getEntityUniques :: EntityDef -> [UniqueDef]
+ Database.Persist.Sql.Shim: getEntityUniquesNoPrimaryKey :: EntityDef -> [UniqueDef]
+ Database.Persist.Sql.Shim: getFieldName :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => EntityField record typ -> m Text
+ Database.Persist.Sql.Shim: getJust :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> m record
+ Database.Persist.Sql.Shim: getJustEntity :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> m (Entity record)
+ Database.Persist.Sql.Shim: getMany :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Key record] -> m (Map (Key record) record)
+ Database.Persist.Sql.Shim: getMigration :: (HasCallStack, MonadSqlQuery m) => Migration -> m [Sql]
+ Database.Persist.Sql.Shim: getPersistMap :: PersistValue -> Either Text [(Text, PersistValue)]
+ Database.Persist.Sql.Shim: getStmtConn :: SqlBackend -> Text -> IO Statement
+ Database.Persist.Sql.Shim: getTableName :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m Text
+ Database.Persist.Sql.Shim: infix 4 ==.
+ Database.Persist.Sql.Shim: infixl 3 ||.
+ Database.Persist.Sql.Shim: infixr 3 =.
+ Database.Persist.Sql.Shim: insert :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Key record)
+ Database.Persist.Sql.Shim: insertBy :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Either (Entity record) (Key record))
+ Database.Persist.Sql.Shim: insertEntity :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Entity record)
+ Database.Persist.Sql.Shim: insertEntityMany :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Entity record] -> m ()
+ Database.Persist.Sql.Shim: insertKey :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> record -> m ()
+ Database.Persist.Sql.Shim: insertMany :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => [record] -> m [Key record]
+ Database.Persist.Sql.Shim: insertMany_ :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => [record] -> m ()
+ Database.Persist.Sql.Shim: insertRecord :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m record
+ Database.Persist.Sql.Shim: insertUnique :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Key record))
+ Database.Persist.Sql.Shim: insertUniqueEntity :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Entity record))
+ Database.Persist.Sql.Shim: insert_ :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m ()
+ Database.Persist.Sql.Shim: isEntitySum :: EntityDef -> Bool
+ Database.Persist.Sql.Shim: isFieldMaybe :: FieldDef -> Bool
+ Database.Persist.Sql.Shim: isFieldNotGenerated :: FieldDef -> Bool
+ Database.Persist.Sql.Shim: isFieldNullable :: FieldDef -> IsNullable
+ Database.Persist.Sql.Shim: isHaskellField :: FieldDef -> Bool
+ Database.Persist.Sql.Shim: keyAndEntityFields :: EntityDef -> NonEmpty FieldDef
+ Database.Persist.Sql.Shim: keyFromRecordM :: PersistEntity record => Maybe (record -> Key record)
+ Database.Persist.Sql.Shim: keyFromValues :: PersistEntity record => [PersistValue] -> Either Text (Key record)
+ Database.Persist.Sql.Shim: keyToValues :: PersistEntity record => Key record -> [PersistValue]
+ Database.Persist.Sql.Shim: keyValueEntityFromJSON :: (PersistEntity record, FromJSON record) => Value -> Parser (Entity record)
+ Database.Persist.Sql.Shim: keyValueEntityToJSON :: (PersistEntity record, ToJSON record) => Entity record -> Value
+ Database.Persist.Sql.Shim: liftPersist :: (MonadIO m, MonadReader backend m) => ReaderT backend IO b -> m b
+ Database.Persist.Sql.Shim: liftSqlPersistMPool :: forall backend m a. (MonadIO m, BackendCompatible SqlBackend backend) => ReaderT backend (NoLoggingT (ResourceT IO)) a -> Pool backend -> m a
+ Database.Persist.Sql.Shim: limitOffsetOrder :: PersistEntity val => [SelectOpt val] -> (Int, Int, [SelectOpt val])
+ Database.Persist.Sql.Shim: listToJSON :: [PersistValue] -> Text
+ Database.Persist.Sql.Shim: loadConfig :: PersistConfig c => Value -> Parser c
+ Database.Persist.Sql.Shim: mapToJSON :: [(Text, PersistValue)] -> Text
+ Database.Persist.Sql.Shim: migrate :: [EntityDef] -> EntityDef -> Migration
+ Database.Persist.Sql.Shim: mkColumns :: [EntityDef] -> EntityDef -> BackendSpecificOverrides -> ([Column], [UniqueDef], [ForeignDef])
+ Database.Persist.Sql.Shim: newtype ConstraintNameDB
+ Database.Persist.Sql.Shim: newtype ConstraintNameHS
+ Database.Persist.Sql.Shim: newtype EntityNameDB
+ Database.Persist.Sql.Shim: newtype EntityNameHS
+ Database.Persist.Sql.Shim: newtype EntityWithPrefix (prefix :: Symbol) record
+ Database.Persist.Sql.Shim: newtype FieldNameDB
+ Database.Persist.Sql.Shim: newtype FieldNameHS
+ Database.Persist.Sql.Shim: newtype OverflowNatural
+ Database.Persist.Sql.Shim: newtype PersistUnsafeMigrationException
+ Database.Persist.Sql.Shim: newtype Single a
+ Database.Persist.Sql.Shim: newtype SqlReadBackend
+ Database.Persist.Sql.Shim: newtype SqlWriteBackend
+ Database.Persist.Sql.Shim: noCascade :: FieldCascade
+ Database.Persist.Sql.Shim: onlyOneUniqueDef :: (OnlyOneUniqueKey record, Monad proxy) => proxy record -> UniqueDef
+ Database.Persist.Sql.Shim: onlyUnique :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, Typeable record, MonadSqlQuery m) => record -> m (Unique record)
+ Database.Persist.Sql.Shim: onlyUniqueP :: OnlyOneUniqueKey record => record -> Unique record
+ Database.Persist.Sql.Shim: orderClause :: PersistEntity val => Maybe FilterTablePrefix -> SqlBackend -> [SelectOpt val] -> Text
+ Database.Persist.Sql.Shim: overEntityFields :: ([FieldDef] -> [FieldDef]) -> EntityDef -> EntityDef
+ Database.Persist.Sql.Shim: overFieldAttrs :: ([FieldAttr] -> [FieldAttr]) -> FieldDef -> FieldDef
+ Database.Persist.Sql.Shim: parseFieldAttrs :: [Text] -> [FieldAttr]
+ Database.Persist.Sql.Shim: parseMigration :: (HasCallStack, MonadSqlQuery m) => Migration -> m (Either [Text] CautiousMigration)
+ Database.Persist.Sql.Shim: parseMigration' :: (HasCallStack, MonadSqlQuery m) => Migration -> m CautiousMigration
+ Database.Persist.Sql.Shim: pattern PersistDbSpecific :: ByteString -> PersistValue
+ Database.Persist.Sql.Shim: pattern PersistLiteral :: ByteString -> PersistValue
+ Database.Persist.Sql.Shim: pattern PersistLiteralEscaped :: ByteString -> PersistValue
+ Database.Persist.Sql.Shim: persistBackend :: HasPersistBackend backend => backend -> BaseBackend backend
+ Database.Persist.Sql.Shim: persistFieldDef :: PersistEntity record => EntityField record typ -> FieldDef
+ Database.Persist.Sql.Shim: persistIdField :: PersistEntity record => EntityField record (Key record)
+ Database.Persist.Sql.Shim: persistUniqueKeys :: PersistEntity record => record -> [Unique record]
+ Database.Persist.Sql.Shim: persistUniqueToFieldNames :: PersistEntity record => Unique record -> NonEmpty (FieldNameHS, FieldNameDB)
+ Database.Persist.Sql.Shim: persistUniqueToValues :: PersistEntity record => Unique record -> [PersistValue]
+ Database.Persist.Sql.Shim: printMigration :: (HasCallStack, MonadSqlQuery m) => Migration -> m ()
+ Database.Persist.Sql.Shim: projectBackend :: BackendCompatible sup sub => sub -> sup
+ Database.Persist.Sql.Shim: putMany :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => [record] -> m ()
+ Database.Persist.Sql.Shim: rawExecute :: MonadSqlQuery m => Text -> [PersistValue] -> m ()
+ Database.Persist.Sql.Shim: rawExecuteCount :: MonadSqlQuery m => Text -> [PersistValue] -> m Int64
+ Database.Persist.Sql.Shim: rawQuery :: (MonadResource m, MonadSqlQuery m) => Text -> [PersistValue] -> ConduitM () [PersistValue] m ()
+ Database.Persist.Sql.Shim: rawQueryRes :: (MonadIO m2, MonadSqlQuery m) => Text -> [PersistValue] -> m (Acquire (ConduitM () [PersistValue] m2 ()))
+ Database.Persist.Sql.Shim: rawSql :: (RawSql a, MonadSqlQuery m) => Text -> [PersistValue] -> m [a]
+ Database.Persist.Sql.Shim: rawSqlColCountReason :: RawSql a => a -> String
+ Database.Persist.Sql.Shim: rawSqlCols :: RawSql a => (Text -> Text) -> a -> (Int, [Text])
+ Database.Persist.Sql.Shim: rawSqlProcessRow :: RawSql a => [PersistValue] -> Either Text a
+ Database.Persist.Sql.Shim: readToUnknown :: forall (m :: Type -> Type) a. Monad m => ReaderT SqlReadBackend m a -> ReaderT SqlBackend m a
+ Database.Persist.Sql.Shim: readToWrite :: forall (m :: Type -> Type) a. Monad m => ReaderT SqlReadBackend m a -> ReaderT SqlWriteBackend m a
+ Database.Persist.Sql.Shim: renderCascadeAction :: CascadeAction -> Text
+ Database.Persist.Sql.Shim: renderFieldCascade :: FieldCascade -> Text
+ Database.Persist.Sql.Shim: replace :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> record -> m ()
+ Database.Persist.Sql.Shim: replaceUnique :: (PersistRecordBackend record SqlBackend, Eq (Unique record), Eq record, Typeable record, MonadSqlQuery m) => Key record -> record -> m (Maybe (Unique record))
+ Database.Persist.Sql.Shim: reportError :: Text -> Migration
+ Database.Persist.Sql.Shim: reportErrors :: [Text] -> Migration
+ Database.Persist.Sql.Shim: repsert :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> record -> m ()
+ Database.Persist.Sql.Shim: repsertMany :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [(Key record, record)] -> m ()
+ Database.Persist.Sql.Shim: requireUniquesP :: AtLeastOneUniqueKey record => record -> NonEmpty (Unique record)
+ Database.Persist.Sql.Shim: runMigration :: MonadSqlQuery m => Migration -> m ()
+ Database.Persist.Sql.Shim: runMigrationQuiet :: MonadSqlQuery m => Migration -> m [Text]
+ Database.Persist.Sql.Shim: runMigrationSilent :: MonadSqlQuery m => Migration -> m [Text]
+ Database.Persist.Sql.Shim: runMigrationUnsafe :: MonadSqlQuery m => Migration -> m ()
+ Database.Persist.Sql.Shim: runMigrationUnsafeQuiet :: (HasCallStack, MonadSqlQuery m) => Migration -> m [Text]
+ Database.Persist.Sql.Shim: runPool :: (PersistConfig c, MonadUnliftIO m) => c -> PersistConfigBackend c m a -> PersistConfigPool c -> m a
+ Database.Persist.Sql.Shim: runSqlCommand :: SqlPersistT IO () -> Migration
+ Database.Persist.Sql.Shim: runSqlConn :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> backend -> m a
+ Database.Persist.Sql.Shim: runSqlConnWithIsolation :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> backend -> IsolationLevel -> m a
+ Database.Persist.Sql.Shim: runSqlPersistM :: BackendCompatible SqlBackend backend => ReaderT backend (NoLoggingT (ResourceT IO)) a -> backend -> IO a
+ Database.Persist.Sql.Shim: runSqlPersistMPool :: BackendCompatible SqlBackend backend => ReaderT backend (NoLoggingT (ResourceT IO)) a -> Pool backend -> IO a
+ Database.Persist.Sql.Shim: runSqlPool :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> m a
+ Database.Persist.Sql.Shim: runSqlPoolNoTransaction :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> m a
+ Database.Persist.Sql.Shim: runSqlPoolWithExtensibleHooks :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> SqlPoolHooks m backend -> m a
+ Database.Persist.Sql.Shim: runSqlPoolWithHooks :: forall backend m a before after onException. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> (backend -> m before) -> (backend -> m after) -> (backend -> SomeException -> m onException) -> m a
+ Database.Persist.Sql.Shim: runSqlPoolWithIsolation :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> Pool backend -> IsolationLevel -> m a
+ Database.Persist.Sql.Shim: selectFirst :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> m (Maybe (Entity record))
+ Database.Persist.Sql.Shim: selectKeys :: (PersistRecordBackend record SqlBackend, MonadResource m, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> ConduitM () (Key record) m ()
+ Database.Persist.Sql.Shim: selectKeysList :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> m [Key record]
+ Database.Persist.Sql.Shim: selectKeysRes :: (MonadIO m2, PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> m (Acquire (ConduitM () (Key record) m2 ()))
+ Database.Persist.Sql.Shim: selectList :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> m [Entity record]
+ Database.Persist.Sql.Shim: selectSource :: (PersistRecordBackend record SqlBackend, MonadResource m, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> ConduitM () (Entity record) m ()
+ Database.Persist.Sql.Shim: selectSourceRes :: (MonadIO m2, PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [SelectOpt record] -> m (Acquire (ConduitM () (Entity record) m2 ()))
+ Database.Persist.Sql.Shim: setBackendSpecificForeignKeyName :: (EntityNameDB -> FieldNameDB -> ConstraintNameDB) -> BackendSpecificOverrides -> BackendSpecificOverrides
+ Database.Persist.Sql.Shim: setEntityDBName :: EntityNameDB -> EntityDef -> EntityDef
+ Database.Persist.Sql.Shim: setEntityId :: FieldDef -> EntityDef -> EntityDef
+ Database.Persist.Sql.Shim: setEntityIdDef :: EntityIdDef -> EntityDef -> EntityDef
+ Database.Persist.Sql.Shim: setFieldAttrs :: [FieldAttr] -> FieldDef -> FieldDef
+ Database.Persist.Sql.Shim: showMigration :: (HasCallStack, MonadSqlQuery m) => Migration -> m [Text]
+ Database.Persist.Sql.Shim: sqlType :: PersistFieldSql a => Proxy a -> SqlType
+ Database.Persist.Sql.Shim: symbolToField :: SymbolToField sym rec typ => EntityField rec typ
+ Database.Persist.Sql.Shim: tableDBName :: PersistEntity record => record -> EntityNameDB
+ Database.Persist.Sql.Shim: tabulateEntity :: PersistEntity record => (forall a. () => EntityField record a -> a) -> Entity record
+ Database.Persist.Sql.Shim: tabulateEntityA :: (PersistEntity record, Applicative f) => (forall a. () => EntityField record a -> f a) -> f (Entity record)
+ Database.Persist.Sql.Shim: toBackendKey :: ToBackendKey backend record => Key record -> BackendKey backend
+ Database.Persist.Sql.Shim: toJsonText :: ToJSON j => j -> Text
+ Database.Persist.Sql.Shim: toPersistFields :: PersistEntity record => record -> [PersistValue]
+ Database.Persist.Sql.Shim: toPersistValue :: PersistField a => a -> PersistValue
+ Database.Persist.Sql.Shim: toPersistValueJSON :: ToJSON a => a -> PersistValue
+ Database.Persist.Sql.Shim: toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record
+ Database.Persist.Sql.Shim: transactionSave :: MonadSqlQuery m => m ()
+ Database.Persist.Sql.Shim: transactionSaveWithIsolation :: MonadSqlQuery m => IsolationLevel -> m ()
+ Database.Persist.Sql.Shim: transactionUndo :: MonadSqlQuery m => m ()
+ Database.Persist.Sql.Shim: transactionUndoWithIsolation :: MonadSqlQuery m => IsolationLevel -> m ()
+ Database.Persist.Sql.Shim: type Attr = Text
+ Database.Persist.Sql.Shim: type CautiousMigration = [(Bool, Sql)]
+ Database.Persist.Sql.Shim: type ConnectionPool = Pool SqlBackend
+ Database.Persist.Sql.Shim: type ExtraLine = [Text]
+ Database.Persist.Sql.Shim: type ForeignFieldDef = (FieldNameHS, FieldNameDB)
+ Database.Persist.Sql.Shim: type IsSqlBackend backend = (IsPersistBackend backend, BaseBackend backend ~ SqlBackend)
+ Database.Persist.Sql.Shim: type LogFunc = Loc -> LogSource -> LogLevel -> LogStr -> IO ()
+ Database.Persist.Sql.Shim: type Migration = WriterT [Text] WriterT CautiousMigration ReaderT SqlBackend IO ()
+ Database.Persist.Sql.Shim: type MultipleUniqueKeysError ty = 'Text "The entity " :<>: 'ShowType ty :<>: 'Text " has multiple unique keys." :$$: 'Text "The function you are trying to call requires only a single " :<>: 'Text "unique key." :$$: 'Text "There is probably a variant of the function with 'By' " :<>: 'Text "appended that will allow you to select a unique key " :<>: 'Text "for the operation."
+ Database.Persist.Sql.Shim: type NoUniqueKeysError ty = 'Text "The entity " :<>: 'ShowType ty :<>: 'Text " does not have any unique keys." :$$: 'Text "The function you are trying to call requires a unique key " :<>: 'Text "to be defined on the entity."
+ Database.Persist.Sql.Shim: type PersistQuery a = PersistQueryWrite a
+ Database.Persist.Sql.Shim: type PersistRecordBackend record backend = (PersistEntity record, PersistEntityBackend record ~ BaseBackend backend)
+ Database.Persist.Sql.Shim: type PersistStore a = PersistStoreWrite a
+ Database.Persist.Sql.Shim: type PersistUnique a = PersistUniqueWrite a
+ Database.Persist.Sql.Shim: type SqlWriteT (m :: Type -> Type) a = forall backend. SqlBackendCanWrite backend => ReaderT backend m a
+ Database.Persist.Sql.Shim: type Sql = Text
+ Database.Persist.Sql.Shim: type SqlBackendCanRead backend = (BackendCompatible SqlBackend backend, PersistQueryRead backend, PersistStoreRead backend, PersistUniqueRead backend)
+ Database.Persist.Sql.Shim: type SqlBackendCanWrite backend = (SqlBackendCanRead backend, PersistQueryWrite backend, PersistStoreWrite backend, PersistUniqueWrite backend)
+ Database.Persist.Sql.Shim: type SqlPersistM = SqlPersistT NoLoggingT ResourceT IO
+ Database.Persist.Sql.Shim: type SqlPersistT = ReaderT SqlBackend
+ Database.Persist.Sql.Shim: type family PersistConfigPool c;
+ Database.Persist.Sql.Shim: unPrefix :: forall (prefix :: Symbol) record. EntityWithPrefix prefix record -> Entity record
+ Database.Persist.Sql.Shim: unsafeLiftSql :: MonadSqlQuery m => Text -> (forall m2. MonadIO m2 => SqlPersistT m2 a) -> m a
+ Database.Persist.Sql.Shim: update :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> [Update record] -> m ()
+ Database.Persist.Sql.Shim: updateGet :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Key record -> [Update record] -> m record
+ Database.Persist.Sql.Shim: updateWhere :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [Update record] -> m ()
+ Database.Persist.Sql.Shim: updateWhereCount :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [Filter record] -> [Update record] -> m Int64
+ Database.Persist.Sql.Shim: upsert :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> [Update record] -> m (Entity record)
+ Database.Persist.Sql.Shim: upsertBy :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => Unique record -> record -> [Update record] -> m (Entity record)
+ Database.Persist.Sql.Shim: withBaseBackend :: forall backend (m :: Type -> Type) a. HasPersistBackend backend => ReaderT (BaseBackend backend) m a -> ReaderT backend m a
+ Database.Persist.Sql.Shim: withCompatibleBackend :: forall sup sub (m :: Type -> Type) a. BackendCompatible sup sub => ReaderT sup m a -> ReaderT sub m a
+ Database.Persist.Sql.Shim: withRawQuery :: MonadSqlQuery m => Text -> [PersistValue] -> ConduitM [PersistValue] Void IO a -> m a
+ Database.Persist.Sql.Shim: withSqlConn :: forall backend m a. (MonadUnliftIO m, MonadLoggerIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> (backend -> m a) -> m a
+ Database.Persist.Sql.Shim: withSqlPool :: forall backend m a. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> Int -> (Pool backend -> m a) -> m a
+ Database.Persist.Sql.Shim: withSqlPoolWithConfig :: forall backend m a. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend) => (LogFunc -> IO backend) -> ConnectionPoolConfig -> (Pool backend -> m a) -> m a
+ Database.Persist.Sql.Shim: writeToUnknown :: forall (m :: Type -> Type) a. Monad m => ReaderT SqlWriteBackend m a -> ReaderT SqlBackend m a
+ Database.Persist.Sql.Shim: }
- Database.Persist.Monad: SqlQueryEnv :: Pool SqlBackend -> (SomeException -> Bool) -> Int -> SqlQueryEnv
+ Database.Persist.Monad: SqlQueryEnv :: Pool SqlBackend -> (SomeException -> Bool) -> Int -> (SomeException -> IO ()) -> SqlQueryEnv
- Database.Persist.Monad.Shim: insert :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m (Key record)
+ Database.Persist.Monad.Shim: insert :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Key record)
- Database.Persist.Monad.Shim: insertBy :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, Typeable record, MonadSqlQuery m) => record -> m (Either (Entity record) (Key record))
+ Database.Persist.Monad.Shim: insertBy :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Either (Entity record) (Key record))
- Database.Persist.Monad.Shim: insertEntity :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m (Entity record)
+ Database.Persist.Monad.Shim: insertEntity :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Entity record)
- Database.Persist.Monad.Shim: insertMany :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [record] -> m [Key record]
+ Database.Persist.Monad.Shim: insertMany :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => [record] -> m [Key record]
- Database.Persist.Monad.Shim: insertMany_ :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [record] -> m ()
+ Database.Persist.Monad.Shim: insertMany_ :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => [record] -> m ()
- Database.Persist.Monad.Shim: insertRecord :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m record
+ Database.Persist.Monad.Shim: insertRecord :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m record
- Database.Persist.Monad.Shim: insertUnique :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Key record))
+ Database.Persist.Monad.Shim: insertUnique :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Key record))
- Database.Persist.Monad.Shim: insertUniqueEntity :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Entity record))
+ Database.Persist.Monad.Shim: insertUniqueEntity :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m (Maybe (Entity record))
- Database.Persist.Monad.Shim: insert_ :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => record -> m ()
+ Database.Persist.Monad.Shim: insert_ :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> m ()
- Database.Persist.Monad.Shim: putMany :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => [record] -> m ()
+ Database.Persist.Monad.Shim: putMany :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => [record] -> m ()
- Database.Persist.Monad.Shim: upsert :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, Typeable record, MonadSqlQuery m) => record -> [Update record] -> m (Entity record)
+ Database.Persist.Monad.Shim: upsert :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, SafeToInsert record, Typeable record, MonadSqlQuery m) => record -> [Update record] -> m (Entity record)
- Database.Persist.Monad.Shim: upsertBy :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m) => Unique record -> record -> [Update record] -> m (Entity record)
+ Database.Persist.Monad.Shim: upsertBy :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m) => Unique record -> record -> [Update record] -> m (Entity record)
- Database.Persist.Monad.SqlQueryRep: [InsertBy] :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record) => record -> SqlQueryRep record (Either (Entity record) (Key record))
+ Database.Persist.Monad.SqlQueryRep: [InsertBy] :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, SafeToInsert record) => record -> SqlQueryRep record (Either (Entity record) (Key record))
- Database.Persist.Monad.SqlQueryRep: [InsertEntity] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Entity record)
+ Database.Persist.Monad.SqlQueryRep: [InsertEntity] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Entity record)
- Database.Persist.Monad.SqlQueryRep: [InsertMany] :: PersistRecordBackend record SqlBackend => [record] -> SqlQueryRep record [Key record]
+ Database.Persist.Monad.SqlQueryRep: [InsertMany] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => [record] -> SqlQueryRep record [Key record]
- Database.Persist.Monad.SqlQueryRep: [InsertMany_] :: PersistRecordBackend record SqlBackend => [record] -> SqlQueryRep record ()
+ Database.Persist.Monad.SqlQueryRep: [InsertMany_] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => [record] -> SqlQueryRep record ()
- Database.Persist.Monad.SqlQueryRep: [InsertRecord] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record record
+ Database.Persist.Monad.SqlQueryRep: [InsertRecord] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record record
- Database.Persist.Monad.SqlQueryRep: [InsertUniqueEntity] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Maybe (Entity record))
+ Database.Persist.Monad.SqlQueryRep: [InsertUniqueEntity] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Maybe (Entity record))
- Database.Persist.Monad.SqlQueryRep: [InsertUnique] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Maybe (Key record))
+ Database.Persist.Monad.SqlQueryRep: [InsertUnique] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Maybe (Key record))
- Database.Persist.Monad.SqlQueryRep: [Insert] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Key record)
+ Database.Persist.Monad.SqlQueryRep: [Insert] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Key record)
- Database.Persist.Monad.SqlQueryRep: [Insert_] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record ()
+ Database.Persist.Monad.SqlQueryRep: [Insert_] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record ()
- Database.Persist.Monad.SqlQueryRep: [PutMany] :: PersistRecordBackend record SqlBackend => [record] -> SqlQueryRep record ()
+ Database.Persist.Monad.SqlQueryRep: [PutMany] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => [record] -> SqlQueryRep record ()
- Database.Persist.Monad.SqlQueryRep: [UpsertBy] :: PersistRecordBackend record SqlBackend => Unique record -> record -> [Update record] -> SqlQueryRep record (Entity record)
+ Database.Persist.Monad.SqlQueryRep: [UpsertBy] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => Unique record -> record -> [Update record] -> SqlQueryRep record (Entity record)
- Database.Persist.Monad.SqlQueryRep: [Upsert] :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record) => record -> [Update record] -> SqlQueryRep record (Entity record)
+ Database.Persist.Monad.SqlQueryRep: [Upsert] :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, SafeToInsert record) => record -> [Update record] -> SqlQueryRep record (Entity record)
- Database.Persist.Monad.TestUtils: [InsertBy] :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record) => record -> SqlQueryRep record (Either (Entity record) (Key record))
+ Database.Persist.Monad.TestUtils: [InsertBy] :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, SafeToInsert record) => record -> SqlQueryRep record (Either (Entity record) (Key record))
- Database.Persist.Monad.TestUtils: [InsertEntity] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Entity record)
+ Database.Persist.Monad.TestUtils: [InsertEntity] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Entity record)
- Database.Persist.Monad.TestUtils: [InsertMany] :: PersistRecordBackend record SqlBackend => [record] -> SqlQueryRep record [Key record]
+ Database.Persist.Monad.TestUtils: [InsertMany] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => [record] -> SqlQueryRep record [Key record]
- Database.Persist.Monad.TestUtils: [InsertMany_] :: PersistRecordBackend record SqlBackend => [record] -> SqlQueryRep record ()
+ Database.Persist.Monad.TestUtils: [InsertMany_] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => [record] -> SqlQueryRep record ()
- Database.Persist.Monad.TestUtils: [InsertRecord] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record record
+ Database.Persist.Monad.TestUtils: [InsertRecord] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record record
- Database.Persist.Monad.TestUtils: [InsertUniqueEntity] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Maybe (Entity record))
+ Database.Persist.Monad.TestUtils: [InsertUniqueEntity] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Maybe (Entity record))
- Database.Persist.Monad.TestUtils: [InsertUnique] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Maybe (Key record))
+ Database.Persist.Monad.TestUtils: [InsertUnique] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Maybe (Key record))
- Database.Persist.Monad.TestUtils: [Insert] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record (Key record)
+ Database.Persist.Monad.TestUtils: [Insert] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record (Key record)
- Database.Persist.Monad.TestUtils: [Insert_] :: PersistRecordBackend record SqlBackend => record -> SqlQueryRep record ()
+ Database.Persist.Monad.TestUtils: [Insert_] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => record -> SqlQueryRep record ()
- Database.Persist.Monad.TestUtils: [PutMany] :: PersistRecordBackend record SqlBackend => [record] -> SqlQueryRep record ()
+ Database.Persist.Monad.TestUtils: [PutMany] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => [record] -> SqlQueryRep record ()
- Database.Persist.Monad.TestUtils: [UpsertBy] :: PersistRecordBackend record SqlBackend => Unique record -> record -> [Update record] -> SqlQueryRep record (Entity record)
+ Database.Persist.Monad.TestUtils: [UpsertBy] :: (PersistRecordBackend record SqlBackend, SafeToInsert record) => Unique record -> record -> [Update record] -> SqlQueryRep record (Entity record)
- Database.Persist.Monad.TestUtils: [Upsert] :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record) => record -> [Update record] -> SqlQueryRep record (Entity record)
+ Database.Persist.Monad.TestUtils: [Upsert] :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, SafeToInsert record) => record -> [Update record] -> SqlQueryRep record (Entity record)

Files

CHANGELOG.md view
@@ -1,36 +1,49 @@ # Unreleased -# 0.4.0.0+# v0.5.0.0 +* Export `SqlQueryT` constructor ([#46](https://github.com/brandonchinn178/persistent-mtl/pull/46))+* Drop support for GHC < 8.10+* Drop support for `persistent` < 2.13+* Add support for `persistent-2.14`+* Add `Database.Persist.Sql.Shim` module that re-exports `Database.Persist.Sql` and `Database.Persist.Monad.Shim`+* Add `MonadFix` instance to `SqlQueryT` and `SqlTransaction`+* Add `getSqlBackendPool`+* Move `rerunnableLift` into `MonadRerunnableTrans` typeclass in `Control.Monad.Trans.Rerunnable`+* Add `catchSqlTransaction`+* Add `retryCallback` to `SqlQueryEnv`++# v0.4.0.0+ * Add some mtl instances: `MonadThrow`, `MonadCatch`, `MonadMask`, `MonadLogger`, `MonadReader` * Removed support for GHC 8.2, 8.4 * Add `MonadSqlQuery (TransactionM m)` superclass constraint to allow writing functions generic on some `MonadSqlQuery m` using `withTransaction`, as shown in examples in README -# 0.3.0.0+# v0.3.0.0  * Add `unsafeLiftSql` ([#38](https://github.com/brandonchinn178/persistent-mtl/pull/38)) -# 0.2.2.0+# v0.2.2.0  * Fix for persistent 2.13 -# 0.2.1.0+# v0.2.1.0  * Add `rerunnableLift` for `SqlTransaction` * Use `unliftio-pool` instead of `resourcet-pool`, which has better async exeception safety -# 0.2.0.0+# v0.2.0.0  * Use a separate monad within `withTransaction` to prevent unsafe/arbitrary IO actions ([#7](https://github.com/brandonchinn178/persistent-mtl/issues/7), [#28](https://github.com/brandonchinn178/persistent-mtl/issues/28)) * Add `MonadRerunnableIO` to support IO actions within `withTransaction` only if the IO action is determined to be rerunnable * Add built-in support for retrying transactions if a serialization error occurs * Remove `SqlQueryRep` as an export from `Database.Persist.Monad`. You shouldn't ever need it for normal usage. It is now re-exported by `Database.Persist.Monad.TestUtils`, since most of the usage of `SqlQueryRep` is in mocking queries. If you need it otherwise, you can import it directly from `Database.Persist.Monad.SqlQueryRep`. -# 0.1.0.1+# v0.1.0.1  Fix quickstart -# 0.1.0.0+# v0.1.0.0  Initial release * `SqlQueryT` + `MonadSqlQuery`
README.md view
@@ -1,8 +1,8 @@ # `persistent-mtl` -[![CircleCI](https://img.shields.io/circleci/build/github/brandonchinn178/persistent-mtl)](https://app.circleci.com/pipelines/github/brandonchinn178/persistent-mtl)+[![GitHub Actions](https://img.shields.io/github/workflow/status/brandonchinn178/persistent-mtl/CI/main)](https://github.com/brandonchinn178/persistent-mtl/actions?query=branch%3Amain) [![Hackage](https://img.shields.io/hackage/v/persistent-mtl)](https://hackage.haskell.org/package/persistent-mtl)-[![Codecov](https://img.shields.io/codecov/c/gh/brandonchinn178/persistent-mtl)](https://codecov.io/gh/brandonchinn178/persistent-mtl)+[![Codecov](https://img.shields.io/codecov/c/gh/brandonchinn178/persistent-mtl)](https://app.codecov.io/gh/brandonchinn178/persistent-mtl)  Use the `persistent` API in your monad transformer stack, seamlessly interleaving business logic with database operations by simply dropping `SqlQueryT` into your stack. 
persistent-mtl.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.35.0. -- -- see: https://github.com/sol/hpack  name:           persistent-mtl-version:        0.4.0.0+version:        0.5.0.0 synopsis:       Monad transformer for the persistent API description:    A monad transformer and mtl-style type class for using the                 persistent API directly in your monad transformer stack.@@ -19,12 +19,8 @@ extra-source-files:     CHANGELOG.md     README.md-    test/goldens/persistent-2.10/sqlqueryrep_show_representation.golden-    test/goldens/persistent-2.11/sqlqueryrep_show_representation.golden-    test/goldens/persistent-2.12/sqlqueryrep_show_representation.golden     test/goldens/persistent-2.13/sqlqueryrep_show_representation.golden-    test/goldens/persistent-2.8/sqlqueryrep_show_representation.golden-    test/goldens/persistent-2.9/sqlqueryrep_show_representation.golden+    test/goldens/persistent-2.14/sqlqueryrep_show_representation.golden  source-repository head   type: git@@ -33,50 +29,55 @@ library   exposed-modules:       Control.Monad.IO.Rerunnable+      Control.Monad.Trans.Rerunnable       Database.Persist.Monad       Database.Persist.Monad.Class+      Database.Persist.Monad.Internal.PersistentShim+      Database.Persist.Monad.Internal.SqlTransaction       Database.Persist.Monad.Shim       Database.Persist.Monad.SqlQueryRep       Database.Persist.Monad.TestUtils+      Database.Persist.Sql.Shim   other-modules:       Paths_persistent_mtl   hs-source-dirs:       src   ghc-options: -Wall   build-depends:-      base >=4.10 && <4.16-    , conduit >=1.3.0.3 && <1.4-    , containers >=0.5.10.2 && <0.7-    , exceptions >=0.8 && <0.11-    , monad-logger >=0.3.29 && <0.4+      base >=4.14 && <4.16+    , conduit >=1.3.4 && <1.4+    , containers ==0.6.*+    , exceptions ==0.10.*+    , monad-logger ==0.3.*     , mtl >=2.2.2 && <2.3-    , persistent >=2.8.2 && <2.14+    , persistent >=2.13 && <2.15     , resource-pool >=0.2.3.2 && <0.3-    , resourcet >=1.2.1 && <1.3-    , text >=1.2.3.0 && <1.3-    , transformers >=0.5.2.0 && <0.6-    , unliftio >=0.2.7.0 && <0.3-    , unliftio-core >=0.1.2.0 && <0.3-    , unliftio-pool >=0.2.0.0 && <0.3+    , resourcet >=1.2.4 && <1.3+    , text >=1.2.4 && <1.3+    , transformers >=0.5.6 && <0.6+    , unliftio ==0.2.*+    , unliftio-core ==0.2.*+    , unliftio-pool ==0.2.*   default-language: Haskell2010  test-suite persistent-mtl-test   type: exitcode-stdio-1.0   main-is: Main.hs   other-modules:-      Basic       Example       Generated-      Integration-      Mocked-      MockSqlQueryT+      IntegrationTest+      MockedTest+      READMETest       SqlQueryRepTest       TestUtils.DB       TestUtils.Esqueleto       Paths_persistent_mtl   hs-source-dirs:       test-  ghc-options: -Wall+  ghc-options: -Wall -F -pgmF=tasty-autocollect+  build-tool-depends:+      tasty-autocollect:tasty-autocollect   build-depends:       base     , bytestring@@ -93,6 +94,7 @@     , resource-pool     , resourcet     , tasty+    , tasty-autocollect     , tasty-golden     , tasty-hunit     , text
src/Control/Monad/IO/Rerunnable.hs view
@@ -5,10 +5,9 @@ to 'Control.Monad.IO.Class.MonadIO', but use of it requires the user to explicitly acknowledge that the given IO operation can be rerun. -}--module Control.Monad.IO.Rerunnable-  ( MonadRerunnableIO(..)-  ) where+module Control.Monad.IO.Rerunnable (+  MonadRerunnableIO (..),+) where  import Control.Monad.Trans.Class (lift) import qualified Control.Monad.Trans.Except as Except@@ -23,8 +22,9 @@ import qualified Control.Monad.Trans.Writer.Lazy as Writer.Lazy import qualified Control.Monad.Trans.Writer.Strict as Writer.Strict --- | A copy of 'Control.Monad.IO.Class.MonadIO' to explicitly allow only IO--- operations that are rerunnable, e.g. in the context of a SQL transaction.+{-| A copy of 'Control.Monad.IO.Class.MonadIO' to explicitly allow only IO+ operations that are rerunnable, e.g. in the context of a SQL transaction.+-} class Monad m => MonadRerunnableIO m where   -- | Lift the given IO operation to @m@.   --
+ src/Control/Monad/Trans/Rerunnable.hs view
@@ -0,0 +1,68 @@+{-|+Module: Control.Monad.Trans.Rerunnable++Defines the 'MonadRerunnableTrans' type class that is functionally equivalent+to 'Control.Monad.Trans.Class.MonadTrans', but use of it requires the user to+explicitly acknowledge that lifting the given action can be rerun.+-}+module Control.Monad.Trans.Rerunnable (+  MonadRerunnableTrans (..),+) where++import Control.Monad.Trans.Class (lift)+import qualified Control.Monad.Trans.Except as Except+import qualified Control.Monad.Trans.Identity as Identity+import qualified Control.Monad.Trans.Maybe as Maybe+import qualified Control.Monad.Trans.RWS.Lazy as RWS.Lazy+import qualified Control.Monad.Trans.RWS.Strict as RWS.Strict+import qualified Control.Monad.Trans.Reader as Reader+import qualified Control.Monad.Trans.Resource as Resource+import qualified Control.Monad.Trans.State.Lazy as State.Lazy+import qualified Control.Monad.Trans.State.Strict as State.Strict+import qualified Control.Monad.Trans.Writer.Lazy as Writer.Lazy+import qualified Control.Monad.Trans.Writer.Strict as Writer.Strict++{-| A copy of 'Control.Monad.Trans.Class.MonadTrans' to explicitly allow only+lifting actions that are rerunnable, e.g. in the context of a SQL transaction.+-}+class MonadRerunnableTrans t where+  -- | Lift the given action.+  --+  -- The given action may be rerun, so use of this function requires+  -- manually verifying that the given action is rerunnable.+  rerunnableLift :: Monad m => m a -> t m a++{- Instances for common monad transformers -}++instance MonadRerunnableTrans (Reader.ReaderT r) where+  rerunnableLift = lift++instance MonadRerunnableTrans (Except.ExceptT e) where+  rerunnableLift = lift++instance MonadRerunnableTrans Identity.IdentityT where+  rerunnableLift = lift++instance MonadRerunnableTrans Maybe.MaybeT where+  rerunnableLift = lift++instance Monoid w => MonadRerunnableTrans (RWS.Lazy.RWST r w s) where+  rerunnableLift = lift++instance Monoid w => MonadRerunnableTrans (RWS.Strict.RWST r w s) where+  rerunnableLift = lift++instance MonadRerunnableTrans (State.Lazy.StateT s) where+  rerunnableLift = lift++instance MonadRerunnableTrans (State.Strict.StateT s) where+  rerunnableLift = lift++instance Monoid w => MonadRerunnableTrans (Writer.Lazy.WriterT w) where+  rerunnableLift = lift++instance Monoid w => MonadRerunnableTrans (Writer.Strict.WriterT w) where+  rerunnableLift = lift++instance MonadRerunnableTrans Resource.ResourceT where+  rerunnableLift = lift
src/Database/Persist/Monad.hs view
@@ -1,3 +1,14 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+ {-| Module: Database.Persist.Monad @@ -36,159 +47,104 @@   return () @ -}--{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}--module Database.Persist.Monad-  (+module Database.Persist.Monad (   -- * Type class for executing database queries-    MonadSqlQuery-  , withTransaction+  MonadSqlQuery,+  withTransaction,    -- * SqlQueryT monad transformer-  , SqlQueryT-  , mapSqlQueryT-  , runSqlQueryT-  , runSqlQueryTWith-  , SqlQueryEnv(..)-  , mkSqlQueryEnv+  SqlQueryT (..),+  mapSqlQueryT,+  runSqlQueryT,+  runSqlQueryTWith,+  SqlQueryEnv (..),+  mkSqlQueryEnv, +  -- ** SqlQueryT environment+  getSqlBackendPool,+   -- * Transactions-  , SqlTransaction-  , rerunnableLift-  , TransactionError(..)+  SqlTransaction,+  TransactionError (..),+  catchSqlTransaction,    -- * Lifted functions-  , module Database.Persist.Monad.Shim-  ) where+  module Database.Persist.Monad.Shim,+) where  import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)-import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.IO.Unlift (MonadUnliftIO(..), wrappedWithRunInIO)+import Control.Monad.Fix (MonadFix)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.IO.Unlift (MonadUnliftIO (..), wrappedWithRunInIO) import Control.Monad.Logger (MonadLogger)-import Control.Monad.Reader (ReaderT(..), mapReaderT)-import Control.Monad.Reader.Class (MonadReader(..))-import Control.Monad.Trans.Class (MonadTrans(..))+import Control.Monad.Reader (ReaderT (..), asks, mapReaderT)+import Control.Monad.Reader.Class (MonadReader (..))+import Control.Monad.Trans.Class (MonadTrans (..)) import Control.Monad.Trans.Resource (MonadResource) import Data.Pool (Pool)-import Database.Persist.Sql (SqlBackend, SqlPersistT, runSqlConn)-import qualified GHC.TypeLits as GHC+import Database.Persist.Sql (SqlBackend) import UnliftIO.Concurrent (threadDelay) import UnliftIO.Exception (Exception, SomeException, catchJust, throwIO) import UnliftIO.Pool (withResource) -import Control.Monad.IO.Rerunnable (MonadRerunnableIO, rerunnableIO)+import Control.Monad.IO.Rerunnable (MonadRerunnableIO) import Database.Persist.Monad.Class+import Database.Persist.Monad.Internal.SqlTransaction import Database.Persist.Monad.Shim-import Database.Persist.Monad.SqlQueryRep -{- SqlTransaction -}---- | The monad that tracks transaction state.------ Conceptually equivalent to 'Database.Persist.Sql.SqlPersistT', but restricts--- IO operations, for two reasons:---   1. Forking a thread that uses the same 'SqlBackend' as the current thread---      causes Bad Things to happen.---   2. Transactions may need to be retried, in which case IO operations in---      a transaction are required to be rerunnable.------ You shouldn't need to explicitly use this type; your functions should only--- declare the 'MonadSqlQuery' constraint.-newtype SqlTransaction m a = SqlTransaction-  { unSqlTransaction :: SqlPersistT m a-  }-  deriving (Functor, Applicative, Monad, MonadRerunnableIO)--instance-  ( GHC.TypeError ('GHC.Text "Cannot run arbitrary IO actions within a transaction. If the IO action is rerunnable, use rerunnableIO")-  , Monad m-  )-  => MonadIO (SqlTransaction m) where-  liftIO = undefined--instance (MonadSqlQuery m, MonadUnliftIO m) => MonadSqlQuery (SqlTransaction m) where-  type TransactionM (SqlTransaction m) = TransactionM m--  runQueryRep = SqlTransaction . runSqlQueryRep--  -- Delegate to 'm', since 'm' is in charge of starting/stopping transactions.-  -- 'SqlTransaction' is ONLY in charge of executing queries.-  withTransaction = SqlTransaction . withTransaction--runSqlTransaction :: MonadUnliftIO m => SqlBackend -> SqlTransaction m a -> m a-runSqlTransaction conn = (`runSqlConn` conn) . unSqlTransaction---- | 'SqlTransaction' does not have an instance for 'MonadTrans' to prevent--- accidental lifting of unsafe monadic actions. Use this function to explicitly--- mark a monadic action as rerunnable.-rerunnableLift :: MonadUnliftIO m => m a -> SqlTransaction m a-rerunnableLift m = SqlTransaction $ lift $ withRunInIO $ \runInIO -> rerunnableIO $ runInIO m---- | Errors that can occur within a SQL transaction.-data TransactionError-  = RetryLimitExceeded-    -- ^ The retry limit was reached when retrying a transaction.-  deriving (Show, Eq)--instance Exception TransactionError- {- SqlQueryT monad -} --- | Environment to configure running 'SqlQueryT'.------ For simple usage, you can just use 'runSqlQueryT', but for more advanced--- usage, including the ability to retry transactions, use 'mkSqlQueryEnv' with--- 'runSqlQueryTWith'.+{-| Environment to configure running 'SqlQueryT'.++ For simple usage, you can just use 'runSqlQueryT', but for more advanced+ usage, including the ability to retry transactions, use 'mkSqlQueryEnv' with+ 'runSqlQueryTWith'.+-} data SqlQueryEnv = SqlQueryEnv   { backendPool :: Pool SqlBackend-    -- ^ The pool for your persistent backend. Get this from @withSqlitePool@-    -- or the equivalent for your backend.+  -- ^ The pool for your persistent backend. Get this from @withSqlitePool@+  -- or the equivalent for your backend.+  , retryIf :: SomeException -> Bool+  -- ^ Retry a transaction when an exception matches this predicate. Will+  -- retry with an exponential backoff.+  --+  -- Defaults to always returning False (i.e. never retry)+  , retryLimit :: Int+  -- ^ The number of times to retry, if 'retryIf' is satisfied.+  --+  -- Defaults to 10.+  , retryCallback :: SomeException -> IO ()+  -- ^ A callback to run if 'retryIf' returns True. Useful for logging.+  } -  , retryIf     :: SomeException -> Bool-    -- ^ Retry a transaction when an exception matches this predicate. Will-    -- retry with an exponential backoff.-    ---    -- Defaults to always returning False (i.e. never retry)+{-| Build a SqlQueryEnv from the default. -  , retryLimit  :: Int-    -- ^ The number of times to retry, if 'retryIf' is satisfied.-    ---    -- Defaults to 10.-  }+ Usage: --- | Build a SqlQueryEnv from the default.------ Usage:------ @--- let env = mkSqlQueryEnv pool $ \\env -> env { retryIf = 10 }--- in runSqlQueryTWith env m--- @+ @+ let env = mkSqlQueryEnv pool $ \\env -> env { retryIf = 10 }+ in runSqlQueryTWith env m+ @+-} mkSqlQueryEnv :: Pool SqlBackend -> (SqlQueryEnv -> SqlQueryEnv) -> SqlQueryEnv-mkSqlQueryEnv backendPool f = f SqlQueryEnv-  { backendPool-  , retryIf = const False-  , retryLimit = 10-  }+mkSqlQueryEnv backendPool f =+  f+    SqlQueryEnv+      { backendPool+      , retryIf = const False+      , retryLimit = 10+      , retryCallback = \_ -> pure ()+      }  -- | The monad transformer that implements 'MonadSqlQuery'. newtype SqlQueryT m a = SqlQueryT   { unSqlQueryT :: ReaderT SqlQueryEnv m a-  } deriving+  }+  deriving     ( Functor     , Applicative     , Monad+    , MonadFix     , MonadIO     , MonadTrans     , MonadResource@@ -209,14 +165,20 @@   withTransaction m = do     SqlQueryEnv{..} <- SqlQueryT ask     withResource backendPool $ \conn ->-      let filterRetry e = if retryIf e then Just e else Nothing-          loop i = catchJust filterRetry (runSqlTransaction conn m) $ \_ ->+      let transactionEnv =+            SqlTransactionEnv+              { sqlBackend = conn+              , ignoreCatch = retryIf -- don't catch retry errors+              }+          filterRetry e = if retryIf e then Just e else Nothing+          loop i = catchJust filterRetry (runSqlTransaction transactionEnv m) $ \e ->             if i < retryLimit               then do-                threadDelay $ 1000 * 2^i+                liftIO $ retryCallback e+                threadDelay $ 1000 * 2 ^ i                 loop $! i + 1               else throwIO RetryLimitExceeded-      in loop 0+       in loop 0  instance MonadUnliftIO m => MonadUnliftIO (SqlQueryT m) where   withRunInIO = wrappedWithRunInIO SqlQueryT unSqlQueryT@@ -225,16 +187,30 @@ mapSqlQueryT f = SqlQueryT . mapReaderT f . unSqlQueryT  instance MonadReader r m => MonadReader r (SqlQueryT m) where-    ask = lift ask-    local = mapSqlQueryT . local+  ask = lift ask+  local = mapSqlQueryT . local +-- | Errors that can occur when running a SQL transaction.+data TransactionError+  = -- | The retry limit was reached when retrying a transaction.+    RetryLimitExceeded+  deriving (Show, Eq)++instance Exception TransactionError+ {- Running SqlQueryT -}  -- | Run the 'SqlQueryT' monad transformer with the given backend. runSqlQueryT :: Pool SqlBackend -> SqlQueryT m a -> m a runSqlQueryT backendPool = runSqlQueryTWith $ mkSqlQueryEnv backendPool id --- | Run the 'SqlQueryT' monad transformer with the explicitly provided--- environment.+{-| Run the 'SqlQueryT' monad transformer with the explicitly provided+ environment.+-} runSqlQueryTWith :: SqlQueryEnv -> SqlQueryT m a -> m a runSqlQueryTWith env = (`runReaderT` env) . unSqlQueryT++{- SqlQueryT environment -}++getSqlBackendPool :: Monad m => SqlQueryT m (Pool SqlBackend)+getSqlBackendPool = SqlQueryT (asks backendPool)
src/Database/Persist/Monad/Class.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableSuperClasses #-}+ {-| Module: Database.Persist.Monad.Class @@ -6,13 +10,9 @@ 'Database.Persist.Monad.SqlQueryRep.SqlQueryRep' sent by a lifted function from @Database.Persist.Monad.Shim@. -}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableSuperClasses #-}--module Database.Persist.Monad.Class-  ( MonadSqlQuery(..)-  ) where+module Database.Persist.Monad.Class (+  MonadSqlQuery (..),+) where  import Control.Monad.Trans.Class (lift) import qualified Control.Monad.Trans.Except as Except
+ src/Database/Persist/Monad/Internal/PersistentShim.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}++module Database.Persist.Monad.Internal.PersistentShim (+  SafeToInsert,+) where++#if MIN_VERSION_persistent(2,14,1)+import Database.Persist.Class (SafeToInsert)+#elif MIN_VERSION_persistent(2,14,0)+import Database.Persist.Class.PersistEntity (SafeToInsert)+#endif++#if !MIN_VERSION_persistent(2,14,0)+class SafeToInsert record+instance SafeToInsert record+#endif
+ src/Database/Persist/Monad/Internal/SqlTransaction.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++module Database.Persist.Monad.Internal.SqlTransaction (+  SqlTransaction (..),+  SqlTransactionEnv (..),+  runSqlTransaction,+  catchSqlTransaction,+) where++import Control.Monad.Fix (MonadFix)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.IO.Unlift (MonadUnliftIO (..))+import Control.Monad.Reader (ReaderT, ask, withReaderT)+import Database.Persist.Sql (SqlBackend, runSqlConn)+import qualified GHC.TypeLits as GHC+import UnliftIO.Exception (Exception, SomeException, catchJust, fromException)++import Control.Monad.IO.Rerunnable (MonadRerunnableIO)+import Control.Monad.Trans.Rerunnable (MonadRerunnableTrans)+import Database.Persist.Monad.Class+import Database.Persist.Monad.SqlQueryRep++{-| The monad that tracks transaction state.++ Conceptually equivalent to 'Database.Persist.Sql.SqlPersistT', but restricts+ IO operations, for two reasons:++   1. Forking a thread that uses the same 'SqlBackend' as the current thread+      causes Bad Things to happen.+   2. Transactions may need to be retried, in which case IO operations in+      a transaction are required to be rerunnable.++ You shouldn't need to explicitly use this type; your functions should only+ declare the 'MonadSqlQuery' constraint.+-}+newtype SqlTransaction m a = UnsafeSqlTransaction+  { unSqlTransaction :: ReaderT SqlTransactionEnv m a+  }+  deriving (Functor, Applicative, Monad, MonadFix, MonadRerunnableIO, MonadRerunnableTrans)++instance+  ( GHC.TypeError ( 'GHC.Text "Cannot run arbitrary IO actions within a transaction. If the IO action is rerunnable, use rerunnableIO")+  , Monad m+  ) =>+  MonadIO (SqlTransaction m)+  where+  liftIO = undefined++instance (MonadSqlQuery m, MonadUnliftIO m) => MonadSqlQuery (SqlTransaction m) where+  type TransactionM (SqlTransaction m) = TransactionM m++  runQueryRep = UnsafeSqlTransaction . withReaderT sqlBackend . runSqlQueryRep++  -- Delegate to 'm', since 'm' is in charge of starting/stopping transactions.+  -- 'SqlTransaction' is ONLY in charge of executing queries.+  withTransaction = UnsafeSqlTransaction . withTransaction++data SqlTransactionEnv = SqlTransactionEnv+  { sqlBackend :: SqlBackend+  , ignoreCatch :: SomeException -> Bool+  }++runSqlTransaction ::+  MonadUnliftIO m =>+  SqlTransactionEnv ->+  SqlTransaction m a ->+  m a+runSqlTransaction opts =+  (`runSqlConn` sqlBackend opts)+    . withReaderT (\conn -> opts{sqlBackend = conn})+    . unSqlTransaction++-- | Like normal 'catch', except ignores errors specified by 'ignoreCatch'.+catchSqlTransaction ::+  (MonadUnliftIO m, Exception e) =>+  SqlTransaction m a ->+  (e -> SqlTransaction m a) ->+  SqlTransaction m a+catchSqlTransaction (UnsafeSqlTransaction m) handler =+  UnsafeSqlTransaction $ m `catch` (unSqlTransaction . handler)+  where+    catch a b = do+      SqlTransactionEnv{ignoreCatch} <- ask+      catchJust+        (\e -> if ignoreCatch e then Nothing else fromException e)+        a+        b
src/Database/Persist/Monad/Shim.hs view
@@ -1,3 +1,6 @@+{- THIS FILE IS AUTOGENERATED AND SHOULD NOT BE EDITED MANUALLY -}+{- FOURMOLU_DISABLE -}+ {-| Module: Database.Persist.Monad.Shim @@ -7,8 +10,6 @@ @Database.Persist.Monad.SqlQueryRep@. -} -{- THIS FILE IS AUTOGENERATED AND SHOULD NOT BE EDITED MANUALLY -}- {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-}@@ -33,7 +34,9 @@ import Database.Persist.Monad.Class (MonadSqlQuery(..)) import Database.Persist.Monad.SqlQueryRep (SqlQueryRep(..)) -{-# ANN module "HLint: ignore" #-}+#if !MIN_VERSION_persistent(2,14,1)+import Database.Persist.Monad.Internal.PersistentShim (SafeToInsert)+#endif  -- | The lifted version of 'Database.Persist.Sql.get' get@@ -79,25 +82,25 @@  -- | The lifted version of 'Database.Persist.Sql.insert' insert-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m (Key record) insert a1 = runQueryRep $ Insert a1  -- | The lifted version of 'Database.Persist.Sql.insert_' insert_-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m () insert_ a1 = runQueryRep $ Insert_ a1  -- | The lifted version of 'Database.Persist.Sql.insertMany' insertMany-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => [record] -> m [Key record] insertMany a1 = runQueryRep $ InsertMany a1  -- | The lifted version of 'Database.Persist.Sql.insertMany_' insertMany_-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => [record] -> m () insertMany_ a1 = runQueryRep $ InsertMany_ a1 @@ -151,13 +154,13 @@  -- | The lifted version of 'Database.Persist.Sql.insertEntity' insertEntity-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m (Entity record) insertEntity a1 = runQueryRep $ InsertEntity a1  -- | The lifted version of 'Database.Persist.Sql.insertRecord' insertRecord-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m record insertRecord a1 = runQueryRep $ InsertRecord a1 @@ -167,35 +170,23 @@   => Unique record -> m (Maybe (Entity record)) getBy a1 = runQueryRep $ GetBy a1 -#if MIN_VERSION_persistent(2,10,0) -- | The lifted version of 'Database.Persist.Sql.getByValue' getByValue   :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, Typeable record, MonadSqlQuery m)   => record -> m (Maybe (Entity record)) getByValue a1 = runQueryRep $ GetByValue a1-#endif -#if !MIN_VERSION_persistent(2,10,0)--- | The lifted version of 'Database.Persist.Sql.getByValue'-getByValue-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)-  => record -> m (Maybe (Entity record))-getByValue a1 = runQueryRep $ GetByValue a1-#endif- -- | The lifted version of 'Database.Persist.Sql.checkUnique' checkUnique   :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)   => record -> m (Maybe (Unique record)) checkUnique a1 = runQueryRep $ CheckUnique a1 -#if MIN_VERSION_persistent(2,11,0) -- | The lifted version of 'Database.Persist.Sql.checkUniqueUpdateable' checkUniqueUpdateable   :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)   => Entity record -> m (Maybe (Unique record)) checkUniqueUpdateable a1 = runQueryRep $ CheckUniqueUpdateable a1-#endif  -- | The lifted version of 'Database.Persist.Sql.deleteBy' deleteBy@@ -205,57 +196,37 @@  -- | The lifted version of 'Database.Persist.Sql.insertUnique' insertUnique-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m (Maybe (Key record)) insertUnique a1 = runQueryRep $ InsertUnique a1 -#if MIN_VERSION_persistent(2,10,0) -- | The lifted version of 'Database.Persist.Sql.upsert' upsert-  :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> [Update record] -> m (Entity record) upsert a1 a2 = runQueryRep $ Upsert a1 a2-#endif -#if !MIN_VERSION_persistent(2,10,0)--- | The lifted version of 'Database.Persist.Sql.upsert'-upsert-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)-  => record -> [Update record] -> m (Entity record)-upsert a1 a2 = runQueryRep $ Upsert a1 a2-#endif- -- | The lifted version of 'Database.Persist.Sql.upsertBy' upsertBy-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => Unique record -> record -> [Update record] -> m (Entity record) upsertBy a1 a2 a3 = runQueryRep $ UpsertBy a1 a2 a3  -- | The lifted version of 'Database.Persist.Sql.putMany' putMany-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => [record] -> m () putMany a1 = runQueryRep $ PutMany a1 -#if MIN_VERSION_persistent(2,10,0) -- | The lifted version of 'Database.Persist.Sql.insertBy' insertBy-  :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m (Either (Entity record) (Key record)) insertBy a1 = runQueryRep $ InsertBy a1-#endif -#if !MIN_VERSION_persistent(2,10,0)--- | The lifted version of 'Database.Persist.Sql.insertBy'-insertBy-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)-  => record -> m (Either (Entity record) (Key record))-insertBy a1 = runQueryRep $ InsertBy a1-#endif- -- | The lifted version of 'Database.Persist.Sql.insertUniqueEntity' insertUniqueEntity-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)+  :: (PersistRecordBackend record SqlBackend, SafeToInsert record, Typeable record, MonadSqlQuery m)   => record -> m (Maybe (Entity record)) insertUniqueEntity a1 = runQueryRep $ InsertUniqueEntity a1 @@ -265,22 +236,12 @@   => Key record -> record -> m (Maybe (Unique record)) replaceUnique a1 a2 = runQueryRep $ ReplaceUnique a1 a2 -#if MIN_VERSION_persistent(2,10,0) -- | The lifted version of 'Database.Persist.Sql.onlyUnique' onlyUnique   :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, Typeable record, MonadSqlQuery m)   => record -> m (Unique record) onlyUnique a1 = runQueryRep $ OnlyUnique a1-#endif -#if !MIN_VERSION_persistent(2,10,0)--- | The lifted version of 'Database.Persist.Sql.onlyUnique'-onlyUnique-  :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)-  => record -> m (Unique record)-onlyUnique a1 = runQueryRep $ OnlyUnique a1-#endif- -- | The lifted version of 'Database.Persist.Sql.selectSourceRes' selectSourceRes   :: (MonadIO m2, PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)@@ -305,13 +266,11 @@   => [Filter record] -> m Int count a1 = runQueryRep $ Count a1 -#if MIN_VERSION_persistent(2,11,0) -- | The lifted version of 'Database.Persist.Sql.exists' exists   :: (PersistRecordBackend record SqlBackend, Typeable record, MonadSqlQuery m)   => [Filter record] -> m Bool exists a1 = runQueryRep $ Exists a1-#endif  -- | The lifted version of 'Database.Persist.Sql.selectSource' selectSource@@ -361,22 +320,6 @@   => [Filter record] -> [Update record] -> m Int64 updateWhereCount a1 a2 = runQueryRep $ UpdateWhereCount a1 a2 -#if !MIN_VERSION_persistent(2,13,0)--- | The lifted version of 'Database.Persist.Sql.deleteCascade'-deleteCascade-  :: (DeleteCascade record SqlBackend, Typeable record, MonadSqlQuery m)-  => Key record -> m ()-deleteCascade a1 = runQueryRep $ DeleteCascade a1-#endif--#if !MIN_VERSION_persistent(2,13,0)--- | The lifted version of 'Database.Persist.Sql.deleteCascadeWhere'-deleteCascadeWhere-  :: (DeleteCascade record SqlBackend, Typeable record, MonadSqlQuery m)-  => [Filter record] -> m ()-deleteCascadeWhere a1 = runQueryRep $ DeleteCascadeWhere a1-#endif- -- | The lifted version of 'Database.Persist.Sql.parseMigration' parseMigration   :: (HasCallStack, MonadSqlQuery m)@@ -413,13 +356,11 @@   => Migration -> m () runMigration a1 = runQueryRep $ RunMigration a1 -#if MIN_VERSION_persistent(2,10,2) -- | The lifted version of 'Database.Persist.Sql.runMigrationQuiet' runMigrationQuiet   :: (MonadSqlQuery m)   => Migration -> m [Text] runMigrationQuiet a1 = runQueryRep $ RunMigrationQuiet a1-#endif  -- | The lifted version of 'Database.Persist.Sql.runMigrationSilent' runMigrationSilent@@ -433,13 +374,11 @@   => Migration -> m () runMigrationUnsafe a1 = runQueryRep $ RunMigrationUnsafe a1 -#if MIN_VERSION_persistent(2,10,2) -- | The lifted version of 'Database.Persist.Sql.runMigrationUnsafeQuiet' runMigrationUnsafeQuiet   :: (HasCallStack, MonadSqlQuery m)   => Migration -> m [Text] runMigrationUnsafeQuiet a1 = runQueryRep $ RunMigrationUnsafeQuiet a1-#endif  -- | The lifted version of 'Database.Persist.Sql.getFieldName' getFieldName@@ -495,13 +434,11 @@   => m () transactionSave = runQueryRep $ TransactionSave -#if MIN_VERSION_persistent(2,9,0) -- | The lifted version of 'Database.Persist.Sql.transactionSaveWithIsolation' transactionSaveWithIsolation   :: (MonadSqlQuery m)   => IsolationLevel -> m () transactionSaveWithIsolation a1 = runQueryRep $ TransactionSaveWithIsolation a1-#endif  -- | The lifted version of 'Database.Persist.Sql.transactionUndo' transactionUndo@@ -509,13 +446,11 @@   => m () transactionUndo = runQueryRep $ TransactionUndo -#if MIN_VERSION_persistent(2,9,0) -- | The lifted version of 'Database.Persist.Sql.transactionUndoWithIsolation' transactionUndoWithIsolation   :: (MonadSqlQuery m)   => IsolationLevel -> m () transactionUndoWithIsolation a1 = runQueryRep $ TransactionUndoWithIsolation a1-#endif  -- | Lift an arbitrary 'SqlPersistT' action into 'MonadSqlQuery'. --
src/Database/Persist/Monad/SqlQueryRep.hs view
@@ -1,3 +1,6 @@+{- THIS FILE IS AUTOGENERATED AND SHOULD NOT BE EDITED MANUALLY -}+{- FOURMOLU_DISABLE -}+ {-| Module: Database.Persist.Monad.SqlQueryRep @@ -8,8 +11,6 @@ @Database.Persist.Monad.Shim@. -} -{- THIS FILE IS AUTOGENERATED AND SHOULD NOT BE EDITED MANUALLY -}- {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-}@@ -38,7 +39,9 @@ import Database.Persist.Sql as Persist hiding (pattern Update) import GHC.Stack (HasCallStack) -{-# ANN module "HLint: ignore" #-}+#if !MIN_VERSION_persistent(2,14,1)+import Database.Persist.Monad.Internal.PersistentShim (SafeToInsert)+#endif  -- | The data type containing a constructor for each persistent function we'd -- like to lift into 'Database.Persist.Monad.MonadSqlQuery'.@@ -87,22 +90,22 @@    -- | Constructor corresponding to 'Persist.insert'   Insert-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => record -> SqlQueryRep record (Key record)    -- | Constructor corresponding to 'Persist.insert_'   Insert_-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => record -> SqlQueryRep record ()    -- | Constructor corresponding to 'Persist.insertMany'   InsertMany-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => [record] -> SqlQueryRep record [Key record]    -- | Constructor corresponding to 'Persist.insertMany_'   InsertMany_-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => [record] -> SqlQueryRep record ()    -- | Constructor corresponding to 'Persist.insertEntityMany'@@ -147,12 +150,12 @@    -- | Constructor corresponding to 'Persist.insertEntity'   InsertEntity-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => record -> SqlQueryRep record (Entity record)    -- | Constructor corresponding to 'Persist.insertRecord'   InsertRecord-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => record -> SqlQueryRep record record    -- | Constructor corresponding to 'Persist.getBy'@@ -160,31 +163,20 @@     :: (PersistRecordBackend record SqlBackend)     => Unique record -> SqlQueryRep record (Maybe (Entity record)) -#if MIN_VERSION_persistent(2,10,0)   -- | Constructor corresponding to 'Persist.getByValue'   GetByValue     :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record)     => record -> SqlQueryRep record (Maybe (Entity record))-#endif -#if !MIN_VERSION_persistent(2,10,0)-  -- | Constructor corresponding to 'Persist.getByValue'-  GetByValue-    :: (PersistRecordBackend record SqlBackend)-    => record -> SqlQueryRep record (Maybe (Entity record))-#endif-   -- | Constructor corresponding to 'Persist.checkUnique'   CheckUnique     :: (PersistRecordBackend record SqlBackend)     => record -> SqlQueryRep record (Maybe (Unique record)) -#if MIN_VERSION_persistent(2,11,0)   -- | Constructor corresponding to 'Persist.checkUniqueUpdateable'   CheckUniqueUpdateable     :: (PersistRecordBackend record SqlBackend)     => Entity record -> SqlQueryRep record (Maybe (Unique record))-#endif    -- | Constructor corresponding to 'Persist.deleteBy'   DeleteBy@@ -193,50 +185,32 @@    -- | Constructor corresponding to 'Persist.insertUnique'   InsertUnique-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => record -> SqlQueryRep record (Maybe (Key record)) -#if MIN_VERSION_persistent(2,10,0)   -- | Constructor corresponding to 'Persist.upsert'   Upsert-    :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record)+    :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record, SafeToInsert record)     => record -> [Update record] -> SqlQueryRep record (Entity record)-#endif -#if !MIN_VERSION_persistent(2,10,0)-  -- | Constructor corresponding to 'Persist.upsert'-  Upsert-    :: (PersistRecordBackend record SqlBackend)-    => record -> [Update record] -> SqlQueryRep record (Entity record)-#endif-   -- | Constructor corresponding to 'Persist.upsertBy'   UpsertBy-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => Unique record -> record -> [Update record] -> SqlQueryRep record (Entity record)    -- | Constructor corresponding to 'Persist.putMany'   PutMany-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => [record] -> SqlQueryRep record () -#if MIN_VERSION_persistent(2,10,0)   -- | Constructor corresponding to 'Persist.insertBy'   InsertBy-    :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record)+    :: (PersistRecordBackend record SqlBackend, AtLeastOneUniqueKey record, SafeToInsert record)     => record -> SqlQueryRep record (Either (Entity record) (Key record))-#endif -#if !MIN_VERSION_persistent(2,10,0)-  -- | Constructor corresponding to 'Persist.insertBy'-  InsertBy-    :: (PersistRecordBackend record SqlBackend)-    => record -> SqlQueryRep record (Either (Entity record) (Key record))-#endif-   -- | Constructor corresponding to 'Persist.insertUniqueEntity'   InsertUniqueEntity-    :: (PersistRecordBackend record SqlBackend)+    :: (PersistRecordBackend record SqlBackend, SafeToInsert record)     => record -> SqlQueryRep record (Maybe (Entity record))    -- | Constructor corresponding to 'Persist.replaceUnique'@@ -244,20 +218,11 @@     :: (PersistRecordBackend record SqlBackend, Eq (Unique record), Eq record)     => Key record -> record -> SqlQueryRep record (Maybe (Unique record)) -#if MIN_VERSION_persistent(2,10,0)   -- | Constructor corresponding to 'Persist.onlyUnique'   OnlyUnique     :: (PersistRecordBackend record SqlBackend, OnlyOneUniqueKey record)     => record -> SqlQueryRep record (Unique record)-#endif -#if !MIN_VERSION_persistent(2,10,0)-  -- | Constructor corresponding to 'Persist.onlyUnique'-  OnlyUnique-    :: (PersistRecordBackend record SqlBackend)-    => record -> SqlQueryRep record (Unique record)-#endif-   -- | Constructor corresponding to 'Persist.selectSourceRes'   SelectSourceRes     :: (MonadIO m2, PersistRecordBackend record SqlBackend)@@ -278,12 +243,10 @@     :: (PersistRecordBackend record SqlBackend)     => [Filter record] -> SqlQueryRep record Int -#if MIN_VERSION_persistent(2,11,0)   -- | Constructor corresponding to 'Persist.exists'   Exists     :: (PersistRecordBackend record SqlBackend)     => [Filter record] -> SqlQueryRep record Bool-#endif    -- | Constructor corresponding to 'Persist.selectList'   SelectList@@ -315,20 +278,6 @@     :: (PersistRecordBackend record SqlBackend)     => [Filter record] -> [Update record] -> SqlQueryRep record Int64 -#if !MIN_VERSION_persistent(2,13,0)-  -- | Constructor corresponding to 'Persist.deleteCascade'-  DeleteCascade-    :: (DeleteCascade record SqlBackend)-    => Key record -> SqlQueryRep record ()-#endif--#if !MIN_VERSION_persistent(2,13,0)-  -- | Constructor corresponding to 'Persist.deleteCascadeWhere'-  DeleteCascadeWhere-    :: (DeleteCascade record SqlBackend)-    => [Filter record] -> SqlQueryRep record ()-#endif-   -- | Constructor corresponding to 'Persist.parseMigration'   ParseMigration     :: (HasCallStack)@@ -359,12 +308,10 @@     :: ()     => Migration -> SqlQueryRep Void () -#if MIN_VERSION_persistent(2,10,2)   -- | Constructor corresponding to 'Persist.runMigrationQuiet'   RunMigrationQuiet     :: ()     => Migration -> SqlQueryRep Void [Text]-#endif    -- | Constructor corresponding to 'Persist.runMigrationSilent'   RunMigrationSilent@@ -376,12 +323,10 @@     :: ()     => Migration -> SqlQueryRep Void () -#if MIN_VERSION_persistent(2,10,2)   -- | Constructor corresponding to 'Persist.runMigrationUnsafeQuiet'   RunMigrationUnsafeQuiet     :: (HasCallStack)     => Migration -> SqlQueryRep Void [Text]-#endif    -- | Constructor corresponding to 'Persist.getFieldName'   GetFieldName@@ -423,24 +368,20 @@     :: ()     => SqlQueryRep Void () -#if MIN_VERSION_persistent(2,9,0)   -- | Constructor corresponding to 'Persist.transactionSaveWithIsolation'   TransactionSaveWithIsolation     :: ()     => IsolationLevel -> SqlQueryRep Void ()-#endif    -- | Constructor corresponding to 'Persist.transactionUndo'   TransactionUndo     :: ()     => SqlQueryRep Void () -#if MIN_VERSION_persistent(2,9,0)   -- | Constructor corresponding to 'Persist.transactionUndoWithIsolation'   TransactionUndoWithIsolation     :: ()     => IsolationLevel -> SqlQueryRep Void ()-#endif    -- | Constructor for lifting an arbitrary SqlPersistT action into SqlQueryRep.   UnsafeLiftSql@@ -470,73 +411,39 @@     InsertEntity{} -> "InsertEntity{..}" ++ record     InsertRecord{} -> "InsertRecord{..}" ++ record     GetBy{} -> "GetBy{..}" ++ record-#if MIN_VERSION_persistent(2,10,0)     GetByValue{} -> "GetByValue{..}" ++ record-#endif-#if !MIN_VERSION_persistent(2,10,0)-    GetByValue{} -> "GetByValue{..}" ++ record-#endif     CheckUnique{} -> "CheckUnique{..}" ++ record-#if MIN_VERSION_persistent(2,11,0)     CheckUniqueUpdateable{} -> "CheckUniqueUpdateable{..}" ++ record-#endif     DeleteBy{} -> "DeleteBy{..}" ++ record     InsertUnique{} -> "InsertUnique{..}" ++ record-#if MIN_VERSION_persistent(2,10,0)     Upsert{} -> "Upsert{..}" ++ record-#endif-#if !MIN_VERSION_persistent(2,10,0)-    Upsert{} -> "Upsert{..}" ++ record-#endif     UpsertBy{} -> "UpsertBy{..}" ++ record     PutMany{} -> "PutMany{..}" ++ record-#if MIN_VERSION_persistent(2,10,0)     InsertBy{} -> "InsertBy{..}" ++ record-#endif-#if !MIN_VERSION_persistent(2,10,0)-    InsertBy{} -> "InsertBy{..}" ++ record-#endif     InsertUniqueEntity{} -> "InsertUniqueEntity{..}" ++ record     ReplaceUnique{} -> "ReplaceUnique{..}" ++ record-#if MIN_VERSION_persistent(2,10,0)     OnlyUnique{} -> "OnlyUnique{..}" ++ record-#endif-#if !MIN_VERSION_persistent(2,10,0)-    OnlyUnique{} -> "OnlyUnique{..}" ++ record-#endif     SelectSourceRes{} -> "SelectSourceRes{..}" ++ record     SelectFirst{} -> "SelectFirst{..}" ++ record     SelectKeysRes{} -> "SelectKeysRes{..}" ++ record     Count{} -> "Count{..}" ++ record-#if MIN_VERSION_persistent(2,11,0)     Exists{} -> "Exists{..}" ++ record-#endif     SelectList{} -> "SelectList{..}" ++ record     SelectKeysList{} -> "SelectKeysList{..}" ++ record     UpdateWhere{} -> "UpdateWhere{..}" ++ record     DeleteWhere{} -> "DeleteWhere{..}" ++ record     DeleteWhereCount{} -> "DeleteWhereCount{..}" ++ record     UpdateWhereCount{} -> "UpdateWhereCount{..}" ++ record-#if !MIN_VERSION_persistent(2,13,0)-    DeleteCascade{} -> "DeleteCascade{..}" ++ record-#endif-#if !MIN_VERSION_persistent(2,13,0)-    DeleteCascadeWhere{} -> "DeleteCascadeWhere{..}" ++ record-#endif     ParseMigration{} -> "ParseMigration{..}" ++ record     ParseMigration'{} -> "ParseMigration'{..}" ++ record     PrintMigration{} -> "PrintMigration{..}" ++ record     ShowMigration{} -> "ShowMigration{..}" ++ record     GetMigration{} -> "GetMigration{..}" ++ record     RunMigration{} -> "RunMigration{..}" ++ record-#if MIN_VERSION_persistent(2,10,2)     RunMigrationQuiet{} -> "RunMigrationQuiet{..}" ++ record-#endif     RunMigrationSilent{} -> "RunMigrationSilent{..}" ++ record     RunMigrationUnsafe{} -> "RunMigrationUnsafe{..}" ++ record-#if MIN_VERSION_persistent(2,10,2)     RunMigrationUnsafeQuiet{} -> "RunMigrationUnsafeQuiet{..}" ++ record-#endif     GetFieldName{} -> "GetFieldName{..}" ++ record     GetTableName{} -> "GetTableName{..}" ++ record     WithRawQuery{} -> "WithRawQuery{..}" ++ record@@ -545,13 +452,9 @@     RawExecuteCount{} -> "RawExecuteCount{..}" ++ record     RawSql{} -> "RawSql{..}" ++ record     TransactionSave{} -> "TransactionSave{..}" ++ record-#if MIN_VERSION_persistent(2,9,0)     TransactionSaveWithIsolation{} -> "TransactionSaveWithIsolation{..}" ++ record-#endif     TransactionUndo{} -> "TransactionUndo{..}" ++ record-#if MIN_VERSION_persistent(2,9,0)     TransactionUndoWithIsolation{} -> "TransactionUndoWithIsolation{..}" ++ record-#endif     UnsafeLiftSql label _ -> "UnsafeLiftSql{" ++ Text.unpack label ++ "}"     where       record = case recordTypeRep of@@ -587,73 +490,39 @@   InsertEntity a1 -> Persist.insertEntity a1   InsertRecord a1 -> Persist.insertRecord a1   GetBy a1 -> Persist.getBy a1-#if MIN_VERSION_persistent(2,10,0)   GetByValue a1 -> Persist.getByValue a1-#endif-#if !MIN_VERSION_persistent(2,10,0)-  GetByValue a1 -> Persist.getByValue a1-#endif   CheckUnique a1 -> Persist.checkUnique a1-#if MIN_VERSION_persistent(2,11,0)   CheckUniqueUpdateable a1 -> Persist.checkUniqueUpdateable a1-#endif   DeleteBy a1 -> Persist.deleteBy a1   InsertUnique a1 -> Persist.insertUnique a1-#if MIN_VERSION_persistent(2,10,0)   Upsert a1 a2 -> Persist.upsert a1 a2-#endif-#if !MIN_VERSION_persistent(2,10,0)-  Upsert a1 a2 -> Persist.upsert a1 a2-#endif   UpsertBy a1 a2 a3 -> Persist.upsertBy a1 a2 a3   PutMany a1 -> Persist.putMany a1-#if MIN_VERSION_persistent(2,10,0)   InsertBy a1 -> Persist.insertBy a1-#endif-#if !MIN_VERSION_persistent(2,10,0)-  InsertBy a1 -> Persist.insertBy a1-#endif   InsertUniqueEntity a1 -> Persist.insertUniqueEntity a1   ReplaceUnique a1 a2 -> Persist.replaceUnique a1 a2-#if MIN_VERSION_persistent(2,10,0)   OnlyUnique a1 -> Persist.onlyUnique a1-#endif-#if !MIN_VERSION_persistent(2,10,0)-  OnlyUnique a1 -> Persist.onlyUnique a1-#endif   SelectSourceRes a1 a2 -> Persist.selectSourceRes a1 a2   SelectFirst a1 a2 -> Persist.selectFirst a1 a2   SelectKeysRes a1 a2 -> Persist.selectKeysRes a1 a2   Count a1 -> Persist.count a1-#if MIN_VERSION_persistent(2,11,0)   Exists a1 -> Persist.exists a1-#endif   SelectList a1 a2 -> Persist.selectList a1 a2   SelectKeysList a1 a2 -> Persist.selectKeysList a1 a2   UpdateWhere a1 a2 -> Persist.updateWhere a1 a2   DeleteWhere a1 -> Persist.deleteWhere a1   DeleteWhereCount a1 -> Persist.deleteWhereCount a1   UpdateWhereCount a1 a2 -> Persist.updateWhereCount a1 a2-#if !MIN_VERSION_persistent(2,13,0)-  DeleteCascade a1 -> Persist.deleteCascade a1-#endif-#if !MIN_VERSION_persistent(2,13,0)-  DeleteCascadeWhere a1 -> Persist.deleteCascadeWhere a1-#endif   ParseMigration a1 -> Persist.parseMigration a1   ParseMigration' a1 -> Persist.parseMigration' a1   PrintMigration a1 -> Persist.printMigration a1   ShowMigration a1 -> Persist.showMigration a1   GetMigration a1 -> Persist.getMigration a1   RunMigration a1 -> Persist.runMigration a1-#if MIN_VERSION_persistent(2,10,2)   RunMigrationQuiet a1 -> Persist.runMigrationQuiet a1-#endif   RunMigrationSilent a1 -> Persist.runMigrationSilent a1   RunMigrationUnsafe a1 -> Persist.runMigrationUnsafe a1-#if MIN_VERSION_persistent(2,10,2)   RunMigrationUnsafeQuiet a1 -> Persist.runMigrationUnsafeQuiet a1-#endif   GetFieldName a1 -> Persist.getFieldName a1   GetTableName a1 -> Persist.getTableName a1   WithRawQuery a1 a2 a3 -> Persist.withRawQuery a1 a2 a3@@ -662,11 +531,7 @@   RawExecuteCount a1 a2 -> Persist.rawExecuteCount a1 a2   RawSql a1 a2 -> Persist.rawSql a1 a2   TransactionSave -> Persist.transactionSave-#if MIN_VERSION_persistent(2,9,0)   TransactionSaveWithIsolation a1 -> Persist.transactionSaveWithIsolation a1-#endif   TransactionUndo -> Persist.transactionUndo-#if MIN_VERSION_persistent(2,9,0)   TransactionUndoWithIsolation a1 -> Persist.transactionUndoWithIsolation a1-#endif   UnsafeLiftSql _ action -> action
src/Database/Persist/Monad/TestUtils.hs view
@@ -1,10 +1,3 @@-{-|-Module: Database.Persist.Monad.TestUtils--Defines 'MockSqlQueryT', which one can use in tests in order to mock out-@persistent@ database queries called in production code.--}- {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-}@@ -13,44 +6,57 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module Database.Persist.Monad.TestUtils-  ( MockSqlQueryT-  , runMockSqlQueryT-  , withRecord-  , mockQuery-  , MockQuery+{-|+Module: Database.Persist.Monad.TestUtils +Defines 'MockSqlQueryT', which one can use in tests in order to mock out+@persistent@ database queries called in production code.+-}+module Database.Persist.Monad.TestUtils (+  MockSqlQueryT,+  runMockSqlQueryT,+  withRecord,+  mockQuery,+  MockQuery,+   -- * Specialized helpers-  , mockSelectSource-  , mockSelectKeys-  , mockWithRawQuery-  , mockRawQuery-  , mockRawSql+  mockSelectSource,+  mockSelectKeys,+  mockWithRawQuery,+  mockRawQuery,+  mockRawSql,    -- * Re-exports-  , SqlQueryRep(..)-  ) where+  SqlQueryRep (..),+) where  import Conduit ((.|)) import qualified Conduit import Control.Monad (msum)-import Control.Monad.IO.Class (MonadIO(..))+import Control.Monad.IO.Class (MonadIO (..)) import Control.Monad.Reader (ReaderT, ask, runReaderT) import Control.Monad.Trans.Resource (MonadResource) import qualified Data.Acquire as Acquire import Data.Text (Text) import qualified Data.Text as Text-import Data.Typeable (Typeable, eqT, (:~:)(..))-import Database.Persist.Sql-    (Entity, Filter, Key, PersistValue, SelectOpt, rawSqlProcessRow)+import Data.Typeable (Typeable, eqT, (:~:) (..))+import Database.Persist.Sql (+  Entity,+  Filter,+  Key,+  PersistValue,+  SelectOpt,+  rawSqlProcessRow,+ ) -import Database.Persist.Monad.Class (MonadSqlQuery(..))-import Database.Persist.Monad.SqlQueryRep (SqlQueryRep(..))+import Database.Persist.Monad.Class (MonadSqlQuery (..))+import Database.Persist.Monad.SqlQueryRep (SqlQueryRep (..))  -- | A monad transformer for testing functions that use 'MonadSqlQuery'. newtype MockSqlQueryT m a = MockSqlQueryT   { unMockSqlQueryT :: ReaderT [MockQuery] m a-  } deriving+  }+  deriving     ( Functor     , Applicative     , Monad@@ -58,34 +64,35 @@     , MonadResource     ) --- | Runs a 'MockSqlQueryT' monad transformer using the given mocks.------ When a database query is executed, the first mock that returns a 'Just' is--- returned. If no mocks match the query, an error is thrown. See 'SqlQueryRep'--- for the constructors available to match against. Most of the time, you'll--- want to use 'withRecord' to only match queries against a specific @record@--- type (e.g. only match 'Database.Persist.Monad.Shim.selectList' calls for--- the @Person@ entity).------ Usage:------ @--- myFunction :: MonadSqlQuery m => m [String]--- myFunction = map personName <$> selectList [PersonAge >. 25] []------ let persons = [Person ...]--- result <- runMockSqlQueryT myFunction---   [ withRecord \@Person $ \\case---       SelectList _ _ -> Just persons---       _ -> Nothing---   , withRecord \@Post $ \\case---       Insert Post{ name = "post1" } -> Just $ toSqlKey 1---       _ -> Nothing---   , mockQuery $ \\case---       RawExecuteCount "DELETE FROM person WHERE name = \'Alice\'" [] -> Just 1---       _ -> Nothing---   ]--- @+{-| Runs a 'MockSqlQueryT' monad transformer using the given mocks.++ When a database query is executed, the first mock that returns a 'Just' is+ returned. If no mocks match the query, an error is thrown. See 'SqlQueryRep'+ for the constructors available to match against. Most of the time, you'll+ want to use 'withRecord' to only match queries against a specific @record@+ type (e.g. only match 'Database.Persist.Monad.Shim.selectList' calls for+ the @Person@ entity).++ Usage:++ @+ myFunction :: MonadSqlQuery m => m [String]+ myFunction = map personName <$> selectList [PersonAge >. 25] []++ let persons = [Person ...]+ result <- runMockSqlQueryT myFunction+   [ withRecord \@Person $ \\case+       SelectList _ _ -> Just persons+       _ -> Nothing+   , withRecord \@Post $ \\case+       Insert Post{ name = "post1" } -> Just $ toSqlKey 1+       _ -> Nothing+   , mockQuery $ \\case+       RawExecuteCount "DELETE FROM person WHERE name = \'Alice\'" [] -> Just 1+       _ -> Nothing+   ]+ @+-} runMockSqlQueryT :: MockSqlQueryT m a -> [MockQuery] -> m a runMockSqlQueryT action mockQueries = (`runReaderT` mockQueries) . unMockSqlQueryT $ action @@ -94,149 +101,158 @@    runQueryRep rep = do     mockQueries <- MockSqlQueryT ask-    maybe (error $ "Could not find mock for query: " ++ show rep) liftIO-      $ msum $ map tryMockQuery mockQueries+    maybe (error $ "Could not find mock for query: " ++ show rep) liftIO $+      msum $+        map tryMockQuery mockQueries     where       tryMockQuery (MockQuery f) = f rep    withTransaction = id --- | A mocked query to use in 'runMockSqlQueryT'.------ Use 'withRecord' or another helper to create a 'MockQuery'.+{-| A mocked query to use in 'runMockSqlQueryT'.++ Use 'withRecord' or another helper to create a 'MockQuery'.+-} data MockQuery = MockQuery (forall record a. Typeable record => SqlQueryRep record a -> Maybe (IO a)) --- | A helper for defining a mocked database query against a specific @record@--- type. Designed to be used with TypeApplications.------ Most 'SqlQueryRep' constructors are in the context of a specific @record@--- type, like @Person@. This helper only matches mocked database queries that--- are querying the record you specify.------ Some constructors reference multiple @record@ types, like--- 'Database.Persist.Monad.BelongsTo'. Look at the type to see the record you--- need to match against. For example,------ @--- withRecord \@(Person, Post) $ \\case---   BelongsTo _ _ -> ...--- @------ would match the function call------ @--- belongsTo :: (Person -> Maybe (Key Post)) -> Person -> SqlQueryRep (Person, Post) (Maybe Post)--- @+{-| A helper for defining a mocked database query against a specific @record@+ type. Designed to be used with TypeApplications.++ Most 'SqlQueryRep' constructors are in the context of a specific @record@+ type, like @Person@. This helper only matches mocked database queries that+ are querying the record you specify.++ Some constructors reference multiple @record@ types, like+ 'Database.Persist.Monad.BelongsTo'. Look at the type to see the record you+ need to match against. For example,++ @+ withRecord \@(Person, Post) $ \\case+   BelongsTo _ _ -> ...+ @++ would match the function call++ @+ belongsTo :: (Person -> Maybe (Key Post)) -> Person -> SqlQueryRep (Person, Post) (Maybe Post)+ @+-} withRecord :: forall record. Typeable record => (forall a. SqlQueryRep record a -> Maybe a) -> MockQuery withRecord f = MockQuery $ \(rep :: SqlQueryRep someRecord result) ->   case eqT @record @someRecord of     Just Refl -> pure <$> f rep     Nothing -> Nothing --- | A helper for defining a mocked database query.------ This does not do any matching on the @record@ type, so it is mostly useful--- for queries that don't use the @record@ type, like--- 'Database.Persist.Monad.Shim.rawExecute'.+{-| A helper for defining a mocked database query.++ This does not do any matching on the @record@ type, so it is mostly useful+ for queries that don't use the @record@ type, like+ 'Database.Persist.Monad.Shim.rawExecute'.+-} mockQuery :: (forall record a. Typeable record => SqlQueryRep record a -> Maybe a) -> MockQuery mockQuery f = MockQuery (fmap pure . f) --- | A helper for mocking a 'Database.Persist.Monad.Shim.selectSource' or--- 'Database.Persist.Monad.Shim.selectSourceRes' call.------ Usage:------ @--- mockSelectSource $ \\filters opts ->---   if null filters && null opts---     then---       let person1 = [Entity (toSqlKey 1) $ Person \"Alice\"]---           person2 = [Entity (toSqlKey 2) $ Person \"Bob\"]---       in Just [person1, person2]---     else Nothing--- @+{-| A helper for mocking a 'Database.Persist.Monad.Shim.selectSource' or+ 'Database.Persist.Monad.Shim.selectSourceRes' call.++ Usage:++ @+ mockSelectSource $ \\filters opts ->+   if null filters && null opts+     then+       let person1 = [Entity (toSqlKey 1) $ Person \"Alice\"]+           person2 = [Entity (toSqlKey 2) $ Person \"Bob\"]+       in Just [person1, person2]+     else Nothing+ @+-} mockSelectSource :: forall record. Typeable record => ([Filter record] -> [SelectOpt record] -> Maybe [Entity record]) -> MockQuery mockSelectSource f = withRecord @record $ \case   SelectSourceRes filters opts ->     let toAcquire entities = Acquire.mkAcquire (pure $ Conduit.yieldMany entities) (\_ -> pure ())-    in toAcquire <$> f filters opts+     in toAcquire <$> f filters opts   _ -> Nothing --- | A helper for mocking a 'Database.Persist.Monad.Shim.selectKeys' or--- 'Database.Persist.Monad.Shim.selectKeysRes' call.------ Usage:------ @--- mockSelectKeys $ \\filters opts ->---   if null filters && null opts---     then Just $ map toSqlKey [1, 2]---     else Nothing--- @+{-| A helper for mocking a 'Database.Persist.Monad.Shim.selectKeys' or+ 'Database.Persist.Monad.Shim.selectKeysRes' call.++ Usage:++ @+ mockSelectKeys $ \\filters opts ->+   if null filters && null opts+     then Just $ map toSqlKey [1, 2]+     else Nothing+ @+-} mockSelectKeys :: forall record. Typeable record => ([Filter record] -> [SelectOpt record] -> Maybe [Key record]) -> MockQuery mockSelectKeys f = withRecord @record $ \case   SelectKeysRes filters opts ->     let toAcquire keys = Acquire.mkAcquire (pure $ Conduit.yieldMany keys) (\_ -> pure ())-    in toAcquire <$> f filters opts+     in toAcquire <$> f filters opts   _ -> Nothing --- | A helper for mocking a 'Database.Persist.Monad.Shim.withRawQuery' call.------ Usage:------ @--- mockWithRawQuery $ \\sql vals ->---   if sql == "SELECT id, name FROM person"---     then---       let row1 = [toPersistValue 1, toPersistValue \"Alice\"]---           row2 = [toPersistValue 2, toPersistValue \"Bob\"]---       in Just [row1, row2]---     else Nothing--- @+{-| A helper for mocking a 'Database.Persist.Monad.Shim.withRawQuery' call.++ Usage:++ @+ mockWithRawQuery $ \\sql vals ->+   if sql == "SELECT id, name FROM person"+     then+       let row1 = [toPersistValue 1, toPersistValue \"Alice\"]+           row2 = [toPersistValue 2, toPersistValue \"Bob\"]+       in Just [row1, row2]+     else Nothing+ @+-} mockWithRawQuery :: (Text -> [PersistValue] -> Maybe [[PersistValue]]) -> MockQuery mockWithRawQuery f = MockQuery $ \case   WithRawQuery sql vals conduit ->     let outputRows rows = Conduit.runConduit $ Conduit.yieldMany rows .| conduit-    in outputRows <$> f sql vals+     in outputRows <$> f sql vals   _ -> Nothing --- | A helper for mocking a 'Database.Persist.Monad.Shim.rawQuery' or--- 'Database.Persist.Monad.Shim.rawQueryRes' call.------ Usage:------ @--- mockRawQuery $ \\sql vals ->---   if sql == "SELECT id, name FROM person"---     then---       let row1 = [toPersistValue 1, toPersistValue \"Alice\"]---           row2 = [toPersistValue 2, toPersistValue \"Bob\"]---       in Just [row1, row2]---     else Nothing--- @+{-| A helper for mocking a 'Database.Persist.Monad.Shim.rawQuery' or+ 'Database.Persist.Monad.Shim.rawQueryRes' call.++ Usage:++ @+ mockRawQuery $ \\sql vals ->+   if sql == "SELECT id, name FROM person"+     then+       let row1 = [toPersistValue 1, toPersistValue \"Alice\"]+           row2 = [toPersistValue 2, toPersistValue \"Bob\"]+       in Just [row1, row2]+     else Nothing+ @+-} mockRawQuery :: (Text -> [PersistValue] -> Maybe [[PersistValue]]) -> MockQuery mockRawQuery f = MockQuery $ \case   RawQueryRes sql vals ->     let toAcquire rows = Acquire.mkAcquire (pure $ Conduit.yieldMany rows) (\_ -> pure ())-    in pure . toAcquire <$> f sql vals+     in pure . toAcquire <$> f sql vals   _ -> Nothing --- | A helper for mocking a 'Database.Persist.Monad.Shim.rawSql' call.------ Usage:------ @--- mockRawSql $ \\sql vals ->---   if sql == "SELECT id, name FROM person"---     then---       let row1 = [toPersistValue 1, toPersistValue \"Alice\"]---           row2 = [toPersistValue 2, toPersistValue \"Bob\"]---       in Just [row1, row2]---     else Nothing--- @+{-| A helper for mocking a 'Database.Persist.Monad.Shim.rawSql' call.++ Usage:++ @+ mockRawSql $ \\sql vals ->+   if sql == "SELECT id, name FROM person"+     then+       let row1 = [toPersistValue 1, toPersistValue \"Alice\"]+           row2 = [toPersistValue 2, toPersistValue \"Bob\"]+       in Just [row1, row2]+     else Nothing+ @+-} mockRawSql :: (Text -> [PersistValue] -> Maybe [[PersistValue]]) -> MockQuery mockRawSql f = MockQuery $ \case   RawSql sql vals ->     let fromRow = either (error . Text.unpack) id . rawSqlProcessRow-    in pure . map fromRow <$> f sql vals+     in pure . map fromRow <$> f sql vals   _ -> Nothing
+ src/Database/Persist/Sql/Shim.hs view
@@ -0,0 +1,233 @@+{- THIS FILE IS AUTOGENERATED AND SHOULD NOT BE EDITED MANUALLY -}+{- FOURMOLU_DISABLE -}++{-|+Module: Database.Persist.Sql.Shim++Defines all the @persistent@ functions lifted into 'MonadSqlQuery', and+re-exports a version of the @Database.Persist.Sql@ module replacing each+function with the lifted version.++This file is autogenerated, to keep it in sync with+@Database.Persist.Monad.Shim@.+-}++{-# LANGUAGE CPP #-}++module Database.Persist.Sql.Shim (+  module Database.Persist.Sql,+  get,+  getMany,+  getJust,+  getJustEntity,+  getEntity,+  belongsTo,+  belongsToJust,+  insert,+  insert_,+  insertMany,+  insertMany_,+  insertEntityMany,+  insertKey,+  repsert,+  repsertMany,+  replace,+  delete,+  update,+  updateGet,+  insertEntity,+  insertRecord,+  getBy,+  getByValue,+  checkUnique,+  checkUniqueUpdateable,+  deleteBy,+  insertUnique,+  upsert,+  upsertBy,+  putMany,+  insertBy,+  insertUniqueEntity,+  replaceUnique,+  onlyUnique,+  selectSourceRes,+  selectFirst,+  selectKeysRes,+  count,+  exists,+  selectSource,+  selectKeys,+  selectList,+  selectKeysList,+  updateWhere,+  deleteWhere,+  deleteWhereCount,+  updateWhereCount,+  parseMigration,+  parseMigration',+  printMigration,+  showMigration,+  getMigration,+  runMigration,+  runMigrationQuiet,+  runMigrationSilent,+  runMigrationUnsafe,+  runMigrationUnsafeQuiet,+  getFieldName,+  getTableName,+  withRawQuery,+  rawQueryRes,+  rawQuery,+  rawExecute,+  rawExecuteCount,+  rawSql,+  transactionSave,+  transactionSaveWithIsolation,+  transactionUndo,+  transactionUndoWithIsolation,+  unsafeLiftSql,+  ) where++import Database.Persist.Monad.Shim (+    get,+    getMany,+    getJust,+    getJustEntity,+    getEntity,+    belongsTo,+    belongsToJust,+    insert,+    insert_,+    insertMany,+    insertMany_,+    insertEntityMany,+    insertKey,+    repsert,+    repsertMany,+    replace,+    delete,+    update,+    updateGet,+    insertEntity,+    insertRecord,+    getBy,+    getByValue,+    checkUnique,+    checkUniqueUpdateable,+    deleteBy,+    insertUnique,+    upsert,+    upsertBy,+    putMany,+    insertBy,+    insertUniqueEntity,+    replaceUnique,+    onlyUnique,+    selectSourceRes,+    selectFirst,+    selectKeysRes,+    count,+    exists,+    selectSource,+    selectKeys,+    selectList,+    selectKeysList,+    updateWhere,+    deleteWhere,+    deleteWhereCount,+    updateWhereCount,+    parseMigration,+    parseMigration',+    printMigration,+    showMigration,+    getMigration,+    runMigration,+    runMigrationQuiet,+    runMigrationSilent,+    runMigrationUnsafe,+    runMigrationUnsafeQuiet,+    getFieldName,+    getTableName,+    withRawQuery,+    rawQueryRes,+    rawQuery,+    rawExecute,+    rawExecuteCount,+    rawSql,+    transactionSave,+    transactionSaveWithIsolation,+    transactionUndo,+    transactionUndoWithIsolation,+    unsafeLiftSql+    )+import Database.Persist.Sql hiding (+    get,+    getMany,+    getJust,+    getJustEntity,+    getEntity,+    belongsTo,+    belongsToJust,+    insert,+    insert_,+    insertMany,+    insertMany_,+    insertEntityMany,+    insertKey,+    repsert,+    repsertMany,+    replace,+    delete,+    update,+    updateGet,+    insertEntity,+    insertRecord,+    getBy,+    getByValue,+    checkUnique,+    checkUniqueUpdateable,+    deleteBy,+    insertUnique,+    upsert,+    upsertBy,+    putMany,+    insertBy,+    insertUniqueEntity,+    replaceUnique,+    onlyUnique,+    selectSourceRes,+    selectFirst,+    selectKeysRes,+    count,+    exists,+    selectSource,+    selectKeys,+    selectList,+    selectKeysList,+    updateWhere,+    deleteWhere,+    deleteWhereCount,+    updateWhereCount,+    parseMigration,+    parseMigration',+    printMigration,+    showMigration,+    getMigration,+    runMigration,+    runMigrationQuiet,+    runMigrationSilent,+    runMigrationUnsafe,+    runMigrationUnsafeQuiet,+    getFieldName,+    getTableName,+    withRawQuery,+    rawQueryRes,+    rawQuery,+    rawExecute,+    rawExecuteCount,+    rawSql,+    transactionSave,+    transactionSaveWithIsolation,+    transactionUndo,+    transactionUndoWithIsolation,+    )
− test/Basic.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TypeApplications #-}--module Basic where--import Test.Tasty-import Test.Tasty.HUnit--import Database.Persist.Monad-import Database.Persist.Monad.TestUtils-import Example--tests :: TestTree-tests = testGroup "Basic functionality tests"-  [ testCase "Ensure withTransaction README example typechecks" $ do-      let foo :: MonadSqlQuery m => m ()-          foo = insert_ $ person "Alice"-          bar :: MonadSqlQuery m => m ()-          bar = insert_ $ person "Bob"-          fooAndBar :: MonadSqlQuery m => m ()-          fooAndBar = withTransaction $ foo >> bar-      runMockSqlQueryT fooAndBar-        [ withRecord @Person $ \case-            Insert_ _ -> Just ()-            _ -> Nothing-        , withRecord @Person $ \case-            Insert_ _ -> Just ()-            _ -> Nothing-        ]-  ]
test/Example.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleInstances #-}@@ -11,55 +10,60 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -Wno-unused-top-binds #-} {-# OPTIONS_GHC -Wno-missing-methods #-}+{-# OPTIONS_GHC -Wno-unused-top-binds #-} -module Example-  ( TestApp-  , runTestApp-  , runTestAppWith+module Example (+  TestApp,+  runTestApp,+  runTestAppWith, -    -- * Person-  , Person(..)-  , person-  , getPeople-  , getPeopleNames-  , getName-  , nameAndAge+  -- * Person+  Person (..),+  person,+  getPeople,+  getPeopleNames,+  getName,+  nameAndAge, -    -- * Post-  , Post(..)-  , post-  , getPosts-  , getPostTitles+  -- * Post+  Post (..),+  post,+  getPosts,+  getPostTitles, -    -- * Persistent-  , EntityField(..)-  , Unique(..)-  , migration-  ) where+  -- * Persistent+  EntityField (..),+  Unique (..),+  migration,+) where  import Control.Arrow ((&&&))-import Control.Monad.IO.Class (MonadIO(..))+import Control.Monad.IO.Class (MonadIO (..)) import Control.Monad.Trans.Resource (MonadResource, ResourceT, runResourceT)-import Database.Persist.Sql-    (Entity(..), EntityField, Key, SelectOpt(..), Unique, toSqlKey)-import Database.Persist.TH-    (mkMigrate, mkPersist, persistLowerCase, share, sqlSettings)-#if !MIN_VERSION_persistent(2,13,0)-import qualified Database.Persist.TH-#endif-import UnliftIO (MonadUnliftIO(..), wrappedWithRunInIO)+import Database.Persist.Sql (+  Entity (..),+  EntityField,+  Key,+  SelectOpt (..),+  Unique,+  toSqlKey,+ )+import Database.Persist.TH (+  mkMigrate,+  mkPersist,+  persistLowerCase,+  share,+  sqlSettings,+ )+import UnliftIO (MonadUnliftIO (..), wrappedWithRunInIO)  import Control.Monad.IO.Rerunnable (MonadRerunnableIO) import Database.Persist.Monad-import TestUtils.DB (BackendType(..), withTestDB)+import TestUtils.DB (BackendType (..), withTestDB)  share   [ mkPersist sqlSettings-#if !MIN_VERSION_persistent(2,13,0)-  , Database.Persist.TH.mkDeleteCascade sqlSettings-#endif   , mkMigrate "migration"   ]   [persistLowerCase|@@ -72,20 +76,13 @@  Post   title  String-#if MIN_VERSION_persistent(2,13,0)   author PersonId   editor PersonId Maybe-#else-  author PersonId       OnDeleteCascade-  editor PersonId Maybe OnDeleteCascade-#endif   deriving Show Eq |]  deriving instance Eq (Unique Person)-#if !MIN_VERSION_persistent_template(2,6,0) || MIN_VERSION_persistent_template(2,9,0) deriving instance Show (Unique Person)-#endif  -- Let tests use a literal number for keys instance Num (Key Person) where@@ -96,7 +93,8 @@  newtype TestApp a = TestApp   { unTestApp :: SqlQueryT (ResourceT IO) a-  } deriving+  }+  deriving     ( Functor     , Applicative     , Monad
test/Generated.hs view
@@ -1,4 +1,5 @@ {- THIS FILE IS AUTOGENERATED AND SHOULD NOT BE EDITED MANUALLY -}+{- FOURMOLU_DISABLE -}  {-# LANGUAGE CPP #-} {-# LANGUAGE GADTs #-}@@ -17,8 +18,6 @@ import Database.Persist.Monad.TestUtils (SqlQueryRep(..)) import Example -{-# ANN module "HLint: ignore" #-}- allSqlQueryRepShowRepresentations :: [String] allSqlQueryRepShowRepresentations =   [ show (Get undefined :: SqlQueryRep Person (Maybe Person))@@ -43,73 +42,39 @@   , show (InsertEntity undefined :: SqlQueryRep Person (Entity Person))   , show (InsertRecord undefined :: SqlQueryRep Person Person)   , show (GetBy undefined :: SqlQueryRep Person (Maybe (Entity Person)))-#if MIN_VERSION_persistent(2,10,0)   , show (GetByValue undefined :: SqlQueryRep Person (Maybe (Entity Person)))-#endif-#if !MIN_VERSION_persistent(2,10,0)-  , show (GetByValue undefined :: SqlQueryRep Person (Maybe (Entity Person)))-#endif   , show (CheckUnique undefined :: SqlQueryRep Person (Maybe (Unique Person)))-#if MIN_VERSION_persistent(2,11,0)   , show (CheckUniqueUpdateable undefined :: SqlQueryRep Person (Maybe (Unique Person)))-#endif   , show (DeleteBy undefined :: SqlQueryRep Person ())   , show (InsertUnique undefined :: SqlQueryRep Person (Maybe (Key Person)))-#if MIN_VERSION_persistent(2,10,0)   , show (Upsert undefined undefined :: SqlQueryRep Person (Entity Person))-#endif-#if !MIN_VERSION_persistent(2,10,0)-  , show (Upsert undefined undefined :: SqlQueryRep Person (Entity Person))-#endif   , show (UpsertBy undefined undefined undefined :: SqlQueryRep Person (Entity Person))   , show (PutMany undefined :: SqlQueryRep Person ())-#if MIN_VERSION_persistent(2,10,0)   , show (InsertBy undefined :: SqlQueryRep Person (Either (Entity Person) (Key Person)))-#endif-#if !MIN_VERSION_persistent(2,10,0)-  , show (InsertBy undefined :: SqlQueryRep Person (Either (Entity Person) (Key Person)))-#endif   , show (InsertUniqueEntity undefined :: SqlQueryRep Person (Maybe (Entity Person)))   , show (ReplaceUnique undefined undefined :: SqlQueryRep Person (Maybe (Unique Person)))-#if MIN_VERSION_persistent(2,10,0)   , show (OnlyUnique undefined :: SqlQueryRep Person (Unique Person))-#endif-#if !MIN_VERSION_persistent(2,10,0)-  , show (OnlyUnique undefined :: SqlQueryRep Person (Unique Person))-#endif   , show (SelectSourceRes undefined undefined :: SqlQueryRep Person (Acquire (ConduitM () (Entity Person) IO ())))   , show (SelectFirst undefined undefined :: SqlQueryRep Person (Maybe (Entity Person)))   , show (SelectKeysRes undefined undefined :: SqlQueryRep Person (Acquire (ConduitM () (Key Person) IO ())))   , show (Count undefined :: SqlQueryRep Person Int)-#if MIN_VERSION_persistent(2,11,0)   , show (Exists undefined :: SqlQueryRep Person Bool)-#endif   , show (SelectList undefined undefined :: SqlQueryRep Person [Entity Person])   , show (SelectKeysList undefined undefined :: SqlQueryRep Person [Key Person])   , show (UpdateWhere undefined undefined :: SqlQueryRep Person ())   , show (DeleteWhere undefined :: SqlQueryRep Person ())   , show (DeleteWhereCount undefined :: SqlQueryRep Person Int64)   , show (UpdateWhereCount undefined undefined :: SqlQueryRep Person Int64)-#if !MIN_VERSION_persistent(2,13,0)-  , show (DeleteCascade undefined :: SqlQueryRep Person ())-#endif-#if !MIN_VERSION_persistent(2,13,0)-  , show (DeleteCascadeWhere undefined :: SqlQueryRep Person ())-#endif   , show (ParseMigration undefined :: SqlQueryRep Void (Either [Text] CautiousMigration))   , show (ParseMigration' undefined :: SqlQueryRep Void CautiousMigration)   , show (PrintMigration undefined :: SqlQueryRep Void ())   , show (ShowMigration undefined :: SqlQueryRep Void [Text])   , show (GetMigration undefined :: SqlQueryRep Void [Sql])   , show (RunMigration undefined :: SqlQueryRep Void ())-#if MIN_VERSION_persistent(2,10,2)   , show (RunMigrationQuiet undefined :: SqlQueryRep Void [Text])-#endif   , show (RunMigrationSilent undefined :: SqlQueryRep Void [Text])   , show (RunMigrationUnsafe undefined :: SqlQueryRep Void ())-#if MIN_VERSION_persistent(2,10,2)   , show (RunMigrationUnsafeQuiet undefined :: SqlQueryRep Void [Text])-#endif   , show (GetFieldName undefined :: SqlQueryRep Person Text)   , show (GetTableName undefined :: SqlQueryRep Person Text)   , show (WithRawQuery undefined undefined undefined :: SqlQueryRep Void a)@@ -118,11 +83,7 @@   , show (RawExecuteCount undefined undefined :: SqlQueryRep Void Int64)   , show (RawSql undefined undefined :: SqlQueryRep Void [Entity Person])   , show (TransactionSave :: SqlQueryRep Void ())-#if MIN_VERSION_persistent(2,9,0)   , show (TransactionSaveWithIsolation undefined :: SqlQueryRep Void ())-#endif   , show (TransactionUndo :: SqlQueryRep Void ())-#if MIN_VERSION_persistent(2,9,0)   , show (TransactionUndoWithIsolation undefined :: SqlQueryRep Void ())-#endif   ]
− test/Integration.hs
@@ -1,898 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}--module Integration where--import Conduit (runConduit, (.|))-import qualified Conduit-import Control.Arrow ((&&&))-import qualified Data.Acquire as Acquire-import Data.Bifunctor (first)-import qualified Data.Map.Strict as Map-import Data.Text (Text)-import qualified Data.Text as Text-import Data.Typeable (Typeable)-#if MIN_VERSION_esqueleto(3,5,0)-import qualified Database.Esqueleto.Experimental as E-#else-import qualified Database.Esqueleto as E-#endif-import Database.Persist.Sql-    ( Entity(..)-    , Migration-    , PersistField-    , PersistRecordBackend-    , PersistValue-    , Single(..)-    , SqlBackend-    , fromPersistValue-    , (=.)-    , (==.)-    )-#if MIN_VERSION_persistent(2,9,0)-import Database.Persist.Sql (IsolationLevel(..))-#endif-import Test.Predicates (anything, elemsAre, eq, right)-import Test.Predicates.HUnit ((@?~))-import Test.Tasty-import Test.Tasty.HUnit-import UnliftIO (MonadIO, MonadUnliftIO, liftIO)-import UnliftIO.Exception-    ( Exception-    , SomeException-    , StringException(..)-    , fromException-    , throwIO-    , throwString-    , try-    )-import UnliftIO.IORef (atomicModifyIORef, newIORef)--import Control.Monad.IO.Rerunnable (MonadRerunnableIO, rerunnableIO)-import Database.Persist.Monad-import Example-import TestUtils.DB (BackendType(..), allBackendTypes)-import TestUtils.Esqueleto (esqueletoSelect)--tests :: TestTree-tests = testGroup "Integration tests" $-  map testsWithBackend allBackendTypes--testsWithBackend :: BackendType -> TestTree-testsWithBackend backendType = testGroup (show backendType)-  [ testWithTransaction backendType-  , testComposability backendType-  , testPersistentAPI backendType-  , testInterop backendType-  ]--testWithTransaction :: BackendType -> TestTree-testWithTransaction backendType = testGroup "withTransaction"-  [ testCase "it uses the same transaction" $ do-      -- without transactions, the INSERT shouldn't be rolled back-      runTestApp backendType $ do-        catchTestError $ insertAndFail $ person "Alice"-        result <- getPeopleNames-        liftIO $ result @?= ["Alice"]--      -- with transactions, the INSERT should be rolled back-      runTestApp backendType $ do-        catchTestError $ withTransaction $ insertAndFail $ person "Alice"-        result <- getPeopleNames-        liftIO $ result @?= []--  , testCase "retries transactions" $ do-      let retryIf e = case fromException e of-            Just (StringException "retry me" _) -> True-            _ -> False-          setRetry env = env { retryIf, retryLimit = 5 }--      counter <- newIORef (0 :: Int)--      result <- try @_ @SomeException $ runTestAppWith backendType setRetry $-        withTransaction $ rerunnableIO $ do-          x <- atomicModifyIORef counter $ \x -> (x + 1, x)-          if x > 2-            then return ()-            else throwString "retry me"--      case result of-        Right () -> return ()-        Left e -> error $ "Got unexpected error: " ++ show e--  , testCase "throws error when retry hits limit" $ do-      let setRetry env = env { retryIf = const True, retryLimit = 2 }--      result <- try @_ @TransactionError @() $ runTestAppWith backendType setRetry $-        withTransaction $ rerunnableIO $ throwString "retry me"--      result @?= Left RetryLimitExceeded-  ]---- this should compile-testComposability :: BackendType -> TestTree-testComposability backendType = testCase "Operations can be composed" $ do-  let onlySql :: MonadSqlQuery m => m ()-      onlySql = do-        _ <- getPeople-        return ()--      sqlAndRerunnableIO :: (MonadSqlQuery m, MonadRerunnableIO m) => m ()-      sqlAndRerunnableIO = do-        _ <- getPeopleNames-        _ <- rerunnableIO $ newIORef True-        return ()--      onlyRerunnableIO :: MonadRerunnableIO m => m ()-      onlyRerunnableIO = do-        _ <- rerunnableIO $ newIORef True-        return ()--      arbitraryIO :: MonadIO m => m ()-      arbitraryIO = do-        _ <- liftIO $ newIORef True-        return ()--  -- everything should compose naturally by default-  runTestApp backendType $ do-    onlySql-    sqlAndRerunnableIO-    onlyRerunnableIO-    arbitraryIO--  -- in a transaction, you can compose everything except arbitrary IO-  runTestApp backendType $ withTransaction $ do-    onlySql-    sqlAndRerunnableIO-    onlyRerunnableIO-    -- uncomment this to get compile error-    -- arbitraryIO--testPersistentAPI :: BackendType -> TestTree-testPersistentAPI backendType = testGroup "Persistent API"-  [ testCase "get" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        mapM get [1, 2]-      map (fmap personName) result @?= [Just "Alice", Nothing]--  , testCase "getMany" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        getMany [1]-      personName <$> Map.lookup 1 result @?= Just "Alice"--  , testCase "getJust" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        getJust 1-      personName result @?= "Alice"--  , testCase "getJustEntity" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        getJustEntity 1-      getName result @?= "Alice"--  , testCase "getEntity" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        mapM getEntity [1, 2]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "belongsTo" $ do-      result <- runTestApp backendType $ do-        aliceKey <- insert $ person "Alice"-        let post1 = Post "Post #1" aliceKey (Just aliceKey)-            post2 = Post "Post #2" aliceKey Nothing-        insertMany_ [post1, post2]-        mapM (belongsTo postEditor) [post1, post2]-      map (fmap personName) result @?= [Just "Alice", Nothing]--  , testCase "belongsToJust" $ do-      result <- runTestApp backendType $ do-        aliceKey <- insert $ person "Alice"-        let post1 = Post "Post #1" aliceKey Nothing-        insert_ post1-        belongsToJust postAuthor post1-      personName result @?= "Alice"--  , testCase "insert" $ do-      result <- runTestApp backendType $ do-        aliceKey <- insert $ person "Alice"-        people <- getPeopleNames-        return (aliceKey, people)-      result @?= (1, ["Alice"])--  , testCase "insert_" $ do-      result <- runTestApp backendType $ do-        result <- insert_ $ person "Alice"-        people <- getPeopleNames-        return (result, people)-      result @?= ((), ["Alice"])--  , testCase "insertMany" $ do-      result <- runTestApp backendType $ do-        keys <- insertMany [person "Alice", person "Bob"]-        people <- getPeopleNames-        return (keys, people)-      result @?= ([1, 2], ["Alice", "Bob"])--  , testCase "insertMany_" $ do-      result <- runTestApp backendType $ do-        result <- insertMany_ [person "Alice", person "Bob"]-        people <- getPeopleNames-        return (result, people)-      result @?= ((), ["Alice", "Bob"])--  , testCase "insertEntityMany" $ do-      result <- runTestApp backendType $ do-        result <- insertEntityMany-          [ Entity 1 $ person "Alice"-          , Entity 2 $ person "Bob"-          ]-        people <- getPeopleNames-        return (result, people)-      result @?= ((), ["Alice", "Bob"])--  , testCase "insertKey" $ do-      result <- runTestApp backendType $ do-        result <- insertKey 1 $ person "Alice"-        people <- getPeopleNames-        return (result, people)-      result @?= ((), ["Alice"])--  , testCase "repsert" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"-        insert_ alice-        repsert 1 $ alice { personAge = 100 }-        repsert 2 $ person "Bob"-        getPeople-      map nameAndAge result @?=-        [ ("Alice", 100)-        , ("Bob", 0)-        ]--  , testCase "repsertMany" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"--- https://github.com/yesodweb/persistent/issues/832-#if MIN_VERSION_persistent(2,9,0)-        insert_ alice-        repsertMany-          [ (1, alice { personAge = 100 })-          , (2, person "Bob")-          ]-#else-        repsertMany [(1, alice { personAge = 100 })]-        repsertMany [(2, person "Bob")]-#endif-        getPeople-      map nameAndAge result @?=-        [ ("Alice", 100)-        , ("Bob", 0)-        ]--  , testCase "replace" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"-        insert_ alice-        replace 1 $ alice { personAge = 100 }-        getJust 1-      personAge result @?= 100--  , testCase "delete" $ do-      result <- runTestApp backendType $ do-        aliceKey <- insert $ person "Alice"-        delete aliceKey-        getPeople-      result @?= []--  , testCase "update" $ do-      result <- runTestApp backendType $ do-        key <- insert $ person "Alice"-        update key [PersonName =. "Alicia"]-        getPeopleNames-      result @?= ["Alicia"]--  , testCase "updateGet" $ do-      (updateResult, getResult) <- runTestApp backendType $ do-        key <- insert $ person "Alice"-        updateResult <- updateGet key [PersonName =. "Alicia"]-        getResult <- getJust key-        return (updateResult, getResult)-      updateResult @?= getResult--  , testCase "insertEntity" $ do-      (insertResult, getResult) <- runTestApp backendType $ do-        insertResult <- insertEntity $ person "Alice"-        getResult <- getJust $ entityKey insertResult-        return (insertResult, getResult)-      entityVal insertResult @?= getResult--  , testCase "insertRecord" $ do-      (insertResult, getResult) <- runTestApp backendType $ do-        insertResult <- insertRecord $ person "Alice"-        getResult <- getJust 1-        return (insertResult, getResult)-      insertResult @?= getResult--  , testCase "getBy" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        mapM getBy [UniqueName "Alice", UniqueName "Bob"]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "getByValue" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"-        insert_ alice-        mapM getByValue [alice, person "Bob"]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "checkUnique" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"-        insert_ alice-        mapM checkUnique-          [ alice-          , person "Bob"-          , (person "Alice"){ personAge = 100 }-          ]-      result @?= [Just (UniqueName "Alice"), Nothing, Just (UniqueName "Alice")]--#if MIN_VERSION_persistent(2,11,0)-  , testCase "checkUniqueUpdateable" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"-        insert_ alice-        mapM checkUniqueUpdateable-          [ Entity 1 alice-          , Entity 2 $ person "Bob"-          , Entity 3 $ (person "Alice"){ personAge = 100 }-          ]-      result @?= [Nothing, Nothing, Just (UniqueName "Alice")]-#endif--  , testCase "deleteBy" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        deleteBy $ UniqueName "Alice"-        getPeople-      result @?= []--  , testCase "insertUnique" $ do-      (result1, result2, people) <- runTestApp backendType $ do-        result1 <- insertUnique $ person "Alice"-        result2 <- insertUnique $ person "Alice"-        people <- getPeopleNames-        return (result1, result2, people)-      result1 @?= Just 1-      result2 @?= Nothing-      people @?= ["Alice"]--  , testCase "upsert" $ do-      (result1, result2, people) <- runTestApp backendType $ do-        result1 <- upsert (person "Alice") [PersonAge =. 0]-        result2 <- upsert (person "Alice") [PersonAge =. 100]-        people <- getPeople-        return (result1, result2, people)-      entityKey result1 @?= entityKey result2-      nameAndAge (entityVal result1) @?= ("Alice", 0)-      nameAndAge (entityVal result2) @?= ("Alice", 100)-      map nameAndAge people @?= [("Alice", 100)]--  , testCase "upsertBy" $ do-      (result1, result2, people) <- runTestApp backendType $ do-        result1 <- upsertBy (UniqueName "Alice") (person "Alice") [PersonAge =. 0]-        result2 <- upsertBy (UniqueName "Alice") (person "Alice") [PersonAge =. 100]-        people <- getPeople-        return (result1, result2, people)-      entityKey result1 @?= entityKey result2-      nameAndAge (entityVal result1) @?= ("Alice", 0)-      nameAndAge (entityVal result2) @?= ("Alice", 100)-      map nameAndAge people @?= [("Alice", 100)]--  , testCase "putMany" $ do-      result <- runTestApp backendType $ do-        let alice = person "Alice"-        insert_ alice-        putMany-          [ alice { personAge = 100 }-          , person "Bob"-          ]-        getPeople-      map nameAndAge result @?=-        [ ("Alice", 100)-        , ("Bob", 0)-        ]--  , testCase "insertBy" $ do-      (result1, result2, people) <- runTestApp backendType $ do-        let alice = person "Alice"-        result1 <- insertBy alice-        result2 <- insertBy $ alice { personAge = 100 }-        people <- getPeople-        return (result1, result2, people)-      result1 @?= Right 1-      first (entityKey &&& getName) result2 @?= Left (1, "Alice")-      map nameAndAge people @?= [("Alice", 0)]--  , testCase "insertUniqueEntity" $ do-      (result1, result2, people) <- runTestApp backendType $ do-        let alice = person "Alice"-        result1 <- insertUniqueEntity alice-        result2 <- insertUniqueEntity $ alice { personAge = 100 }-        people <- getPeople-        return (result1, result2, people)-      (entityKey &&& getName) <$> result1 @?= Just (1, "Alice")-      result2 @?= Nothing-      map nameAndAge people @?= [("Alice", 0)]--  , testCase "replaceUnique" $ do-      (result1, result2, people) <- runTestApp backendType $ do-        let alice = person "Alice"-            bob = person "Bob"-        insertMany_ [alice, bob]-        result1 <- replaceUnique 1 $ alice { personName = "Bob" }-        result2 <- replaceUnique 2 $ bob { personAge = 100 }-        people <- getPeople-        return (result1, result2, people)-      result1 @?= Just (UniqueName "Bob")-      result2 @?= Nothing-      map nameAndAge people @?= [("Alice", 0), ("Bob", 100)]--  , testCase "onlyUnique" $ do-      result <- runTestApp backendType $ onlyUnique $ person "Alice"-      result @?= UniqueName "Alice"--  , testCase "selectSourceRes" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        acquire <- selectSourceRes [] []-        Acquire.with acquire $ \conduit ->-          runConduit $ conduit .| Conduit.mapC getName .| Conduit.sinkList-      result @?= ["Alice", "Bob"]--  , testCase "selectFirst" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        sequence-          [ selectFirst [PersonName ==. "Alice"] []-          , selectFirst [PersonName ==. "Bob"] []-          ]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "selectKeysRes" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        acquire <- selectKeysRes @_ @Person [] []-        Acquire.with acquire $ \conduit ->-          runConduit $ conduit .| Conduit.sinkList-      result @?= [1, 2]--  , testCase "count" $ do-      result <- runTestApp backendType $ do-        insertMany_ $ map (\p -> p{personAge = 100}) [person "Alice", person "Bob"]-        count [PersonAge ==. 100]-      result @?= 2--#if MIN_VERSION_persistent(2,11,0)-  , testCase "exists" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        exists [PersonName ==. "Alice"]-      result @?= True-#endif--  , testCase "selectSource" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        runConduit $ selectSource [] [] .| Conduit.mapC getName .| Conduit.sinkList-      result @?= ["Alice", "Bob"]--  , testCase "selectKeys" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        runConduit $ selectKeys @Person [] [] .| Conduit.sinkList-      result @?= [1, 2]--  , testCase "selectList" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        insert_ $ person "Bob"-        selectList [] []-      map getName result @?= ["Alice", "Bob"]--  , testCase "selectKeysList" $ do-      result <- runTestApp backendType $ do-        insert_ $ person "Alice"-        insert_ $ person "Bob"-        selectKeysList @Person [] []-      result @?= [1, 2]--  , testCase "updateWhere" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        updateWhere [PersonName ==. "Alice"] [PersonAge =. 100]-        getPeople-      map nameAndAge result @?= [("Alice", 100), ("Bob", 0)]--  , testCase "deleteWhere" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        deleteWhere [PersonName ==. "Alice"]-        getPeopleNames-      result @?= ["Bob"]--  , testCase "updateWhereCount" $ do-      (rowsUpdated, people) <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        rowsUpdated <- updateWhereCount [PersonName ==. "Alice"] [PersonAge =. 100]-        people <- getPeople-        return (rowsUpdated, people)-      rowsUpdated @?= 1-      map nameAndAge people @?= [("Alice", 100), ("Bob", 0)]--  , testCase "deleteWhereCount" $ do-      (rowsDeleted, names) <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        rowsDeleted <- deleteWhereCount [PersonName ==. "Alice"]-        names <- getPeopleNames-        return (rowsDeleted, names)-      rowsDeleted @?= 1-      names @?= ["Bob"]--#if !MIN_VERSION_persistent(2,13,0)-  , testCase "deleteCascade" $ do-      (people, posts) <- runTestApp backendType $ do-        aliceKey <- insert $ person "Alice"-        bobKey <- insert $ person "Bob"-        insertMany_-          [ post "Post #1" aliceKey-          , post "Post #2" bobKey-          ]-        deleteCascade aliceKey-        people <- getPeopleNames-        posts <- getPostTitles-        return (people, posts)-      people @?= ["Bob"]-      posts @?= ["Post #2"]--  , testCase "deleteCascadeWhere" $ do-      (people, posts) <- runTestApp backendType $ do-        aliceKey <- insert $ person "Alice"-        bobKey <- insert $ person "Bob"-        insertMany_-          [ post "Post #1" aliceKey-          , post "Post #2" bobKey-          ]-        deleteCascadeWhere [PersonName ==. "Alice"]-        people <- getPeopleNames-        posts <- getPostTitles-        return (people, posts)-      people @?= ["Bob"]-      posts @?= ["Post #2"]-#endif--  , testCase "parseMigration" $ do-      result <- runTestApp backendType $ do-        setupUnsafeMigration-        parseMigration migration--      let sql = case backendType of-            Sqlite ->-              [ eq-                  ( False-                  , Text.concat-                      [ "CREATE TEMP TABLE \"person_backup\"("-                      , "\"id\" INTEGER PRIMARY KEY,"-                      , "\"name\" VARCHAR NOT NULL,"-                      , "\"age\" INTEGER NOT NULL,"-                      , "CONSTRAINT \"unique_name\" UNIQUE (\"name\"))"-                      ]-                  )-              , anything-              , eq (True, "DROP TABLE \"person\"")-              , anything-              , anything-              , eq (False, "DROP TABLE \"person_backup\"")-              ]-            Postgresql ->-              [ eq (True, "ALTER TABLE \"person\" DROP COLUMN \"foo\"")-              ]--      result @?~ right (elemsAre sql)--  , testCase "parseMigration'" $ do-      let action :: (Migration -> TestApp a) -> IO a-          action f = runTestApp backendType $ do-            setupUnsafeMigration-            f migration--      result <- action parseMigration-      result' <- action parseMigration'-      Right result' @?= result--  , testCase "printMigration" $-      runTestApp backendType $ do-        setupUnsafeMigration-        printMigration migration--  , testCase "showMigration" $ do-      result <- runTestApp backendType $ do-        setupUnsafeMigration-        showMigration migration--      let sql = case backendType of-            Sqlite ->-              [ eq $ Text.concat-                  [ "CREATE TEMP TABLE \"person_backup\"("-                  , "\"id\" INTEGER PRIMARY KEY,"-                  , "\"name\" VARCHAR NOT NULL,"-                  , "\"age\" INTEGER NOT NULL,"-                  , "CONSTRAINT \"unique_name\" UNIQUE (\"name\"));"-                  ]-              , anything-              , eq "DROP TABLE \"person\";"-              , anything-              , anything-              , eq "DROP TABLE \"person_backup\";"-              ]-            Postgresql ->-              [ eq "ALTER TABLE \"person\" DROP COLUMN \"foo\";"-              ]--      result @?~ elemsAre sql--  , testCase "getMigration" $ do-      result <- runTestApp backendType $ do-        setupUnsafeMigration-        getMigration migration--      let sql = case backendType of-            Sqlite ->-              [ eq $ Text.concat-                  [ "CREATE TEMP TABLE \"person_backup\"("-                  , "\"id\" INTEGER PRIMARY KEY,"-                  , "\"name\" VARCHAR NOT NULL,"-                  , "\"age\" INTEGER NOT NULL,"-                  , "CONSTRAINT \"unique_name\" UNIQUE (\"name\"))"-                  ]-              , anything-              , eq "DROP TABLE \"person\""-              , anything-              , anything-              , eq "DROP TABLE \"person_backup\""-              ]-            Postgresql ->-              [ eq "ALTER TABLE \"person\" DROP COLUMN \"foo\""-              ]--      result @?~ elemsAre sql--  , testCase "runMigration" $ do-      result <- runTestApp backendType $ do-        setupSafeMigration-        runMigration migration-        getSchemaColumnNames backendType "person"-      assertNotIn "removed_column" result--#if MIN_VERSION_persistent(2,10,2)-  , testCase "runMigrationQuiet" $ do-      (withQuiet, cols) <- runTestApp backendType $ do-        setupSafeMigration-        sql <- runMigrationQuiet migration-        cols <- getSchemaColumnNames backendType "person"-        return (sql, cols)-      withSilent <- runTestApp backendType $ do-        setupSafeMigration-        runMigrationSilent migration-      assertNotIn "removed_column" cols-      withQuiet @?= withSilent-#endif--  , testCase "runMigrationSilent" $ do-      (sqlPlanned, sqlExecuted, cols) <- runTestApp backendType $ do-        setupSafeMigration-        sqlPlanned <- getMigration migration-        sqlExecuted <- runMigrationSilent migration-        cols <- getSchemaColumnNames backendType "person"-        return (sqlPlanned, sqlExecuted, cols)-      assertNotIn "removed_column" cols-      sqlExecuted @?= sqlPlanned--  , testCase "runMigrationUnsafe" $ do-      result <- runTestApp backendType $ do-        setupUnsafeMigration-        runMigrationUnsafe migration-        getSchemaColumnNames backendType "person"-      assertNotIn "removed_column" result--#if MIN_VERSION_persistent(2,10,2)-  , testCase "runMigrationUnsafeQuiet" $ do-      (sqlPlanned, sqlExecuted, cols) <- runTestApp backendType $ do-        setupUnsafeMigration-        sqlPlanned <- getMigration migration-        sqlExecuted <- runMigrationUnsafeQuiet migration-        cols <- getSchemaColumnNames backendType "person"-        return (sqlPlanned, sqlExecuted, cols)-      assertNotIn "removed_column" cols-      sqlExecuted @?= sqlPlanned-#endif--  , testCase "getFieldName" $ do-      result <- runTestApp backendType $-        getFieldName PersonName-      result @?= "\"name\""--  , testCase "getTableName" $ do-      result <- runTestApp backendType $-        getTableName $ person "Alice"-      result @?= "\"person\""--  , testCase "withRawQuery" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        withRawQuery "SELECT name FROM person" [] $-          Conduit.mapC (fromPersistValue' @Text . head) .| Conduit.sinkList--      result @?= ["Alice", "Bob"]--  , testCase "rawQueryRes" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        acquire <- rawQueryRes "SELECT name FROM person" []-        Acquire.with acquire $ \conduit ->-          runConduit $ conduit .| Conduit.mapC (fromPersistValue' @Text . head) .| Conduit.sinkList-      result @?= ["Alice", "Bob"]--  , testCase "rawQuery" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        runConduit $ rawQuery "SELECT name FROM person" [] .| Conduit.mapC (fromPersistValue' @Text . head) .| Conduit.sinkList-      result @?= ["Alice", "Bob"]--  , testCase "rawExecute" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        rawExecute "UPDATE person SET age = 100 WHERE name = 'Alice'" []-        getPeople-      map nameAndAge result @?= [("Alice", 100), ("Bob", 0)]--  , testCase "rawExecuteCount" $ do-      (rowsUpdated, people) <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        rowsUpdated <- rawExecuteCount "UPDATE person SET age = 100 WHERE name = 'Alice'" []-        people <- getPeople-        return (rowsUpdated, people)-      rowsUpdated @?= 1-      map nameAndAge people @?= [("Alice", 100), ("Bob", 0)]--  , testCase "rawSql" $ do-      result <- runTestApp backendType $ do-        insertMany_ [person "Alice", person "Bob"]-        rawSql @(Single String) "SELECT name FROM person" []-      map unSingle result @?= ["Alice", "Bob"]--  , testCase "transactionSave" $ do-      result1 <- runTestApp backendType $ do-        catchTestError $ withTransaction $ do-          insert_ $ person "Alice"-          insertAndFail $ person "Bob"-        getPeopleNames-      result1 @?= []--      result2 <- runTestApp backendType $ do-        catchTestError $ withTransaction $ do-          insert_ $ person "Alice"-          transactionSave-          insertAndFail $ person "Bob"-        getPeopleNames-      result2 @?= ["Alice"]--#if MIN_VERSION_persistent(2,9,0)-  , testCase "transactionSaveWithIsolation" $ do-      result1 <- runTestApp backendType $ do-        catchTestError $ withTransaction $ do-          insert_ $ person "Alice"-          insertAndFail $ person "Bob"-        getPeopleNames-      result1 @?= []--      result2 <- runTestApp backendType $ do-        catchTestError $ withTransaction $ do-          insert_ $ person "Alice"-          transactionSaveWithIsolation Serializable-          insertAndFail $ person "Bob"-        getPeopleNames-      result2 @?= ["Alice"]-#endif--  , testCase "transactionUndo" $ do-      result <- runTestApp backendType $ withTransaction $ do-        insert_ $ person "Alice"-        transactionUndo-        getPeopleNames-      result @?= []--#if MIN_VERSION_persistent(2,9,0)-  , testCase "transactionUndoWithIsolation" $ do-      result <- runTestApp backendType $ withTransaction $ do-        insert_ $ person "Alice"-        transactionUndoWithIsolation Serializable-        getPeopleNames-      result @?= []-#endif-  ]--testInterop :: BackendType -> TestTree-testInterop backendType = testGroup "Interop with third-party Persistent libraries"-  [ testCase "unsafeLiftSql" $ do-      let alice = person "Alice"-      result <- runTestApp backendType $ do-        insert_ alice-        esqueletoSelect $-#if MIN_VERSION_esqueleto(3,5,0)-          E.from $ E.table @Person-#else-          E.from $ \p -> return p-#endif-      result @?= [Entity 1 alice]-  ]--{- Persistent helpers -}--fromPersistValue' :: PersistField a => PersistValue -> a-fromPersistValue' = either (error . Text.unpack) id . fromPersistValue--{- Meta SQL helpers -}---- | Put the database in a state where running a migration is safe.-setupSafeMigration :: MonadSqlQuery m => m ()-setupSafeMigration = rawExecute "ALTER TABLE person ADD COLUMN removed_column VARCHAR" []---- | Put the database in a state where running a migration is unsafe.-setupUnsafeMigration :: MonadSqlQuery m => m ()-setupUnsafeMigration = rawExecute "ALTER TABLE person ADD COLUMN foo VARCHAR" []---- | Get the names of all columns in the given table.-getSchemaColumnNames :: MonadSqlQuery m => BackendType -> String -> m [String]-getSchemaColumnNames backendType tableName = map unSingle <$> rawSql sql []-  where-    sql = Text.pack $ case backendType of-      Sqlite -> "SELECT name FROM pragma_table_info('" ++ tableName ++ "')"-      Postgresql -> unlines-        [ "SELECT column_name FROM information_schema.columns"-        , "WHERE table_schema = 'public' AND table_name = '" ++ tableName ++ "'"-        ]--{- Test helpers -}--data TestError = TestError-  deriving (Show, Eq)--instance Exception TestError--catchTestError :: (MonadUnliftIO m, Eq a, Show a) => m a -> m ()-catchTestError m = do-  result <- try m-  liftIO $ result @?= Left TestError--insertAndFail ::-  ( MonadRerunnableIO m-  , MonadSqlQuery m-  , PersistRecordBackend record SqlBackend-  , Typeable record-  )-  => record -> m ()-insertAndFail record = do-  insert_ record-  rerunnableIO $ throwIO TestError--assertNotIn :: (Eq a, Show a) => a -> [a] -> Assertion-assertNotIn a as = as @?= filter (/= a) as
+ test/IntegrationTest.hs view
@@ -0,0 +1,846 @@+{- AUTOCOLLECT.TEST -}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module IntegrationTest (+  -- $AUTOCOLLECT.TEST.export$+) where++import Conduit (runConduit, (.|))+import qualified Conduit+import Control.Arrow ((&&&))+import qualified Data.Acquire as Acquire+import Data.Bifunctor (first)+import qualified Data.Map.Strict as Map+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Typeable (Typeable)+import qualified Database.Esqueleto.Experimental as E+import Database.Persist.Sql (+  Entity (..),+  IsolationLevel (..),+  Migration,+  PersistField,+  PersistRecordBackend,+  PersistValue,+  Single (..),+  SqlBackend,+  fromPersistValue,+  (=.),+  (==.),+ )+import Test.Predicates (anything, elemsAre, eq, right)+import Test.Predicates.HUnit ((@?~))+import Test.Tasty+import Test.Tasty.HUnit+import UnliftIO (MonadIO, MonadUnliftIO, liftIO)+import UnliftIO.Exception (+  Exception,+  SomeException,+  StringException (..),+  fromException,+  throwIO,+  throwString,+  try,+ )+import UnliftIO.IORef (atomicModifyIORef, newIORef, readIORef, writeIORef)++import Control.Monad.IO.Rerunnable (MonadRerunnableIO, rerunnableIO)+import Database.Persist.Monad+import Database.Persist.Monad.Internal.PersistentShim (SafeToInsert)+import Example+import TestUtils.DB (BackendType (..), allBackendTypes)+import TestUtils.Esqueleto (esqueletoSelect)++test_batch =+  [ testGroup+    (show backendType)+    [ testWithTransaction backendType+    , testCatchTransaction backendType+    , testComposability backendType+    , testPersistentAPI backendType+    , testInterop backendType+    ]+  | backendType <- allBackendTypes+  ]++testWithTransaction :: BackendType -> TestTree+testWithTransaction backendType =+  testGroup+    "withTransaction"+    [ testCase "it uses the same transaction" $ do+        -- without transactions, the INSERT shouldn't be rolled back+        runTestApp backendType $ do+          catchTestError $ insertAndFail $ person "Alice"+          result <- getPeopleNames+          liftIO $ result @?= ["Alice"]++        -- with transactions, the INSERT should be rolled back+        runTestApp backendType $ do+          catchTestError $ withTransaction $ insertAndFail $ person "Alice"+          result <- getPeopleNames+          liftIO $ result @?= []+    , testCase "retries transactions" $ do+        let retryIf e = case fromException e of+              Just (StringException "retry me" _) -> True+              _ -> False+            setRetry env = env{retryIf, retryLimit = 5}++        counter <- newIORef (0 :: Int)++        result <- try @_ @SomeException $+          runTestAppWith backendType setRetry $+            withTransaction $+              rerunnableIO $ do+                x <- atomicModifyIORef counter $ \x -> (x + 1, x)+                if x > 2+                  then return ()+                  else throwString "retry me"++        case result of+          Right () -> return ()+          Left e -> error $ "Got unexpected error: " ++ show e+    , testCase "throws error when retry hits limit" $ do+        let setRetry env = env{retryIf = const True, retryLimit = 2}++        result <-+          try @_ @TransactionError @() $+            runTestAppWith backendType setRetry $+              withTransaction $+                rerunnableIO $+                  throwString "retry me"++        result @?= Left RetryLimitExceeded+    , testCase "Runs retryCallback" $ do+        callbackRef <- newIORef Nothing++        let setRetry env =+              env+                { retryIf = const True+                , retryLimit = 2+                , retryCallback = writeIORef callbackRef . Just+                }+        _ <-+          try @_ @TransactionError @() $+            runTestAppWith backendType setRetry . withTransaction $+              rerunnableIO (throwIO TestError)++        mError <- readIORef callbackRef+        case mError >>= fromException of+          Just TestError -> return ()+          _ -> assertFailure $ "Unexpected result: " ++ show mError+    ]++testCatchTransaction :: BackendType -> TestTree+testCatchTransaction backendType =+  testGroup+    "catchSqlTransaction"+    [ testCase "catches errors" $ do+        wasCaughtRef <- newIORef False+        runTestApp backendType . withTransaction $+          (`catchSqlTransaction` markCaught wasCaughtRef) $+            rerunnableIO (throwString "error")+        wasCaught <- readIORef wasCaughtRef+        wasCaught @?= True+    , testCase "does not catch retry errors" $ do+        let retryIf e = case fromException e of+              Just (StringException "retry me" _) -> True+              _ -> False+            setRetry env = env{retryIf, retryLimit = 2}++        wasCaughtRef <- newIORef False+        _ <-+          try @_ @SomeException $+            runTestAppWith backendType setRetry . withTransaction $+              (`catchSqlTransaction` markCaught wasCaughtRef) $+                rerunnableIO (throwString "retry me")+        wasCaught <- readIORef wasCaughtRef+        wasCaught @?= False+    ]+  where+    markCaught wasCaughtRef (_ :: SomeException) =+      rerunnableIO $ writeIORef wasCaughtRef True++-- this should compile+testComposability :: BackendType -> TestTree+testComposability backendType = testCase "Operations can be composed" $ do+  let onlySql :: MonadSqlQuery m => m ()+      onlySql = do+        _ <- getPeople+        return ()++      sqlAndRerunnableIO :: (MonadSqlQuery m, MonadRerunnableIO m) => m ()+      sqlAndRerunnableIO = do+        _ <- getPeopleNames+        _ <- rerunnableIO $ newIORef True+        return ()++      onlyRerunnableIO :: MonadRerunnableIO m => m ()+      onlyRerunnableIO = do+        _ <- rerunnableIO $ newIORef True+        return ()++      arbitraryIO :: MonadIO m => m ()+      arbitraryIO = do+        _ <- liftIO $ newIORef True+        return ()++  -- everything should compose naturally by default+  runTestApp backendType $ do+    onlySql+    sqlAndRerunnableIO+    onlyRerunnableIO+    arbitraryIO++  -- in a transaction, you can compose everything except arbitrary IO+  runTestApp backendType $ withTransaction $ do+    onlySql+    sqlAndRerunnableIO+    onlyRerunnableIO++-- uncomment this to get compile error+-- arbitraryIO++testPersistentAPI :: BackendType -> TestTree+testPersistentAPI backendType =+  testGroup+    "Persistent API"+    [ testCase "get" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          mapM get [1, 2]+        map (fmap personName) result @?= [Just "Alice", Nothing]+    , testCase "getMany" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          getMany [1]+        personName <$> Map.lookup 1 result @?= Just "Alice"+    , testCase "getJust" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          getJust 1+        personName result @?= "Alice"+    , testCase "getJustEntity" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          getJustEntity 1+        getName result @?= "Alice"+    , testCase "getEntity" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          mapM getEntity [1, 2]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "belongsTo" $ do+        result <- runTestApp backendType $ do+          aliceKey <- insert $ person "Alice"+          let post1 = Post "Post #1" aliceKey (Just aliceKey)+              post2 = Post "Post #2" aliceKey Nothing+          insertMany_ [post1, post2]+          mapM (belongsTo postEditor) [post1, post2]+        map (fmap personName) result @?= [Just "Alice", Nothing]+    , testCase "belongsToJust" $ do+        result <- runTestApp backendType $ do+          aliceKey <- insert $ person "Alice"+          let post1 = Post "Post #1" aliceKey Nothing+          insert_ post1+          belongsToJust postAuthor post1+        personName result @?= "Alice"+    , testCase "insert" $ do+        result <- runTestApp backendType $ do+          aliceKey <- insert $ person "Alice"+          people <- getPeopleNames+          return (aliceKey, people)+        result @?= (1, ["Alice"])+    , testCase "insert_" $ do+        result <- runTestApp backendType $ do+          result <- insert_ $ person "Alice"+          people <- getPeopleNames+          return (result, people)+        result @?= ((), ["Alice"])+    , testCase "insertMany" $ do+        result <- runTestApp backendType $ do+          keys <- insertMany [person "Alice", person "Bob"]+          people <- getPeopleNames+          return (keys, people)+        result @?= ([1, 2], ["Alice", "Bob"])+    , testCase "insertMany_" $ do+        result <- runTestApp backendType $ do+          result <- insertMany_ [person "Alice", person "Bob"]+          people <- getPeopleNames+          return (result, people)+        result @?= ((), ["Alice", "Bob"])+    , testCase "insertEntityMany" $ do+        result <- runTestApp backendType $ do+          result <-+            insertEntityMany+              [ Entity 1 $ person "Alice"+              , Entity 2 $ person "Bob"+              ]+          people <- getPeopleNames+          return (result, people)+        result @?= ((), ["Alice", "Bob"])+    , testCase "insertKey" $ do+        result <- runTestApp backendType $ do+          result <- insertKey 1 $ person "Alice"+          people <- getPeopleNames+          return (result, people)+        result @?= ((), ["Alice"])+    , testCase "repsert" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          insert_ alice+          repsert 1 $ alice{personAge = 100}+          repsert 2 $ person "Bob"+          getPeople+        map nameAndAge result+          @?= [ ("Alice", 100)+              , ("Bob", 0)+              ]+    , testCase "repsertMany" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          -- https://github.com/yesodweb/persistent/issues/832+          insert_ alice+          repsertMany+            [ (1, alice{personAge = 100})+            , (2, person "Bob")+            ]+          getPeople+        map nameAndAge result+          @?= [ ("Alice", 100)+              , ("Bob", 0)+              ]+    , testCase "replace" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          insert_ alice+          replace 1 $ alice{personAge = 100}+          getJust 1+        personAge result @?= 100+    , testCase "delete" $ do+        result <- runTestApp backendType $ do+          aliceKey <- insert $ person "Alice"+          delete aliceKey+          getPeople+        result @?= []+    , testCase "update" $ do+        result <- runTestApp backendType $ do+          key <- insert $ person "Alice"+          update key [PersonName =. "Alicia"]+          getPeopleNames+        result @?= ["Alicia"]+    , testCase "updateGet" $ do+        (updateResult, getResult) <- runTestApp backendType $ do+          key <- insert $ person "Alice"+          updateResult <- updateGet key [PersonName =. "Alicia"]+          getResult <- getJust key+          return (updateResult, getResult)+        updateResult @?= getResult+    , testCase "insertEntity" $ do+        (insertResult, getResult) <- runTestApp backendType $ do+          insertResult <- insertEntity $ person "Alice"+          getResult <- getJust $ entityKey insertResult+          return (insertResult, getResult)+        entityVal insertResult @?= getResult+    , testCase "insertRecord" $ do+        (insertResult, getResult) <- runTestApp backendType $ do+          insertResult <- insertRecord $ person "Alice"+          getResult <- getJust 1+          return (insertResult, getResult)+        insertResult @?= getResult+    , testCase "getBy" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          mapM getBy [UniqueName "Alice", UniqueName "Bob"]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "getByValue" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          insert_ alice+          mapM getByValue [alice, person "Bob"]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "checkUnique" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          insert_ alice+          mapM+            checkUnique+            [ alice+            , person "Bob"+            , (person "Alice"){personAge = 100}+            ]+        result @?= [Just (UniqueName "Alice"), Nothing, Just (UniqueName "Alice")]+    , testCase "checkUniqueUpdateable" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          insert_ alice+          mapM+            checkUniqueUpdateable+            [ Entity 1 alice+            , Entity 2 $ person "Bob"+            , Entity 3 $ (person "Alice"){personAge = 100}+            ]+        result @?= [Nothing, Nothing, Just (UniqueName "Alice")]+    , testCase "deleteBy" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          deleteBy $ UniqueName "Alice"+          getPeople+        result @?= []+    , testCase "insertUnique" $ do+        (result1, result2, people) <- runTestApp backendType $ do+          result1 <- insertUnique $ person "Alice"+          result2 <- insertUnique $ person "Alice"+          people <- getPeopleNames+          return (result1, result2, people)+        result1 @?= Just 1+        result2 @?= Nothing+        people @?= ["Alice"]+    , testCase "upsert" $ do+        (result1, result2, people) <- runTestApp backendType $ do+          result1 <- upsert (person "Alice") [PersonAge =. 0]+          result2 <- upsert (person "Alice") [PersonAge =. 100]+          people <- getPeople+          return (result1, result2, people)+        entityKey result1 @?= entityKey result2+        nameAndAge (entityVal result1) @?= ("Alice", 0)+        nameAndAge (entityVal result2) @?= ("Alice", 100)+        map nameAndAge people @?= [("Alice", 100)]+    , testCase "upsertBy" $ do+        (result1, result2, people) <- runTestApp backendType $ do+          result1 <- upsertBy (UniqueName "Alice") (person "Alice") [PersonAge =. 0]+          result2 <- upsertBy (UniqueName "Alice") (person "Alice") [PersonAge =. 100]+          people <- getPeople+          return (result1, result2, people)+        entityKey result1 @?= entityKey result2+        nameAndAge (entityVal result1) @?= ("Alice", 0)+        nameAndAge (entityVal result2) @?= ("Alice", 100)+        map nameAndAge people @?= [("Alice", 100)]+    , testCase "putMany" $ do+        result <- runTestApp backendType $ do+          let alice = person "Alice"+          insert_ alice+          putMany+            [ alice{personAge = 100}+            , person "Bob"+            ]+          getPeople+        map nameAndAge result+          @?= [ ("Alice", 100)+              , ("Bob", 0)+              ]+    , testCase "insertBy" $ do+        (result1, result2, people) <- runTestApp backendType $ do+          let alice = person "Alice"+          result1 <- insertBy alice+          result2 <- insertBy $ alice{personAge = 100}+          people <- getPeople+          return (result1, result2, people)+        result1 @?= Right 1+        first (entityKey &&& getName) result2 @?= Left (1, "Alice")+        map nameAndAge people @?= [("Alice", 0)]+    , testCase "insertUniqueEntity" $ do+        (result1, result2, people) <- runTestApp backendType $ do+          let alice = person "Alice"+          result1 <- insertUniqueEntity alice+          result2 <- insertUniqueEntity $ alice{personAge = 100}+          people <- getPeople+          return (result1, result2, people)+        (entityKey &&& getName) <$> result1 @?= Just (1, "Alice")+        result2 @?= Nothing+        map nameAndAge people @?= [("Alice", 0)]+    , testCase "replaceUnique" $ do+        (result1, result2, people) <- runTestApp backendType $ do+          let alice = person "Alice"+              bob = person "Bob"+          insertMany_ [alice, bob]+          result1 <- replaceUnique 1 $ alice{personName = "Bob"}+          result2 <- replaceUnique 2 $ bob{personAge = 100}+          people <- getPeople+          return (result1, result2, people)+        result1 @?= Just (UniqueName "Bob")+        result2 @?= Nothing+        map nameAndAge people @?= [("Alice", 0), ("Bob", 100)]+    , testCase "onlyUnique" $ do+        result <- runTestApp backendType $ onlyUnique $ person "Alice"+        result @?= UniqueName "Alice"+    , testCase "selectSourceRes" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          acquire <- selectSourceRes [] []+          Acquire.with acquire $ \conduit ->+            runConduit $ conduit .| Conduit.mapC getName .| Conduit.sinkList+        result @?= ["Alice", "Bob"]+    , testCase "selectFirst" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          sequence+            [ selectFirst [PersonName ==. "Alice"] []+            , selectFirst [PersonName ==. "Bob"] []+            ]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "selectKeysRes" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          acquire <- selectKeysRes @_ @Person [] []+          Acquire.with acquire $ \conduit ->+            runConduit $ conduit .| Conduit.sinkList+        result @?= [1, 2]+    , testCase "count" $ do+        result <- runTestApp backendType $ do+          insertMany_ $ map (\p -> p{personAge = 100}) [person "Alice", person "Bob"]+          count [PersonAge ==. 100]+        result @?= 2+    , testCase "exists" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          exists [PersonName ==. "Alice"]+        result @?= True+    , testCase "selectSource" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          runConduit $ selectSource [] [] .| Conduit.mapC getName .| Conduit.sinkList+        result @?= ["Alice", "Bob"]+    , testCase "selectKeys" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          runConduit $ selectKeys @Person [] [] .| Conduit.sinkList+        result @?= [1, 2]+    , testCase "selectList" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          insert_ $ person "Bob"+          selectList [] []+        map getName result @?= ["Alice", "Bob"]+    , testCase "selectKeysList" $ do+        result <- runTestApp backendType $ do+          insert_ $ person "Alice"+          insert_ $ person "Bob"+          selectKeysList @Person [] []+        result @?= [1, 2]+    , testCase "updateWhere" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          updateWhere [PersonName ==. "Alice"] [PersonAge =. 100]+          getPeople+        map nameAndAge result @?= [("Alice", 100), ("Bob", 0)]+    , testCase "deleteWhere" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          deleteWhere [PersonName ==. "Alice"]+          getPeopleNames+        result @?= ["Bob"]+    , testCase "updateWhereCount" $ do+        (rowsUpdated, people) <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          rowsUpdated <- updateWhereCount [PersonName ==. "Alice"] [PersonAge =. 100]+          people <- getPeople+          return (rowsUpdated, people)+        rowsUpdated @?= 1+        map nameAndAge people @?= [("Alice", 100), ("Bob", 0)]+    , testCase "deleteWhereCount" $ do+        (rowsDeleted, names) <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          rowsDeleted <- deleteWhereCount [PersonName ==. "Alice"]+          names <- getPeopleNames+          return (rowsDeleted, names)+        rowsDeleted @?= 1+        names @?= ["Bob"]+    , testCase "parseMigration" $ do+        result <- runTestApp backendType $ do+          setupUnsafeMigration+          parseMigration migration++        let sql = case backendType of+              Sqlite ->+                [ eq+                    ( False+                    , Text.concat+                        [ "CREATE TEMP TABLE \"person_backup\"("+                        , "\"id\" INTEGER PRIMARY KEY,"+                        , "\"name\" VARCHAR NOT NULL,"+                        , "\"age\" INTEGER NOT NULL,"+                        , "CONSTRAINT \"unique_name\" UNIQUE (\"name\"))"+                        ]+                    )+                , anything+                , eq (True, "DROP TABLE \"person\"")+                , anything+                , anything+                , eq (False, "DROP TABLE \"person_backup\"")+                ]+              Postgresql ->+                [ eq (True, "ALTER TABLE \"person\" DROP COLUMN \"foo\"")+                ]++        result @?~ right (elemsAre sql)+    , testCase "parseMigration'" $ do+        let action :: (Migration -> TestApp a) -> IO a+            action f = runTestApp backendType $ do+              setupUnsafeMigration+              f migration++        result <- action parseMigration+        result' <- action parseMigration'+        Right result' @?= result+    , testCase "printMigration" $+        runTestApp backendType $ do+          setupUnsafeMigration+          printMigration migration+    , testCase "showMigration" $ do+        result <- runTestApp backendType $ do+          setupUnsafeMigration+          showMigration migration++        let sql = case backendType of+              Sqlite ->+                [ eq $+                    Text.concat+                      [ "CREATE TEMP TABLE \"person_backup\"("+                      , "\"id\" INTEGER PRIMARY KEY,"+                      , "\"name\" VARCHAR NOT NULL,"+                      , "\"age\" INTEGER NOT NULL,"+                      , "CONSTRAINT \"unique_name\" UNIQUE (\"name\"));"+                      ]+                , anything+                , eq "DROP TABLE \"person\";"+                , anything+                , anything+                , eq "DROP TABLE \"person_backup\";"+                ]+              Postgresql ->+                [ eq "ALTER TABLE \"person\" DROP COLUMN \"foo\";"+                ]++        result @?~ elemsAre sql+    , testCase "getMigration" $ do+        result <- runTestApp backendType $ do+          setupUnsafeMigration+          getMigration migration++        let sql = case backendType of+              Sqlite ->+                [ eq $+                    Text.concat+                      [ "CREATE TEMP TABLE \"person_backup\"("+                      , "\"id\" INTEGER PRIMARY KEY,"+                      , "\"name\" VARCHAR NOT NULL,"+                      , "\"age\" INTEGER NOT NULL,"+                      , "CONSTRAINT \"unique_name\" UNIQUE (\"name\"))"+                      ]+                , anything+                , eq "DROP TABLE \"person\""+                , anything+                , anything+                , eq "DROP TABLE \"person_backup\""+                ]+              Postgresql ->+                [ eq "ALTER TABLE \"person\" DROP COLUMN \"foo\""+                ]++        result @?~ elemsAre sql+    , testCase "runMigration" $ do+        result <- runTestApp backendType $ do+          setupSafeMigration+          runMigration migration+          getSchemaColumnNames backendType "person"+        assertNotIn "removed_column" result+    , testCase "runMigrationQuiet" $ do+        (withQuiet, cols) <- runTestApp backendType $ do+          setupSafeMigration+          sql <- runMigrationQuiet migration+          cols <- getSchemaColumnNames backendType "person"+          return (sql, cols)+        withSilent <- runTestApp backendType $ do+          setupSafeMigration+          runMigrationSilent migration+        assertNotIn "removed_column" cols+        withQuiet @?= withSilent+    , testCase "runMigrationSilent" $ do+        (sqlPlanned, sqlExecuted, cols) <- runTestApp backendType $ do+          setupSafeMigration+          sqlPlanned <- getMigration migration+          sqlExecuted <- runMigrationSilent migration+          cols <- getSchemaColumnNames backendType "person"+          return (sqlPlanned, sqlExecuted, cols)+        assertNotIn "removed_column" cols+        sqlExecuted @?= sqlPlanned+    , testCase "runMigrationUnsafe" $ do+        result <- runTestApp backendType $ do+          setupUnsafeMigration+          runMigrationUnsafe migration+          getSchemaColumnNames backendType "person"+        assertNotIn "removed_column" result+    , testCase "runMigrationUnsafeQuiet" $ do+        (sqlPlanned, sqlExecuted, cols) <- runTestApp backendType $ do+          setupUnsafeMigration+          sqlPlanned <- getMigration migration+          sqlExecuted <- runMigrationUnsafeQuiet migration+          cols <- getSchemaColumnNames backendType "person"+          return (sqlPlanned, sqlExecuted, cols)+        assertNotIn "removed_column" cols+        sqlExecuted @?= sqlPlanned+    , testCase "getFieldName" $ do+        result <-+          runTestApp backendType $+            getFieldName PersonName+        result @?= "\"name\""+    , testCase "getTableName" $ do+        result <-+          runTestApp backendType $+            getTableName $+              person "Alice"+        result @?= "\"person\""+    , testCase "withRawQuery" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          withRawQuery "SELECT name FROM person" [] $+            Conduit.mapC (fromPersistValue' @Text . head) .| Conduit.sinkList++        result @?= ["Alice", "Bob"]+    , testCase "rawQueryRes" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          acquire <- rawQueryRes "SELECT name FROM person" []+          Acquire.with acquire $ \conduit ->+            runConduit $ conduit .| Conduit.mapC (fromPersistValue' @Text . head) .| Conduit.sinkList+        result @?= ["Alice", "Bob"]+    , testCase "rawQuery" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          runConduit $ rawQuery "SELECT name FROM person" [] .| Conduit.mapC (fromPersistValue' @Text . head) .| Conduit.sinkList+        result @?= ["Alice", "Bob"]+    , testCase "rawExecute" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          rawExecute "UPDATE person SET age = 100 WHERE name = 'Alice'" []+          getPeople+        map nameAndAge result @?= [("Alice", 100), ("Bob", 0)]+    , testCase "rawExecuteCount" $ do+        (rowsUpdated, people) <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          rowsUpdated <- rawExecuteCount "UPDATE person SET age = 100 WHERE name = 'Alice'" []+          people <- getPeople+          return (rowsUpdated, people)+        rowsUpdated @?= 1+        map nameAndAge people @?= [("Alice", 100), ("Bob", 0)]+    , testCase "rawSql" $ do+        result <- runTestApp backendType $ do+          insertMany_ [person "Alice", person "Bob"]+          rawSql @(Single String) "SELECT name FROM person" []+        map unSingle result @?= ["Alice", "Bob"]+    , testCase "transactionSave" $ do+        result1 <- runTestApp backendType $ do+          catchTestError $ withTransaction $ do+            insert_ $ person "Alice"+            insertAndFail $ person "Bob"+          getPeopleNames+        result1 @?= []++        result2 <- runTestApp backendType $ do+          catchTestError $ withTransaction $ do+            insert_ $ person "Alice"+            transactionSave+            insertAndFail $ person "Bob"+          getPeopleNames+        result2 @?= ["Alice"]+    , testCase "transactionSaveWithIsolation" $ do+        result1 <- runTestApp backendType $ do+          catchTestError $ withTransaction $ do+            insert_ $ person "Alice"+            insertAndFail $ person "Bob"+          getPeopleNames+        result1 @?= []++        result2 <- runTestApp backendType $ do+          catchTestError $ withTransaction $ do+            insert_ $ person "Alice"+            transactionSaveWithIsolation Serializable+            insertAndFail $ person "Bob"+          getPeopleNames+        result2 @?= ["Alice"]+    , testCase "transactionUndo" $ do+        result <- runTestApp backendType $ withTransaction $ do+          insert_ $ person "Alice"+          transactionUndo+          getPeopleNames+        result @?= []+    , testCase "transactionUndoWithIsolation" $ do+        result <- runTestApp backendType $ withTransaction $ do+          insert_ $ person "Alice"+          transactionUndoWithIsolation Serializable+          getPeopleNames+        result @?= []+    ]++testInterop :: BackendType -> TestTree+testInterop backendType =+  testGroup+    "Interop with third-party Persistent libraries"+    [ testCase "unsafeLiftSql" $ do+        let alice = person "Alice"+        result <- runTestApp backendType $ do+          insert_ alice+          esqueletoSelect $+            E.from $+              E.table @Person+        result @?= [Entity 1 alice]+    ]++{- Persistent helpers -}++fromPersistValue' :: PersistField a => PersistValue -> a+fromPersistValue' = either (error . Text.unpack) id . fromPersistValue++{- Meta SQL helpers -}++-- | Put the database in a state where running a migration is safe.+setupSafeMigration :: MonadSqlQuery m => m ()+setupSafeMigration = rawExecute "ALTER TABLE person ADD COLUMN removed_column VARCHAR" []++-- | Put the database in a state where running a migration is unsafe.+setupUnsafeMigration :: MonadSqlQuery m => m ()+setupUnsafeMigration = rawExecute "ALTER TABLE person ADD COLUMN foo VARCHAR" []++-- | Get the names of all columns in the given table.+getSchemaColumnNames :: MonadSqlQuery m => BackendType -> String -> m [String]+getSchemaColumnNames backendType tableName = map unSingle <$> rawSql sql []+  where+    sql = Text.pack $ case backendType of+      Sqlite -> "SELECT name FROM pragma_table_info('" ++ tableName ++ "')"+      Postgresql ->+        unlines+          [ "SELECT column_name FROM information_schema.columns"+          , "WHERE table_schema = 'public' AND table_name = '" ++ tableName ++ "'"+          ]++{- Test helpers -}++data TestError = TestError+  deriving (Show, Eq)++instance Exception TestError++catchTestError :: (MonadUnliftIO m, Eq a, Show a) => m a -> m ()+catchTestError m = do+  result <- try m+  liftIO $ result @?= Left TestError++insertAndFail ::+  ( MonadRerunnableIO m+  , MonadSqlQuery m+  , PersistRecordBackend record SqlBackend+  , Typeable record+  , SafeToInsert record+  ) =>+  record ->+  m ()+insertAndFail record = do+  insert_ record+  rerunnableIO $ throwIO TestError++assertNotIn :: (Eq a, Show a) => a -> [a] -> Assertion+assertNotIn a as = as @?= filter (/= a) as
test/Main.hs view
@@ -1,19 +1,4 @@-import Test.Tasty--import qualified Basic-import qualified Integration-import qualified MockSqlQueryT-import qualified Mocked-import qualified SqlQueryRepTest--main :: IO ()-main = defaultMain tests--tests :: TestTree-tests = testGroup "persistent-mtl"-  [ Basic.tests-  , Mocked.tests-  , Integration.tests-  , MockSqlQueryT.tests-  , SqlQueryRepTest.tests-  ]+{- AUTOCOLLECT.MAIN+suite_name = persistent-mtl+strip_suffix = Test+-}
− test/MockSqlQueryT.hs
@@ -1,38 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TypeApplications #-}--module MockSqlQueryT where--import Database.Persist (Entity(..))-import Database.Persist.Sql (toSqlKey)-import Test.Tasty-import Test.Tasty.HUnit-import UnliftIO (SomeException, try)--import Database.Persist.Monad.TestUtils-import Example--tests :: TestTree-tests = testGroup "MockSqlQueryT"-  [ testCase "it errors if it could not find a mock" $ do-      result <- try $ runMockSqlQueryT getPeopleNames []-      case result of-        Right _ -> assertFailure "runMockSqlQueryT did not fail"-        Left e -> do-          let msg = head $ lines $ show (e :: SomeException)-          msg @?= "Could not find mock for query: SelectList{..}<Person>"-  , testCase "it continues after a mock doesn't match" $ do-      result <- runMockSqlQueryT getPeopleNames-        [ withRecord @Post $ \_ -> error "getPeopleNames matched Post record"-        , mockQuery $ \_ -> Nothing-        , withRecord @Person $ \case-            SelectList _ _ -> Just-              [ Entity (toSqlKey 1) (Person "Alice" 10)-              , Entity (toSqlKey 2) (Person "Bob" 20)-              ]-            _ -> Nothing-        ]--      result @?= ["Alice", "Bob"]-  ]
− test/Mocked.hs
@@ -1,548 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications #-}--module Mocked where--import Conduit (runConduit, runResourceT, (.|))-import qualified Conduit-import qualified Data.Acquire as Acquire-import qualified Data.Map.Strict as Map-import Database.Persist.Sql-    (Entity(..), Single(..), toPersistValue, (=.), (==.))-import Test.Tasty-import Test.Tasty.HUnit--import Database.Persist.Monad-import Database.Persist.Monad.TestUtils-import Example--tests :: TestTree-tests = testGroup "Mocked tests"-  [ testWithTransaction-  , testPersistentAPI-  ]--testWithTransaction :: TestTree-testWithTransaction = testGroup "withTransaction"-  [ testCase "it doesn't error with MockSqlQueryT" $-      runMockSqlQueryT (withTransaction $ insert_ $ person "Alice")-        [ withRecord @Person $ \case-            Insert_ _ -> Just ()-            _ -> Nothing-        ]-  ]--testPersistentAPI :: TestTree-testPersistentAPI = testGroup "Persistent API"-  [ testCase "get" $ do-      result <- runMockSqlQueryT (mapM get [1, 2])-        [ withRecord @Person $ \case-            Get n-              | n == 1 -> Just $ Just $ person "Alice"-              | n == 2 -> Just Nothing-            _ -> Nothing-        ]-      map (fmap personName) result @?= [Just "Alice", Nothing]--  , testCase "getMany" $ do-      result <- runMockSqlQueryT (getMany [1])-        [ withRecord @Person $ \case-            GetMany _ -> Just $ Map.fromList [(1, person "Alice")]-            _ -> Nothing-        ]-      personName <$> Map.lookup 1 result @?= Just "Alice"--  , testCase "getJust" $ do-      result <- runMockSqlQueryT (getJust 1)-        [ withRecord @Person $ \case-            GetJust _ -> Just $ person "Alice"-            _ -> Nothing-        ]-      personName result @?= "Alice"--  , testCase "getJustEntity" $ do-      result <- runMockSqlQueryT (getJustEntity 1)-        [ withRecord @Person $ \case-            GetJustEntity _ -> Just $ Entity 1 $ person "Alice"-            _ -> Nothing-        ]-      getName result @?= "Alice"--  , testCase "getEntity" $ do-      result <- runMockSqlQueryT (mapM getEntity [1, 2])-        [ withRecord @Person $ \case-            GetEntity n-              | n == 1 -> Just $ Just $ Entity 1 $ person "Alice"-              | n == 2 -> Just Nothing-            _ -> Nothing-        ]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "belongsTo" $ do-      let post1 = Post "Post #1" 1 (Just 1)-          post2 = Post "Post #2" 1 Nothing-      result <- runMockSqlQueryT (mapM (belongsTo postEditor) [post1, post2])-        [ withRecord @(Post, Person) $ \case-            BelongsTo _ Post{postEditor = Just 1} -> Just $ Just $ person "Alice"-            BelongsTo _ Post{postEditor = Nothing} -> Just Nothing-            _ -> Nothing-        ]-      map (fmap personName) result @?= [Just "Alice", Nothing]--  , testCase "belongsToJust" $ do-      let post1 = Post "Post #1" 1 Nothing-      result <- runMockSqlQueryT (belongsToJust postAuthor post1)-        [ withRecord @(Post, Person) $ \case-            BelongsToJust _ _ -> Just $ person "Alice"-            _ -> Nothing-        ]-      personName result @?= "Alice"--  , testCase "insert" $ do-      result <- runMockSqlQueryT (insert $ person "Alice")-        [ withRecord @Person $ \case-            Insert _ -> Just 1-            _ -> Nothing-        ]-      result @?= 1--  , testCase "insert_" $ do-      result <- runMockSqlQueryT (insert_ $ person "Alice")-        [ withRecord @Person $ \case-            Insert_ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "insertMany" $ do-      result <- runMockSqlQueryT (insertMany [person "Alice", person "Bob"])-        [ withRecord @Person $ \case-            InsertMany records -> Just $ map fromIntegral [ 1 .. length records ]-            _ -> Nothing-        ]-      result @?= [1, 2]--  , testCase "insertMany_" $ do-      result <- runMockSqlQueryT (insertMany_ [person "Alice", person "Bob"])-        [ withRecord @Person $ \case-            InsertMany_ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "insertEntityMany" $ do-      result <- runMockSqlQueryT (insertEntityMany [Entity 1 $ person "Alice"])-        [ withRecord @Person $ \case-            InsertEntityMany _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "insertKey" $ do-      result <- runMockSqlQueryT (insertKey 1 $ person "Alice")-        [ withRecord @Person $ \case-            InsertKey _ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "repsert" $ do-      result <- runMockSqlQueryT (repsert 1 $ person "Alice")-        [ withRecord @Person $ \case-            Repsert _ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "repsertMany" $ do-      result <- runMockSqlQueryT (repsertMany [(1, person "Alice")])-        [ withRecord @Person $ \case-            RepsertMany _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "replace" $ do-      result <- runMockSqlQueryT (replace 1 $ person "Alice")-        [ withRecord @Person $ \case-            Replace _ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "delete" $ do-      result <- runMockSqlQueryT (delete @Person 1)-        [ withRecord @Person $ \case-            Delete _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "update" $ do-      result <- runMockSqlQueryT (update 1 [PersonName =. "Alicia"])-        [ withRecord @Person $ \case-            Update _ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "updateGet" $ do-      result <- runMockSqlQueryT (updateGet 1 [PersonName =. "Alicia"])-        [ withRecord @Person $ \case-            UpdateGet _ _ -> Just $ person "Alicia"-            _ -> Nothing-        ]-      personName result @?= "Alicia"--  , testCase "insertEntity" $ do-      let alice = person "Alice"-      result <- runMockSqlQueryT (insertEntity alice)-        [ withRecord @Person $ \case-            InsertEntity _ -> Just $ Entity 1 alice-            _ -> Nothing-        ]-      entityVal result @?= alice--  , testCase "insertRecord" $ do-      let alice = person "Alice"-      result <- runMockSqlQueryT (insertRecord alice)-        [ withRecord @Person $ \case-            InsertRecord _ -> Just alice-            _ -> Nothing-        ]-      result @?= alice--  , testCase "getBy" $ do-      result <- runMockSqlQueryT (mapM getBy [UniqueName "Alice", UniqueName "Bob"])-        [ withRecord @Person $ \case-            GetBy (UniqueName "Alice") -> Just $ Just $ Entity 1 $ person "Alice"-            GetBy (UniqueName "Bob") -> Just Nothing-            _ -> Nothing-        ]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "getByValue" $ do-      result <- runMockSqlQueryT (mapM getByValue [person "Alice", person "Bob"])-        [ withRecord @Person $ \case-            GetByValue Person{personName = "Alice"} -> Just $ Just $ Entity 1 $ person "Alice"-            GetByValue Person{personName = "Bob"} -> Just Nothing-            _ -> Nothing-        ]-      map (fmap getName) result @?= [Just "Alice", Nothing]--  , testCase "checkUnique" $ do-      result <- runMockSqlQueryT (mapM checkUnique [person "Alice", person "Bob"])-        [ withRecord @Person $ \case-            CheckUnique Person{personName = "Alice"} -> Just $ Just $ UniqueName "Alice"-            CheckUnique Person{personName = "Bob"} -> Just Nothing-            _ -> Nothing-        ]-      result @?= [Just $ UniqueName "Alice", Nothing]--#if MIN_VERSION_persistent(2,11,0)-  , testCase "checkUniqueUpdateable" $ do-      result <- runMockSqlQueryT (mapM checkUniqueUpdateable [Entity 1 $ person "Alice", Entity 2 $ person "Bob"])-        [ withRecord @Person $ \case-            CheckUniqueUpdateable (Entity _ Person{personName = "Alice"}) -> Just $ Just $ UniqueName "Alice"-            CheckUniqueUpdateable (Entity _ Person{personName = "Bob"}) -> Just Nothing-            _ -> Nothing-        ]-      result @?= [Just $ UniqueName "Alice", Nothing]-#endif--  , testCase "deleteBy" $ do-      result <- runMockSqlQueryT (deleteBy $ UniqueName "Alice")-        [ withRecord @Person $ \case-            DeleteBy _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "insertUnique" $ do-      result <- runMockSqlQueryT (mapM insertUnique [person "Alice", person "Bob"])-        [ withRecord @Person $ \case-            InsertUnique Person{personName = "Alice"} -> Just $ Just 1-            InsertUnique Person{personName = "Bob"} -> Just Nothing-            _ -> Nothing-        ]-      result @?= [Just 1, Nothing]--  , testCase "upsert" $ do-      let alice = person "Alice"-      result <- runMockSqlQueryT (upsert alice [PersonAge =. 100])-        [ withRecord @Person $ \case-            Upsert _ _ -> Just $ Entity 1 alice-            _ -> Nothing-        ]-      result @?= Entity 1 alice--  , testCase "upsertBy" $ do-      let alice = person "Alice"-      result <- runMockSqlQueryT (upsertBy (UniqueName "Alice") alice [PersonAge =. 100])-        [ withRecord @Person $ \case-            UpsertBy _ _ _ -> Just $ Entity 1 alice-            _ -> Nothing-        ]-      result @?= Entity 1 alice--  , testCase "putMany" $ do-      result <- runMockSqlQueryT (putMany [person "Alice"])-        [ withRecord @Person $ \case-            PutMany _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "insertBy" $ do-      let alice = person "Alice"-      result <- runMockSqlQueryT (mapM insertBy [alice, person "Bob"])-        [ withRecord @Person $ \case-            InsertBy Person{personName = "Alice"} -> Just $ Left $ Entity 1 alice-            InsertBy Person{personName = "Bob"} -> Just $ Right 2-            _ -> Nothing-        ]-      result @?= [Left $ Entity 1 alice, Right 2]--  , testCase "insertUniqueEntity" $ do-      let bob = person "Bob"-      result <- runMockSqlQueryT (mapM insertUniqueEntity [person "Alice", bob])-        [ withRecord @Person $ \case-            InsertUniqueEntity Person{personName = "Alice"} -> Just Nothing-            InsertUniqueEntity Person{personName = "Bob"} -> Just $ Just $ Entity 1 bob-            _ -> Nothing-        ]-      result @?= [Nothing, Just $ Entity 1 bob]--  , testCase "replaceUnique" $ do-      result <- runMockSqlQueryT (mapM (uncurry replaceUnique) [(1, person "Alice"), (2, person "Bob")])-        [ withRecord @Person $ \case-            ReplaceUnique _ Person{personName = "Alice"} -> Just Nothing-            ReplaceUnique _ Person{personName = "Bob"} -> Just $ Just $ UniqueName "Bob"-            _ -> Nothing-        ]-      result @?= [Nothing, Just $ UniqueName "Bob"]--  , testCase "onlyUnique" $ do-      result <- runMockSqlQueryT (onlyUnique $ person "Alice")-        [ withRecord @Person $ \case-            OnlyUnique _ -> Just $ UniqueName "Alice"-            _ -> Nothing-        ]-      result @?= UniqueName "Alice"--  , testCase "selectSourceRes" $ do-      acquire <- runMockSqlQueryT (selectSourceRes [] [])-        [ mockSelectSource $ \_ _ -> Just-            [ Entity 1 $ person "Alice"-            , Entity 2 $ person "Bob"-            ]-        ]-      result <- Acquire.with acquire $ \conduit ->-        runConduit $ conduit .| Conduit.mapC getName .| Conduit.sinkList-      result @?= ["Alice", "Bob"]--  , testCase "selectFirst" $ do-      result1 <- runMockSqlQueryT (selectFirst [PersonName ==. "Alice"] [])-        [ withRecord @Person $ \case-            SelectFirst _ _ -> Just $ Just $ Entity 1 $ person "Alice"-            _ -> Nothing-        ]-      getName <$> result1 @?= Just "Alice"-      result2 <- runMockSqlQueryT (selectFirst [PersonName ==. "Alice"] [])-        [ withRecord @Person $ \case-            SelectFirst _ _ -> Just Nothing-            _ -> Nothing-        ]-      result2 @?= Nothing--  , testCase "selectKeysRes" $ do-      let keys = [1, 2, 3]-      acquire <- runMockSqlQueryT (selectKeysRes @_ @Person [] [])-        [ mockSelectKeys $ \_ _ -> Just keys-        ]-      result <- Acquire.with acquire $ \conduit ->-        runConduit $ conduit .| Conduit.sinkList-      result @?= keys--  , testCase "count" $ do-      result <- runMockSqlQueryT (count @Person [])-        [ withRecord @Person $ \case-            Count _ -> Just 10-            _ -> Nothing-        ]-      result @?= 10--#if MIN_VERSION_persistent(2,11,0)-  , testCase "exists" $ do-      result <- runMockSqlQueryT (exists @Person [])-        [ withRecord @Person $ \case-            Exists _ -> Just True-            _ -> Nothing-        ]-      result @?= True-#endif--  , testCase "selectSource" $ do-      result <- runResourceT $ runMockSqlQueryT-        (runConduit $ selectSource [] [] .| Conduit.mapC getName .| Conduit.sinkList)-        [ mockSelectSource $ \_ _ -> Just-            [ Entity 1 $ person "Alice"-            , Entity 2 $ person "Bob"-            ]-        ]-      result @?= ["Alice", "Bob"]--  , testCase "selectKeys" $ do-      let keys = [1, 2, 3]-      result <- runResourceT $ runMockSqlQueryT-        (runConduit $ selectKeys @Person [] [] .| Conduit.sinkList)-        [ mockSelectKeys $ \_ _ -> Just keys-        ]-      result @?= keys--  , testCase "selectList" $ do-      result <- runMockSqlQueryT (selectList [] [])-        [ withRecord @Person $ \case-            SelectList _ _ -> Just-              [ Entity 1 (person "Alice")-              , Entity 2 (person "Bob")-              ]-            _ -> Nothing-        ]-      map getName result @?= ["Alice", "Bob"]--  , testCase "selectKeysList" $ do-      let keys = [1, 2, 3]-      result <- runMockSqlQueryT (selectKeysList @Person [] [])-        [ withRecord @Person $ \case-            SelectKeysList _ _ -> Just keys-            _ -> Nothing-        ]-      result @?= keys--  , testCase "updateWhere" $ do-      result <- runMockSqlQueryT (updateWhere [] [PersonAge =. 100])-        [ withRecord @Person $ \case-            UpdateWhere _ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "deleteWhere" $ do-      result <- runMockSqlQueryT (deleteWhere [PersonName ==. "Alice"])-        [ withRecord @Person $ \case-            DeleteWhere _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "updateWhereCount" $ do-      result <- runMockSqlQueryT (updateWhereCount [] [PersonAge =. 100])-        [ withRecord @Person $ \case-            UpdateWhereCount _ _ -> Just 10-            _ -> Nothing-        ]-      result @?= 10--  , testCase "deleteWhereCount" $ do-      result <- runMockSqlQueryT (deleteWhereCount [PersonName ==. "Alice"])-        [ withRecord @Person $ \case-            DeleteWhereCount _ -> Just 10-            _ -> Nothing-        ]-      result @?= 10--#if !MIN_VERSION_persistent(2,13,0)-  , testCase "deleteCascade" $ do-      result <- runMockSqlQueryT (deleteCascade @Person 1)-        [ withRecord @Person $ \case-            DeleteCascade _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "deleteCascadeWhere" $ do-      result <- runMockSqlQueryT (deleteCascadeWhere [PersonName ==. "Alice"])-        [ withRecord @Person $ \case-            DeleteCascadeWhere _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()-#endif--  , testCase "getFieldName" $ do-      result <- runMockSqlQueryT (getFieldName PersonName)-        [ withRecord @Person $ \case-            GetFieldName PersonName -> Just "\"name\""-            _ -> Nothing-        ]-      result @?= "\"name\""--  , testCase "getTableName" $ do-      result <- runMockSqlQueryT (getTableName $ person "Alice")-        [ withRecord @Person $ \case-            GetTableName _ -> Just "\"person\""-            _ -> Nothing-        ]-      result @?= "\"person\""--  , testCase "withRawQuery" $ do-      let query = "SELECT name FROM person"-          row1 = [toPersistValue @String "Alice"]-          row2 = [toPersistValue @String "Bob"]-          rows = [row1, row2]-      result <- runMockSqlQueryT (withRawQuery query [] Conduit.sinkList)-        [ mockWithRawQuery $ \sql _ ->-            if sql == query-              then Just rows-              else Nothing-        ]-      result @?= rows--  , testCase "rawQueryRes" $ do-      let row1 = [toPersistValue @String "Alice"]-          row2 = [toPersistValue @String "Bob"]-          rows = [row1, row2]-      acquire <- runMockSqlQueryT (rawQueryRes "SELECT name FROM person" [])-        [ mockRawQuery $ \_ _ -> Just rows-        ]-      result <- Acquire.with acquire $ \conduit ->-        runConduit $ conduit .| Conduit.sinkList-      result @?= rows--  , testCase "rawQuery" $ do-      let row1 = [toPersistValue @String "Alice"]-          row2 = [toPersistValue @String "Bob"]-          rows = [row1, row2]-      result <- runResourceT $ runMockSqlQueryT-        (runConduit $ rawQuery "SELECT name FROM person" [] .| Conduit.sinkList)-        [ mockRawQuery $ \_ _ -> Just rows-        ]-      result @?= rows--  , testCase "rawExecute" $ do-      result <- runMockSqlQueryT (rawExecute "DELETE FROM person" [])-        [ mockQuery $ \case-            RawExecute _ _ -> Just ()-            _ -> Nothing-        ]-      result @?= ()--  , testCase "rawExecuteCount" $ do-      result <- runMockSqlQueryT (rawExecuteCount "DELETE FROM person" [])-        [ mockQuery $ \case-            RawExecuteCount _ _ -> Just 10-            _ -> Nothing-        ]-      result @?= 10--  , testCase "rawSql" $ do-      let names = ["Alice", "Bob"] :: [String]-      result <- runMockSqlQueryT (rawSql "SELECT name FROM person" [])-        [ mockRawSql $ \_ _ -> Just $ map ((:[]) . toPersistValue) names-        ]-      map unSingle result @?= names-  ]
+ test/MockedTest.hs view
@@ -0,0 +1,621 @@+{- AUTOCOLLECT.TEST -}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++module MockedTest (+  -- $AUTOCOLLECT.TEST.export$+) where++import Conduit (runConduit, runResourceT, (.|))+import qualified Conduit+import qualified Data.Acquire as Acquire+import qualified Data.Map.Strict as Map+import Database.Persist.Sql (+  Entity (..),+  Single (..),+  toPersistValue,+  toSqlKey,+  (=.),+  (==.),+ )+import Test.Tasty+import Test.Tasty.HUnit+import UnliftIO (SomeException, try)++import Database.Persist.Monad+import Database.Persist.Monad.TestUtils+import Example++test =+  testGroup+    "withTransaction"+    [ testCase "it doesn't error with MockSqlQueryT" $+        runMockSqlQueryT+          (withTransaction $ insert_ $ person "Alice")+          [ withRecord @Person $ \case+              Insert_ _ -> Just ()+              _ -> Nothing+          ]+    ]++test =+  testGroup+    "MockSqlQueryT"+    [ testCase "it errors if it could not find a mock" $ do+        result <- try $ runMockSqlQueryT getPeopleNames []+        case result of+          Right _ -> assertFailure "runMockSqlQueryT did not fail"+          Left e -> do+            let msg = head $ lines $ show (e :: SomeException)+            msg @?= "Could not find mock for query: SelectList{..}<Person>"+    , testCase "it continues after a mock doesn't match" $ do+        result <-+          runMockSqlQueryT+            getPeopleNames+            [ withRecord @Post $ \_ -> error "getPeopleNames matched Post record"+            , mockQuery $ \_ -> Nothing+            , withRecord @Person $ \case+                SelectList _ _ ->+                  Just+                    [ Entity (toSqlKey 1) (Person "Alice" 10)+                    , Entity (toSqlKey 2) (Person "Bob" 20)+                    ]+                _ -> Nothing+            ]++        result @?= ["Alice", "Bob"]+    ]++test =+  testGroup+    "Persistent API"+    [ testCase "get" $ do+        result <-+          runMockSqlQueryT+            (mapM get [1, 2])+            [ withRecord @Person $ \case+                Get n+                  | n == 1 -> Just $ Just $ person "Alice"+                  | n == 2 -> Just Nothing+                _ -> Nothing+            ]+        map (fmap personName) result @?= [Just "Alice", Nothing]+    , testCase "getMany" $ do+        result <-+          runMockSqlQueryT+            (getMany [1])+            [ withRecord @Person $ \case+                GetMany _ -> Just $ Map.fromList [(1, person "Alice")]+                _ -> Nothing+            ]+        personName <$> Map.lookup 1 result @?= Just "Alice"+    , testCase "getJust" $ do+        result <-+          runMockSqlQueryT+            (getJust 1)+            [ withRecord @Person $ \case+                GetJust _ -> Just $ person "Alice"+                _ -> Nothing+            ]+        personName result @?= "Alice"+    , testCase "getJustEntity" $ do+        result <-+          runMockSqlQueryT+            (getJustEntity 1)+            [ withRecord @Person $ \case+                GetJustEntity _ -> Just $ Entity 1 $ person "Alice"+                _ -> Nothing+            ]+        getName result @?= "Alice"+    , testCase "getEntity" $ do+        result <-+          runMockSqlQueryT+            (mapM getEntity [1, 2])+            [ withRecord @Person $ \case+                GetEntity n+                  | n == 1 -> Just $ Just $ Entity 1 $ person "Alice"+                  | n == 2 -> Just Nothing+                _ -> Nothing+            ]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "belongsTo" $ do+        let post1 = Post "Post #1" 1 (Just 1)+            post2 = Post "Post #2" 1 Nothing+        result <-+          runMockSqlQueryT+            (mapM (belongsTo postEditor) [post1, post2])+            [ withRecord @(Post, Person) $ \case+                BelongsTo _ Post{postEditor = Just 1} -> Just $ Just $ person "Alice"+                BelongsTo _ Post{postEditor = Nothing} -> Just Nothing+                _ -> Nothing+            ]+        map (fmap personName) result @?= [Just "Alice", Nothing]+    , testCase "belongsToJust" $ do+        let post1 = Post "Post #1" 1 Nothing+        result <-+          runMockSqlQueryT+            (belongsToJust postAuthor post1)+            [ withRecord @(Post, Person) $ \case+                BelongsToJust _ _ -> Just $ person "Alice"+                _ -> Nothing+            ]+        personName result @?= "Alice"+    , testCase "insert" $ do+        result <-+          runMockSqlQueryT+            (insert $ person "Alice")+            [ withRecord @Person $ \case+                Insert _ -> Just 1+                _ -> Nothing+            ]+        result @?= 1+    , testCase "insert_" $ do+        result <-+          runMockSqlQueryT+            (insert_ $ person "Alice")+            [ withRecord @Person $ \case+                Insert_ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "insertMany" $ do+        result <-+          runMockSqlQueryT+            (insertMany [person "Alice", person "Bob"])+            [ withRecord @Person $ \case+                InsertMany records -> Just $ map fromIntegral [1 .. length records]+                _ -> Nothing+            ]+        result @?= [1, 2]+    , testCase "insertMany_" $ do+        result <-+          runMockSqlQueryT+            (insertMany_ [person "Alice", person "Bob"])+            [ withRecord @Person $ \case+                InsertMany_ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "insertEntityMany" $ do+        result <-+          runMockSqlQueryT+            (insertEntityMany [Entity 1 $ person "Alice"])+            [ withRecord @Person $ \case+                InsertEntityMany _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "insertKey" $ do+        result <-+          runMockSqlQueryT+            (insertKey 1 $ person "Alice")+            [ withRecord @Person $ \case+                InsertKey _ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "repsert" $ do+        result <-+          runMockSqlQueryT+            (repsert 1 $ person "Alice")+            [ withRecord @Person $ \case+                Repsert _ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "repsertMany" $ do+        result <-+          runMockSqlQueryT+            (repsertMany [(1, person "Alice")])+            [ withRecord @Person $ \case+                RepsertMany _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "replace" $ do+        result <-+          runMockSqlQueryT+            (replace 1 $ person "Alice")+            [ withRecord @Person $ \case+                Replace _ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "delete" $ do+        result <-+          runMockSqlQueryT+            (delete @Person 1)+            [ withRecord @Person $ \case+                Delete _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "update" $ do+        result <-+          runMockSqlQueryT+            (update 1 [PersonName =. "Alicia"])+            [ withRecord @Person $ \case+                Update _ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "updateGet" $ do+        result <-+          runMockSqlQueryT+            (updateGet 1 [PersonName =. "Alicia"])+            [ withRecord @Person $ \case+                UpdateGet _ _ -> Just $ person "Alicia"+                _ -> Nothing+            ]+        personName result @?= "Alicia"+    , testCase "insertEntity" $ do+        let alice = person "Alice"+        result <-+          runMockSqlQueryT+            (insertEntity alice)+            [ withRecord @Person $ \case+                InsertEntity _ -> Just $ Entity 1 alice+                _ -> Nothing+            ]+        entityVal result @?= alice+    , testCase "insertRecord" $ do+        let alice = person "Alice"+        result <-+          runMockSqlQueryT+            (insertRecord alice)+            [ withRecord @Person $ \case+                InsertRecord _ -> Just alice+                _ -> Nothing+            ]+        result @?= alice+    , testCase "getBy" $ do+        result <-+          runMockSqlQueryT+            (mapM getBy [UniqueName "Alice", UniqueName "Bob"])+            [ withRecord @Person $ \case+                GetBy (UniqueName "Alice") -> Just $ Just $ Entity 1 $ person "Alice"+                GetBy (UniqueName "Bob") -> Just Nothing+                _ -> Nothing+            ]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "getByValue" $ do+        result <-+          runMockSqlQueryT+            (mapM getByValue [person "Alice", person "Bob"])+            [ withRecord @Person $ \case+                GetByValue Person{personName = "Alice"} -> Just $ Just $ Entity 1 $ person "Alice"+                GetByValue Person{personName = "Bob"} -> Just Nothing+                _ -> Nothing+            ]+        map (fmap getName) result @?= [Just "Alice", Nothing]+    , testCase "checkUnique" $ do+        result <-+          runMockSqlQueryT+            (mapM checkUnique [person "Alice", person "Bob"])+            [ withRecord @Person $ \case+                CheckUnique Person{personName = "Alice"} -> Just $ Just $ UniqueName "Alice"+                CheckUnique Person{personName = "Bob"} -> Just Nothing+                _ -> Nothing+            ]+        result @?= [Just $ UniqueName "Alice", Nothing]+    , testCase "checkUniqueUpdateable" $ do+        result <-+          runMockSqlQueryT+            (mapM checkUniqueUpdateable [Entity 1 $ person "Alice", Entity 2 $ person "Bob"])+            [ withRecord @Person $ \case+                CheckUniqueUpdateable (Entity _ Person{personName = "Alice"}) -> Just $ Just $ UniqueName "Alice"+                CheckUniqueUpdateable (Entity _ Person{personName = "Bob"}) -> Just Nothing+                _ -> Nothing+            ]+        result @?= [Just $ UniqueName "Alice", Nothing]+    , testCase "deleteBy" $ do+        result <-+          runMockSqlQueryT+            (deleteBy $ UniqueName "Alice")+            [ withRecord @Person $ \case+                DeleteBy _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "insertUnique" $ do+        result <-+          runMockSqlQueryT+            (mapM insertUnique [person "Alice", person "Bob"])+            [ withRecord @Person $ \case+                InsertUnique Person{personName = "Alice"} -> Just $ Just 1+                InsertUnique Person{personName = "Bob"} -> Just Nothing+                _ -> Nothing+            ]+        result @?= [Just 1, Nothing]+    , testCase "upsert" $ do+        let alice = person "Alice"+        result <-+          runMockSqlQueryT+            (upsert alice [PersonAge =. 100])+            [ withRecord @Person $ \case+                Upsert _ _ -> Just $ Entity 1 alice+                _ -> Nothing+            ]+        result @?= Entity 1 alice+    , testCase "upsertBy" $ do+        let alice = person "Alice"+        result <-+          runMockSqlQueryT+            (upsertBy (UniqueName "Alice") alice [PersonAge =. 100])+            [ withRecord @Person $ \case+                UpsertBy _ _ _ -> Just $ Entity 1 alice+                _ -> Nothing+            ]+        result @?= Entity 1 alice+    , testCase "putMany" $ do+        result <-+          runMockSqlQueryT+            (putMany [person "Alice"])+            [ withRecord @Person $ \case+                PutMany _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "insertBy" $ do+        let alice = person "Alice"+        result <-+          runMockSqlQueryT+            (mapM insertBy [alice, person "Bob"])+            [ withRecord @Person $ \case+                InsertBy Person{personName = "Alice"} -> Just $ Left $ Entity 1 alice+                InsertBy Person{personName = "Bob"} -> Just $ Right 2+                _ -> Nothing+            ]+        result @?= [Left $ Entity 1 alice, Right 2]+    , testCase "insertUniqueEntity" $ do+        let bob = person "Bob"+        result <-+          runMockSqlQueryT+            (mapM insertUniqueEntity [person "Alice", bob])+            [ withRecord @Person $ \case+                InsertUniqueEntity Person{personName = "Alice"} -> Just Nothing+                InsertUniqueEntity Person{personName = "Bob"} -> Just $ Just $ Entity 1 bob+                _ -> Nothing+            ]+        result @?= [Nothing, Just $ Entity 1 bob]+    , testCase "replaceUnique" $ do+        result <-+          runMockSqlQueryT+            (mapM (uncurry replaceUnique) [(1, person "Alice"), (2, person "Bob")])+            [ withRecord @Person $ \case+                ReplaceUnique _ Person{personName = "Alice"} -> Just Nothing+                ReplaceUnique _ Person{personName = "Bob"} -> Just $ Just $ UniqueName "Bob"+                _ -> Nothing+            ]+        result @?= [Nothing, Just $ UniqueName "Bob"]+    , testCase "onlyUnique" $ do+        result <-+          runMockSqlQueryT+            (onlyUnique $ person "Alice")+            [ withRecord @Person $ \case+                OnlyUnique _ -> Just $ UniqueName "Alice"+                _ -> Nothing+            ]+        result @?= UniqueName "Alice"+    , testCase "selectSourceRes" $ do+        acquire <-+          runMockSqlQueryT+            (selectSourceRes [] [])+            [ mockSelectSource $ \_ _ ->+                Just+                  [ Entity 1 $ person "Alice"+                  , Entity 2 $ person "Bob"+                  ]+            ]+        result <- Acquire.with acquire $ \conduit ->+          runConduit $ conduit .| Conduit.mapC getName .| Conduit.sinkList+        result @?= ["Alice", "Bob"]+    , testCase "selectFirst" $ do+        result1 <-+          runMockSqlQueryT+            (selectFirst [PersonName ==. "Alice"] [])+            [ withRecord @Person $ \case+                SelectFirst _ _ -> Just $ Just $ Entity 1 $ person "Alice"+                _ -> Nothing+            ]+        getName <$> result1 @?= Just "Alice"+        result2 <-+          runMockSqlQueryT+            (selectFirst [PersonName ==. "Alice"] [])+            [ withRecord @Person $ \case+                SelectFirst _ _ -> Just Nothing+                _ -> Nothing+            ]+        result2 @?= Nothing+    , testCase "selectKeysRes" $ do+        let keys = [1, 2, 3]+        acquire <-+          runMockSqlQueryT+            (selectKeysRes @_ @Person [] [])+            [ mockSelectKeys $ \_ _ -> Just keys+            ]+        result <- Acquire.with acquire $ \conduit ->+          runConduit $ conduit .| Conduit.sinkList+        result @?= keys+    , testCase "count" $ do+        result <-+          runMockSqlQueryT+            (count @Person [])+            [ withRecord @Person $ \case+                Count _ -> Just 10+                _ -> Nothing+            ]+        result @?= 10+    , testCase "exists" $ do+        result <-+          runMockSqlQueryT+            (exists @Person [])+            [ withRecord @Person $ \case+                Exists _ -> Just True+                _ -> Nothing+            ]+        result @?= True+    , testCase "selectSource" $ do+        result <-+          runResourceT $+            runMockSqlQueryT+              (runConduit $ selectSource [] [] .| Conduit.mapC getName .| Conduit.sinkList)+              [ mockSelectSource $ \_ _ ->+                  Just+                    [ Entity 1 $ person "Alice"+                    , Entity 2 $ person "Bob"+                    ]+              ]+        result @?= ["Alice", "Bob"]+    , testCase "selectKeys" $ do+        let keys = [1, 2, 3]+        result <-+          runResourceT $+            runMockSqlQueryT+              (runConduit $ selectKeys @Person [] [] .| Conduit.sinkList)+              [ mockSelectKeys $ \_ _ -> Just keys+              ]+        result @?= keys+    , testCase "selectList" $ do+        result <-+          runMockSqlQueryT+            (selectList [] [])+            [ withRecord @Person $ \case+                SelectList _ _ ->+                  Just+                    [ Entity 1 (person "Alice")+                    , Entity 2 (person "Bob")+                    ]+                _ -> Nothing+            ]+        map getName result @?= ["Alice", "Bob"]+    , testCase "selectKeysList" $ do+        let keys = [1, 2, 3]+        result <-+          runMockSqlQueryT+            (selectKeysList @Person [] [])+            [ withRecord @Person $ \case+                SelectKeysList _ _ -> Just keys+                _ -> Nothing+            ]+        result @?= keys+    , testCase "updateWhere" $ do+        result <-+          runMockSqlQueryT+            (updateWhere [] [PersonAge =. 100])+            [ withRecord @Person $ \case+                UpdateWhere _ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "deleteWhere" $ do+        result <-+          runMockSqlQueryT+            (deleteWhere [PersonName ==. "Alice"])+            [ withRecord @Person $ \case+                DeleteWhere _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "updateWhereCount" $ do+        result <-+          runMockSqlQueryT+            (updateWhereCount [] [PersonAge =. 100])+            [ withRecord @Person $ \case+                UpdateWhereCount _ _ -> Just 10+                _ -> Nothing+            ]+        result @?= 10+    , testCase "deleteWhereCount" $ do+        result <-+          runMockSqlQueryT+            (deleteWhereCount [PersonName ==. "Alice"])+            [ withRecord @Person $ \case+                DeleteWhereCount _ -> Just 10+                _ -> Nothing+            ]+        result @?= 10+    , testCase "getFieldName" $ do+        result <-+          runMockSqlQueryT+            (getFieldName PersonName)+            [ withRecord @Person $ \case+                GetFieldName PersonName -> Just "\"name\""+                _ -> Nothing+            ]+        result @?= "\"name\""+    , testCase "getTableName" $ do+        result <-+          runMockSqlQueryT+            (getTableName $ person "Alice")+            [ withRecord @Person $ \case+                GetTableName _ -> Just "\"person\""+                _ -> Nothing+            ]+        result @?= "\"person\""+    , testCase "withRawQuery" $ do+        let query = "SELECT name FROM person"+            row1 = [toPersistValue @String "Alice"]+            row2 = [toPersistValue @String "Bob"]+            rows = [row1, row2]+        result <-+          runMockSqlQueryT+            (withRawQuery query [] Conduit.sinkList)+            [ mockWithRawQuery $ \sql _ ->+                if sql == query+                  then Just rows+                  else Nothing+            ]+        result @?= rows+    , testCase "rawQueryRes" $ do+        let row1 = [toPersistValue @String "Alice"]+            row2 = [toPersistValue @String "Bob"]+            rows = [row1, row2]+        acquire <-+          runMockSqlQueryT+            (rawQueryRes "SELECT name FROM person" [])+            [ mockRawQuery $ \_ _ -> Just rows+            ]+        result <- Acquire.with acquire $ \conduit ->+          runConduit $ conduit .| Conduit.sinkList+        result @?= rows+    , testCase "rawQuery" $ do+        let row1 = [toPersistValue @String "Alice"]+            row2 = [toPersistValue @String "Bob"]+            rows = [row1, row2]+        result <-+          runResourceT $+            runMockSqlQueryT+              (runConduit $ rawQuery "SELECT name FROM person" [] .| Conduit.sinkList)+              [ mockRawQuery $ \_ _ -> Just rows+              ]+        result @?= rows+    , testCase "rawExecute" $ do+        result <-+          runMockSqlQueryT+            (rawExecute "DELETE FROM person" [])+            [ mockQuery $ \case+                RawExecute _ _ -> Just ()+                _ -> Nothing+            ]+        result @?= ()+    , testCase "rawExecuteCount" $ do+        result <-+          runMockSqlQueryT+            (rawExecuteCount "DELETE FROM person" [])+            [ mockQuery $ \case+                RawExecuteCount _ _ -> Just 10+                _ -> Nothing+            ]+        result @?= 10+    , testCase "rawSql" $ do+        let names = ["Alice", "Bob"] :: [String]+        result <-+          runMockSqlQueryT+            (rawSql "SELECT name FROM person" [])+            [ mockRawSql $ \_ _ -> Just $ map ((: []) . toPersistValue) names+            ]+        map unSingle result @?= names+    ]
+ test/READMETest.hs view
@@ -0,0 +1,32 @@+{- AUTOCOLLECT.TEST -}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TypeApplications #-}++module READMETest (+  -- $AUTOCOLLECT.TEST.export$+) where++import Test.Tasty.HUnit++import Database.Persist.Monad+import Database.Persist.Monad.TestUtils+import Example++test =+  testCase "withTransaction example works" $ do+    let foo :: MonadSqlQuery m => m ()+        foo = insert_ $ person "Alice"+        bar :: MonadSqlQuery m => m ()+        bar = insert_ $ person "Bob"+        fooAndBar :: MonadSqlQuery m => m ()+        fooAndBar = withTransaction $ foo >> bar+    runMockSqlQueryT+      fooAndBar+      [ withRecord @Person $ \case+          Insert_ _ -> Just ()+          _ -> Nothing+      , withRecord @Person $ \case+          Insert_ _ -> Just ()+          _ -> Nothing+      ]
test/SqlQueryRepTest.hs view
@@ -1,6 +1,9 @@+{- AUTOCOLLECT.TEST -} {-# LANGUAGE CPP #-} -module SqlQueryRepTest where+module SqlQueryRepTest (+  -- $AUTOCOLLECT.TEST.export$+) where  import qualified Data.ByteString.Lazy.Char8 as Char8 import Test.Tasty@@ -8,32 +11,21 @@  import Generated -{-# ANN module "HLint: ignore" #-}- persistentVersionDir :: FilePath-#if MIN_VERSION_persistent(2,14,0)-persistentVersionDir = error "Running tests against persistent > 2.13 is not supported"+#if MIN_VERSION_persistent(2,15,0)+persistentVersionDir = error "Running tests against persistent > 2.14 is not supported"+#elif MIN_VERSION_persistent(2,14,0)+persistentVersionDir = "persistent-2.14/" #elif MIN_VERSION_persistent(2,13,0) persistentVersionDir = "persistent-2.13/"-#elif MIN_VERSION_persistent(2,12,0)-persistentVersionDir = "persistent-2.12/"-#elif MIN_VERSION_persistent(2,11,0)-persistentVersionDir = "persistent-2.11/"-#elif MIN_VERSION_persistent(2,10,0)-persistentVersionDir = "persistent-2.10/"-#elif MIN_VERSION_persistent(2,9,0)-persistentVersionDir = "persistent-2.9/"-#elif MIN_VERSION_persistent(2,8,0)-persistentVersionDir = "persistent-2.8/" #else-persistentVersionDir = error "Running tests against persistent < 2.8 is not supported"+persistentVersionDir = error "Running tests against persistent < 2.13 is not supported" #endif -tests :: TestTree-tests = testGroup "SqlQueryRep tests"-  [ golden "Show representation" (persistentVersionDir ++ "sqlqueryrep_show_representation.golden") $-      pure $ unlines allSqlQueryRepShowRepresentations-  ]+test =+  golden "Show representation" (persistentVersionDir ++ "sqlqueryrep_show_representation.golden") $+    pure $+      unlines allSqlQueryRepShowRepresentations  golden :: String -> FilePath -> IO String -> TestTree golden name fp action = goldenVsStringDiff name diffCmd ("test/goldens/" ++ fp) $ Char8.pack <$> action
test/TestUtils/DB.hs view
@@ -1,10 +1,10 @@ {-# LANGUAGE OverloadedStrings #-} -module TestUtils.DB-  ( BackendType(..)-  , allBackendTypes-  , withTestDB-  ) where+module TestUtils.DB (+  BackendType (..),+  allBackendTypes,+  withTestDB,+) where  import Control.Monad.Logger (runNoLoggingT) import qualified Data.ByteString.Char8 as Char8
test/TestUtils/Esqueleto.hs view
@@ -1,17 +1,11 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} -module TestUtils.Esqueleto-  ( esqueletoSelect-  ) where+module TestUtils.Esqueleto (+  esqueletoSelect,+) where -#if MIN_VERSION_esqueleto(3,5,0) import qualified Database.Esqueleto.Experimental as E import qualified Database.Esqueleto.Internal.Internal as E-#else-import qualified Database.Esqueleto as E-import qualified Database.Esqueleto.Internal.Sql as E-#endif  import Database.Persist.Monad (MonadSqlQuery, unsafeLiftSql) 
− test/goldens/persistent-2.10/sqlqueryrep_show_representation.golden
@@ -1,66 +0,0 @@-Get{..}<Person>-GetMany{..}<Person>-GetJust{..}<Person>-GetJustEntity{..}<Person>-GetEntity{..}<Person>-BelongsTo{..}<(Person,Post)>-BelongsToJust{..}<(Person,Post)>-Insert{..}<Person>-Insert_{..}<Person>-InsertMany{..}<Person>-InsertMany_{..}<Person>-InsertEntityMany{..}<Person>-InsertKey{..}<Person>-Repsert{..}<Person>-RepsertMany{..}<Person>-Replace{..}<Person>-Delete{..}<Person>-Update{..}<Person>-UpdateGet{..}<Person>-InsertEntity{..}<Person>-InsertRecord{..}<Person>-GetBy{..}<Person>-GetByValue{..}<Person>-CheckUnique{..}<Person>-DeleteBy{..}<Person>-InsertUnique{..}<Person>-Upsert{..}<Person>-UpsertBy{..}<Person>-PutMany{..}<Person>-InsertBy{..}<Person>-InsertUniqueEntity{..}<Person>-ReplaceUnique{..}<Person>-OnlyUnique{..}<Person>-SelectSourceRes{..}<Person>-SelectFirst{..}<Person>-SelectKeysRes{..}<Person>-Count{..}<Person>-SelectList{..}<Person>-SelectKeysList{..}<Person>-UpdateWhere{..}<Person>-DeleteWhere{..}<Person>-DeleteWhereCount{..}<Person>-UpdateWhereCount{..}<Person>-DeleteCascade{..}<Person>-DeleteCascadeWhere{..}<Person>-ParseMigration{..}-ParseMigration'{..}-PrintMigration{..}-ShowMigration{..}-GetMigration{..}-RunMigration{..}-RunMigrationQuiet{..}-RunMigrationSilent{..}-RunMigrationUnsafe{..}-RunMigrationUnsafeQuiet{..}-GetFieldName{..}<Person>-GetTableName{..}<Person>-WithRawQuery{..}-RawQueryRes{..}-RawExecute{..}-RawExecuteCount{..}-RawSql{..}-TransactionSave{..}-TransactionSaveWithIsolation{..}-TransactionUndo{..}-TransactionUndoWithIsolation{..}
− test/goldens/persistent-2.11/sqlqueryrep_show_representation.golden
@@ -1,68 +0,0 @@-Get{..}<Person>-GetMany{..}<Person>-GetJust{..}<Person>-GetJustEntity{..}<Person>-GetEntity{..}<Person>-BelongsTo{..}<(Person,Post)>-BelongsToJust{..}<(Person,Post)>-Insert{..}<Person>-Insert_{..}<Person>-InsertMany{..}<Person>-InsertMany_{..}<Person>-InsertEntityMany{..}<Person>-InsertKey{..}<Person>-Repsert{..}<Person>-RepsertMany{..}<Person>-Replace{..}<Person>-Delete{..}<Person>-Update{..}<Person>-UpdateGet{..}<Person>-InsertEntity{..}<Person>-InsertRecord{..}<Person>-GetBy{..}<Person>-GetByValue{..}<Person>-CheckUnique{..}<Person>-CheckUniqueUpdateable{..}<Person>-DeleteBy{..}<Person>-InsertUnique{..}<Person>-Upsert{..}<Person>-UpsertBy{..}<Person>-PutMany{..}<Person>-InsertBy{..}<Person>-InsertUniqueEntity{..}<Person>-ReplaceUnique{..}<Person>-OnlyUnique{..}<Person>-SelectSourceRes{..}<Person>-SelectFirst{..}<Person>-SelectKeysRes{..}<Person>-Count{..}<Person>-Exists{..}<Person>-SelectList{..}<Person>-SelectKeysList{..}<Person>-UpdateWhere{..}<Person>-DeleteWhere{..}<Person>-DeleteWhereCount{..}<Person>-UpdateWhereCount{..}<Person>-DeleteCascade{..}<Person>-DeleteCascadeWhere{..}<Person>-ParseMigration{..}-ParseMigration'{..}-PrintMigration{..}-ShowMigration{..}-GetMigration{..}-RunMigration{..}-RunMigrationQuiet{..}-RunMigrationSilent{..}-RunMigrationUnsafe{..}-RunMigrationUnsafeQuiet{..}-GetFieldName{..}<Person>-GetTableName{..}<Person>-WithRawQuery{..}-RawQueryRes{..}-RawExecute{..}-RawExecuteCount{..}-RawSql{..}-TransactionSave{..}-TransactionSaveWithIsolation{..}-TransactionUndo{..}-TransactionUndoWithIsolation{..}
− test/goldens/persistent-2.12/sqlqueryrep_show_representation.golden
@@ -1,68 +0,0 @@-Get{..}<Person>-GetMany{..}<Person>-GetJust{..}<Person>-GetJustEntity{..}<Person>-GetEntity{..}<Person>-BelongsTo{..}<(Person,Post)>-BelongsToJust{..}<(Person,Post)>-Insert{..}<Person>-Insert_{..}<Person>-InsertMany{..}<Person>-InsertMany_{..}<Person>-InsertEntityMany{..}<Person>-InsertKey{..}<Person>-Repsert{..}<Person>-RepsertMany{..}<Person>-Replace{..}<Person>-Delete{..}<Person>-Update{..}<Person>-UpdateGet{..}<Person>-InsertEntity{..}<Person>-InsertRecord{..}<Person>-GetBy{..}<Person>-GetByValue{..}<Person>-CheckUnique{..}<Person>-CheckUniqueUpdateable{..}<Person>-DeleteBy{..}<Person>-InsertUnique{..}<Person>-Upsert{..}<Person>-UpsertBy{..}<Person>-PutMany{..}<Person>-InsertBy{..}<Person>-InsertUniqueEntity{..}<Person>-ReplaceUnique{..}<Person>-OnlyUnique{..}<Person>-SelectSourceRes{..}<Person>-SelectFirst{..}<Person>-SelectKeysRes{..}<Person>-Count{..}<Person>-Exists{..}<Person>-SelectList{..}<Person>-SelectKeysList{..}<Person>-UpdateWhere{..}<Person>-DeleteWhere{..}<Person>-DeleteWhereCount{..}<Person>-UpdateWhereCount{..}<Person>-DeleteCascade{..}<Person>-DeleteCascadeWhere{..}<Person>-ParseMigration{..}-ParseMigration'{..}-PrintMigration{..}-ShowMigration{..}-GetMigration{..}-RunMigration{..}-RunMigrationQuiet{..}-RunMigrationSilent{..}-RunMigrationUnsafe{..}-RunMigrationUnsafeQuiet{..}-GetFieldName{..}<Person>-GetTableName{..}<Person>-WithRawQuery{..}-RawQueryRes{..}-RawExecute{..}-RawExecuteCount{..}-RawSql{..}-TransactionSave{..}-TransactionSaveWithIsolation{..}-TransactionUndo{..}-TransactionUndoWithIsolation{..}
+ test/goldens/persistent-2.14/sqlqueryrep_show_representation.golden view
@@ -0,0 +1,66 @@+Get{..}<Person>+GetMany{..}<Person>+GetJust{..}<Person>+GetJustEntity{..}<Person>+GetEntity{..}<Person>+BelongsTo{..}<(Person,Post)>+BelongsToJust{..}<(Person,Post)>+Insert{..}<Person>+Insert_{..}<Person>+InsertMany{..}<Person>+InsertMany_{..}<Person>+InsertEntityMany{..}<Person>+InsertKey{..}<Person>+Repsert{..}<Person>+RepsertMany{..}<Person>+Replace{..}<Person>+Delete{..}<Person>+Update{..}<Person>+UpdateGet{..}<Person>+InsertEntity{..}<Person>+InsertRecord{..}<Person>+GetBy{..}<Person>+GetByValue{..}<Person>+CheckUnique{..}<Person>+CheckUniqueUpdateable{..}<Person>+DeleteBy{..}<Person>+InsertUnique{..}<Person>+Upsert{..}<Person>+UpsertBy{..}<Person>+PutMany{..}<Person>+InsertBy{..}<Person>+InsertUniqueEntity{..}<Person>+ReplaceUnique{..}<Person>+OnlyUnique{..}<Person>+SelectSourceRes{..}<Person>+SelectFirst{..}<Person>+SelectKeysRes{..}<Person>+Count{..}<Person>+Exists{..}<Person>+SelectList{..}<Person>+SelectKeysList{..}<Person>+UpdateWhere{..}<Person>+DeleteWhere{..}<Person>+DeleteWhereCount{..}<Person>+UpdateWhereCount{..}<Person>+ParseMigration{..}+ParseMigration'{..}+PrintMigration{..}+ShowMigration{..}+GetMigration{..}+RunMigration{..}+RunMigrationQuiet{..}+RunMigrationSilent{..}+RunMigrationUnsafe{..}+RunMigrationUnsafeQuiet{..}+GetFieldName{..}<Person>+GetTableName{..}<Person>+WithRawQuery{..}+RawQueryRes{..}+RawExecute{..}+RawExecuteCount{..}+RawSql{..}+TransactionSave{..}+TransactionSaveWithIsolation{..}+TransactionUndo{..}+TransactionUndoWithIsolation{..}
− test/goldens/persistent-2.8/sqlqueryrep_show_representation.golden
@@ -1,62 +0,0 @@-Get{..}<Person>-GetMany{..}<Person>-GetJust{..}<Person>-GetJustEntity{..}<Person>-GetEntity{..}<Person>-BelongsTo{..}<(Person,Post)>-BelongsToJust{..}<(Person,Post)>-Insert{..}<Person>-Insert_{..}<Person>-InsertMany{..}<Person>-InsertMany_{..}<Person>-InsertEntityMany{..}<Person>-InsertKey{..}<Person>-Repsert{..}<Person>-RepsertMany{..}<Person>-Replace{..}<Person>-Delete{..}<Person>-Update{..}<Person>-UpdateGet{..}<Person>-InsertEntity{..}<Person>-InsertRecord{..}<Person>-GetBy{..}<Person>-GetByValue{..}<Person>-CheckUnique{..}<Person>-DeleteBy{..}<Person>-InsertUnique{..}<Person>-Upsert{..}<Person>-UpsertBy{..}<Person>-PutMany{..}<Person>-InsertBy{..}<Person>-InsertUniqueEntity{..}<Person>-ReplaceUnique{..}<Person>-OnlyUnique{..}<Person>-SelectSourceRes{..}<Person>-SelectFirst{..}<Person>-SelectKeysRes{..}<Person>-Count{..}<Person>-SelectList{..}<Person>-SelectKeysList{..}<Person>-UpdateWhere{..}<Person>-DeleteWhere{..}<Person>-DeleteWhereCount{..}<Person>-UpdateWhereCount{..}<Person>-DeleteCascade{..}<Person>-DeleteCascadeWhere{..}<Person>-ParseMigration{..}-ParseMigration'{..}-PrintMigration{..}-ShowMigration{..}-GetMigration{..}-RunMigration{..}-RunMigrationSilent{..}-RunMigrationUnsafe{..}-GetFieldName{..}<Person>-GetTableName{..}<Person>-WithRawQuery{..}-RawQueryRes{..}-RawExecute{..}-RawExecuteCount{..}-RawSql{..}-TransactionSave{..}-TransactionUndo{..}
− test/goldens/persistent-2.9/sqlqueryrep_show_representation.golden
@@ -1,64 +0,0 @@-Get{..}<Person>-GetMany{..}<Person>-GetJust{..}<Person>-GetJustEntity{..}<Person>-GetEntity{..}<Person>-BelongsTo{..}<(Person,Post)>-BelongsToJust{..}<(Person,Post)>-Insert{..}<Person>-Insert_{..}<Person>-InsertMany{..}<Person>-InsertMany_{..}<Person>-InsertEntityMany{..}<Person>-InsertKey{..}<Person>-Repsert{..}<Person>-RepsertMany{..}<Person>-Replace{..}<Person>-Delete{..}<Person>-Update{..}<Person>-UpdateGet{..}<Person>-InsertEntity{..}<Person>-InsertRecord{..}<Person>-GetBy{..}<Person>-GetByValue{..}<Person>-CheckUnique{..}<Person>-DeleteBy{..}<Person>-InsertUnique{..}<Person>-Upsert{..}<Person>-UpsertBy{..}<Person>-PutMany{..}<Person>-InsertBy{..}<Person>-InsertUniqueEntity{..}<Person>-ReplaceUnique{..}<Person>-OnlyUnique{..}<Person>-SelectSourceRes{..}<Person>-SelectFirst{..}<Person>-SelectKeysRes{..}<Person>-Count{..}<Person>-SelectList{..}<Person>-SelectKeysList{..}<Person>-UpdateWhere{..}<Person>-DeleteWhere{..}<Person>-DeleteWhereCount{..}<Person>-UpdateWhereCount{..}<Person>-DeleteCascade{..}<Person>-DeleteCascadeWhere{..}<Person>-ParseMigration{..}-ParseMigration'{..}-PrintMigration{..}-ShowMigration{..}-GetMigration{..}-RunMigration{..}-RunMigrationSilent{..}-RunMigrationUnsafe{..}-GetFieldName{..}<Person>-GetTableName{..}<Person>-WithRawQuery{..}-RawQueryRes{..}-RawExecute{..}-RawExecuteCount{..}-RawSql{..}-TransactionSave{..}-TransactionSaveWithIsolation{..}-TransactionUndo{..}-TransactionUndoWithIsolation{..}