packages feed

beam-postgres 0.4.0.0 → 0.5.0.0

raw patch · 21 files changed

+707/−359 lines, 21 filesdep +tmp-postgresdep −directorydep −filepathdep −processdep ~aesondep ~basedep ~beam-corePVP ok

version bump matches the API change (PVP)

Dependencies added: tmp-postgres

Dependencies removed: directory, filepath, process, temporary

Dependency ranges changed: aeson, base, beam-core, beam-migrate, hashable, haskell-src-exts, vector

API changes (from Hackage documentation)

- Database.Beam.Postgres.Full: PgConflictAction :: (tbl (QField PostgresInaccessible) -> PgConflictActionSyntax) -> PgConflictAction
- Database.Beam.Postgres.Full: PgInsertOnConflictTarget :: (tbl (QExpr Postgres PostgresInaccessible) -> PgInsertOnConflictTargetSyntax) -> PgInsertOnConflictTarget
- Database.Beam.Postgres.Full: newtype PgConflictAction (tbl :: (* -> *) -> *)
- Database.Beam.Postgres.Full: newtype PgInsertOnConflictTarget (tbl :: (* -> *) -> *)
- Database.Beam.Postgres.Full: onConflictSetAll :: (Beamable tbl, ProjectibleWithPredicate AnyType () Text (tbl (Const Text))) => PgConflictAction tbl
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Types.Int
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Types.Word
+ Database.Beam.Postgres: (!~*.) :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (!~.) :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (~*.) :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (~.) :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: PgRegex :: Text -> PgRegex
+ Database.Beam.Postgres: fromPgIntegral :: forall a. (FromField a, Integral a, Typeable a) => FromBackendRowM Postgres a
+ Database.Beam.Postgres: fromPgScientificOrIntegral :: (Bounded a, Integral a) => FromBackendRowM Postgres a
+ Database.Beam.Postgres: liftIOWithHandle :: (Connection -> IO a) -> Pg a
+ Database.Beam.Postgres: newtype PgRegex
+ Database.Beam.Postgres: pgArrayToJson :: QGenExpr ctxt Postgres s (Vector e) -> QGenExpr ctxt Postgres s (PgJSON a)
+ Database.Beam.Postgres: pgRegex_ :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex
+ Database.Beam.Postgres: pgRegexpMatch_ :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s (Maybe (Vector text))
+ Database.Beam.Postgres: pgRegexpReplace_ :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s txt
+ Database.Beam.Postgres: pgRegexpSplitToArray :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> QGenExpr ctxt Postgres s (Vector text)
+ Database.Beam.Postgres: pgRegexpSplitToTable :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex -> Q Postgres db s (QExpr Postgres s Text)
+ Database.Beam.Postgres.Extensions.UuidOssp: UuidOssp :: (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s (UUID -> Text -> UUID)) -> (forall ctxt s. LiftPg ctxt s UUID) -> (forall ctxt s. LiftPg ctxt s (UUID -> Text -> UUID)) -> UuidOssp
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidGenerateV1Mc] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidGenerateV1] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidGenerateV3] :: UuidOssp -> forall ctxt s. LiftPg ctxt s (UUID -> Text -> UUID)
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidGenerateV4] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidGenerateV5] :: UuidOssp -> forall ctxt s. LiftPg ctxt s (UUID -> Text -> UUID)
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidNil] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidNsDns] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidNsOid] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidNsUrl] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: [pgUuidNsX500] :: UuidOssp -> forall ctxt s. LiftPg ctxt s UUID
+ Database.Beam.Postgres.Extensions.UuidOssp: data UuidOssp
+ Database.Beam.Postgres.Extensions.UuidOssp: instance Database.Beam.Postgres.Extensions.IsPgExtension Database.Beam.Postgres.Extensions.UuidOssp.UuidOssp
+ Database.Beam.Postgres.Full: -- table <tt>tbl</tt> that violates a constraint.
+ Database.Beam.Postgres.Full: -- to occur
+ Database.Beam.Postgres.Full: -- | What to do when an <tt>INSERT</tt> statement inserts a row into the
+ Database.Beam.Postgres.Full: class BeamSqlBackend be => BeamHasInsertOnConflict be where {
+ Database.Beam.Postgres.Full: data family SqlConflictAction be (table :: Type -> Type -> Type) :: Type;
+ Database.Beam.Postgres.Full: insertOnConflict :: (BeamHasInsertOnConflict be, Beamable table) => DatabaseEntity be db (TableEntity table) -> SqlInsertValues be (table (QExpr be s)) -> SqlConflictTarget be table -> SqlConflictAction be table -> SqlInsert be table
+ Database.Beam.Postgres.Full: instance Database.Beam.Backend.SQL.BeamExtensions.BeamHasInsertOnConflict Database.Beam.Postgres.Types.Postgres
+ Database.Beam.Postgres.Full: onConflictUpdateAll :: (BeamHasInsertOnConflict be, Beamable table) => SqlConflictAction be table
+ Database.Beam.Postgres.Migrate: getDbConstraintsForSchemas :: Maybe [String] -> Connection -> IO [SomeDatabasePredicate]
+ Database.Beam.Postgres.Syntax: instance (TypeError ...) => Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Types.Int
+ Database.Beam.Postgres.Syntax: instance (TypeError ...) => Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Types.Word
- Database.Beam.Postgres: (->#) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int -> QGenExpr ctxt Postgres s (json b)
+ Database.Beam.Postgres: (->#) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int32 -> QGenExpr ctxt Postgres s (json b)
- Database.Beam.Postgres: (->>#) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int -> QGenExpr ctxt Postgres s Text
+ Database.Beam.Postgres: (->>#) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int32 -> QGenExpr ctxt Postgres s Text
- Database.Beam.Postgres: (<@) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s (json b) -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (<@) :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s (PgJSONB b) -> QGenExpr ctxt Postgres s Bool
- Database.Beam.Postgres: (?&) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s (Vector Text) -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (?&) :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s (Vector Text) -> QGenExpr ctxt Postgres s Bool
- Database.Beam.Postgres: (?) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (?) :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s Bool
- Database.Beam.Postgres: (?|) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s (Vector Text) -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (?|) :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s (Vector Text) -> QGenExpr ctxt Postgres s Bool
- Database.Beam.Postgres: (@>) :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s (json b) -> QGenExpr ctxt Postgres s Bool
+ Database.Beam.Postgres: (@>) :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s (PgJSONB b) -> QGenExpr ctxt Postgres s Bool
- Database.Beam.Postgres: pgJsonArrayLength :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int
+ Database.Beam.Postgres: pgJsonArrayLength :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int32
- Database.Beam.Postgres: pgUnnestArrayWithOrdinality :: QExpr Postgres s (Vector a) -> Q Postgres db s (QExpr Postgres s Int, QExpr Postgres s a)
+ Database.Beam.Postgres: pgUnnestArrayWithOrdinality :: QExpr Postgres s (Vector a) -> Q Postgres db s (QExpr Postgres s Int64, QExpr Postgres s a)
- Database.Beam.Postgres: withoutIdx :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Int -> QGenExpr ctxt Postgres s (json b)
+ Database.Beam.Postgres: withoutIdx :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s Int32 -> QGenExpr ctxt Postgres s (PgJSONB b)
- Database.Beam.Postgres: withoutKey :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s (json b)
+ Database.Beam.Postgres: withoutKey :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s (PgJSONB b)
- Database.Beam.Postgres: withoutKeys :: IsPgJSON json => QGenExpr ctxt Postgres s (json a) -> QGenExpr ctxt Postgres s (Vector Text) -> QGenExpr ctxt Postgres s (json b)
+ Database.Beam.Postgres: withoutKeys :: QGenExpr ctxt Postgres s (PgJSONB a) -> QGenExpr ctxt Postgres s (Vector Text) -> QGenExpr ctxt Postgres s (PgJSONB b)
- Database.Beam.Postgres.Conduit: runDeleteReturning :: (MonadIO m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> PgDeleteReturning a -> (ConduitT () a m () -> m b) -> m b
+ Database.Beam.Postgres.Conduit: runDeleteReturning :: (MonadIO m, MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> PgDeleteReturning a -> (ConduitT () a m () -> m b) -> m b
- Database.Beam.Postgres.Conduit: runInsertReturning :: (MonadIO m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> PgInsertReturning a -> (ConduitT () a m () -> m b) -> m b
+ Database.Beam.Postgres.Conduit: runInsertReturning :: (MonadIO m, MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> PgInsertReturning a -> (ConduitT () a m () -> m b) -> m b
- Database.Beam.Postgres.Conduit: runQueryReturning :: (MonadIO m, MonadBaseControl IO m, Functor m, FromBackendRow Postgres r) => Connection -> PgSyntax -> (ConduitT () r m () -> m b) -> m b
+ Database.Beam.Postgres.Conduit: runQueryReturning :: (MonadIO m, MonadFail m, MonadBaseControl IO m, Functor m, FromBackendRow Postgres r) => Connection -> PgSyntax -> (ConduitT () r m () -> m b) -> m b
- Database.Beam.Postgres.Conduit: runSelect :: (MonadIO m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> SqlSelect Postgres a -> (ConduitT () a m () -> m b) -> m b
+ Database.Beam.Postgres.Conduit: runSelect :: (MonadIO m, MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> SqlSelect Postgres a -> (ConduitT () a m () -> m b) -> m b
- Database.Beam.Postgres.Conduit: runUpdateReturning :: (MonadIO m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> PgUpdateReturning a -> (ConduitT () a m () -> m b) -> m b
+ Database.Beam.Postgres.Conduit: runUpdateReturning :: (MonadIO m, MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a) => Connection -> PgUpdateReturning a -> (ConduitT () a m () -> m b) -> m b
- Database.Beam.Postgres.Full: PgInsertOnConflict :: (tbl (QField PostgresInaccessible) -> PgInsertOnConflictSyntax) -> PgInsertOnConflict
+ Database.Beam.Postgres.Full: PgInsertOnConflict :: (tbl (QField QInternal) -> PgInsertOnConflictSyntax) -> PgInsertOnConflict
- Database.Beam.Postgres.Full: anyConflict :: PgInsertOnConflictTarget tbl
+ Database.Beam.Postgres.Full: anyConflict :: BeamHasInsertOnConflict be => SqlConflictTarget be table
- Database.Beam.Postgres.Full: conflictingConstraint :: Text -> PgInsertOnConflictTarget tbl
+ Database.Beam.Postgres.Full: conflictingConstraint :: Text -> SqlConflictTarget Postgres tbl
- Database.Beam.Postgres.Full: conflictingFields :: Projectible Postgres proj => (tbl (QExpr Postgres PostgresInaccessible) -> proj) -> PgInsertOnConflictTarget tbl
+ Database.Beam.Postgres.Full: conflictingFields :: (BeamHasInsertOnConflict be, Projectible be proj) => (table (QExpr be QInternal) -> proj) -> SqlConflictTarget be table
- Database.Beam.Postgres.Full: conflictingFieldsWhere :: Projectible Postgres proj => (tbl (QExpr Postgres PostgresInaccessible) -> proj) -> (tbl (QExpr Postgres PostgresInaccessible) -> QExpr Postgres PostgresInaccessible Bool) -> PgInsertOnConflictTarget tbl
+ Database.Beam.Postgres.Full: conflictingFieldsWhere :: (BeamHasInsertOnConflict be, Projectible be proj) => (table (QExpr be QInternal) -> proj) -> (forall s. () => table (QExpr be s) -> QExpr be s Bool) -> SqlConflictTarget be table
- Database.Beam.Postgres.Full: onConflict :: Beamable tbl => PgInsertOnConflictTarget tbl -> PgConflictAction tbl -> PgInsertOnConflict tbl
+ Database.Beam.Postgres.Full: onConflict :: Beamable tbl => SqlConflictTarget Postgres tbl -> SqlConflictAction Postgres tbl -> PgInsertOnConflict tbl
- Database.Beam.Postgres.Full: onConflictDoNothing :: PgConflictAction tbl
+ Database.Beam.Postgres.Full: onConflictDoNothing :: BeamHasInsertOnConflict be => SqlConflictAction be table
- Database.Beam.Postgres.Full: onConflictUpdateInstead :: (Beamable tbl, ProjectibleWithPredicate AnyType () Text proj) => (tbl (Const Text) -> proj) -> PgConflictAction tbl
+ Database.Beam.Postgres.Full: onConflictUpdateInstead :: (BeamHasInsertOnConflict be, Beamable table, ProjectibleWithPredicate AnyType () (InaccessibleQAssignment be) proj) => (table (Const (InaccessibleQAssignment be) :: Type -> Type) -> proj) -> SqlConflictAction be table
- Database.Beam.Postgres.Full: onConflictUpdateSet :: Beamable tbl => (tbl (QField PostgresInaccessible) -> tbl (QExpr Postgres PostgresInaccessible) -> QAssignment Postgres PostgresInaccessible) -> PgConflictAction tbl
+ Database.Beam.Postgres.Full: onConflictUpdateSet :: (BeamHasInsertOnConflict be, Beamable table) => (forall s. () => table (QField s) -> table (QExpr be s) -> QAssignment be s) -> SqlConflictAction be table
- Database.Beam.Postgres.Full: onConflictUpdateSetWhere :: Beamable tbl => (tbl (QField PostgresInaccessible) -> tbl (QExpr Postgres PostgresInaccessible) -> QAssignment Postgres PostgresInaccessible) -> (tbl (QExpr Postgres PostgresInaccessible) -> QExpr Postgres PostgresInaccessible Bool) -> PgConflictAction tbl
+ Database.Beam.Postgres.Full: onConflictUpdateSetWhere :: (BeamHasInsertOnConflict be, Beamable table) => (forall s. () => table (QField s) -> table (QExpr be s) -> QAssignment be s) -> (forall s. () => table (QField s) -> table (QExpr be s) -> QExpr be s Bool) -> SqlConflictAction be table
- Database.Beam.Postgres.PgCrypto: PgCrypto :: (forall ctxt s. LiftPg ctxt s (Text -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (Text -> Text -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (Text -> Text -> Text)) -> (forall ctxt s. LiftPg ctxt s (Text -> Maybe Int -> Text)) -> (forall ctxt s. LiftPg ctxt s (Text -> Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Maybe Text -> Text)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (Text -> ByteString -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> ByteString -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> ByteString -> Maybe Text -> Maybe Text -> Text)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> ByteString -> Maybe Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text)) -> (forall ctxt s. PgExpr ctxt s ByteString -> Maybe (PgExpr ctxt s (Vector Text), PgExpr ctxt s (Vector Text)) -> PgExpr ctxt s Text) -> (forall ctxt s. LiftPg ctxt s (Text -> ByteString)) -> (forall ctxt s i. Integral i => PgExpr ctxt s i -> PgExpr ctxt s ByteString) -> (forall ctxt s. PgExpr ctxt s UUID) -> PgCrypto
+ Database.Beam.Postgres.PgCrypto: PgCrypto :: (forall ctxt s. LiftPg ctxt s (Text -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (Text -> Text -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (Text -> Text -> Text)) -> (forall ctxt s. LiftPg ctxt s (Text -> Maybe Int32 -> Text)) -> (forall ctxt s. LiftPg ctxt s (Text -> Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Maybe Text -> Text)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (Text -> ByteString -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> ByteString -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> ByteString -> Maybe Text -> Maybe Text -> Text)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> ByteString -> Maybe Text -> Maybe Text -> ByteString)) -> (forall ctxt s. LiftPg ctxt s (ByteString -> Text)) -> (forall ctxt s. PgExpr ctxt s ByteString -> Maybe (PgExpr ctxt s (Vector Text), PgExpr ctxt s (Vector Text)) -> PgExpr ctxt s Text) -> (forall ctxt s. LiftPg ctxt s (Text -> ByteString)) -> (forall ctxt s i. Integral i => PgExpr ctxt s i -> PgExpr ctxt s ByteString) -> (forall ctxt s. PgExpr ctxt s UUID) -> PgCrypto
- Database.Beam.Postgres.PgCrypto: [pgCryptoGenSalt] :: PgCrypto -> forall ctxt s. LiftPg ctxt s (Text -> Maybe Int -> Text)
+ Database.Beam.Postgres.PgCrypto: [pgCryptoGenSalt] :: PgCrypto -> forall ctxt s. LiftPg ctxt s (Text -> Maybe Int32 -> Text)

Files

ChangeLog.md view
@@ -1,3 +1,33 @@+# 0.5.0.0++## Interface changes++ * Removed instances for machine-dependent ambiguous integer types `Int` and `Word`+ * Fixed types for some functions that only work with `jsonb` and not `json`++## Added features++ * Support for `in_` on row values+ * Various Postgres regex functions+ * Expose `fromPgIntegral` and `fromPgScientificOrIntegral`+ * Add `liftIOWithHandle :: (Connection -> IO a) -> Pg a`+ * Add `getDbConstraintsForSchemas` to get constraints without relying on the state of the connection+ * Poly-kinded instances for `Data.Tagged.Tagged`+ * Add `HasDefaultDatatype` for `UTCTime`+ * Support for specifically-sized `SqlSerial` integers (`smallserial`, `serial`, `bigserial`)+ * Predicate detection for extensions+ * `pgArrayToJson` for `array_to_json`+ * Extension definition and all functions provided by `uuid-ossp`+ * GHC 8.8 support++## Bug fixes++ * Only detect primary keys of tables in visible schemas+ * Fix emitting of `DECIMAL` type+ * Report JSON correct decoding errors instead of throwing `UnexpectedNull`++# 0.4.0.0+ # 0.3.2.0  Add `Semigroup` instances to prepare for GHC 8.4 and Stackage nightly
Database/Beam/Postgres.hs view
@@ -15,11 +15,11 @@ -- <https://www.postgresql.org/docs/current/static/index.html behavior>. -- -- For examples on how to use @beam-postgres@ usage, see--- <http://tathougies.github.io/beam/user-guide/backends/beam-postgres/ its manual>.+-- <https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres/ its manual>.  module Database.Beam.Postgres   (  -- * Beam Postgres backend-    Postgres(..), Pg+    Postgres(..), Pg, liftIOWithHandle      -- ** Postgres syntax   , PgCommandSyntax, PgSyntax@@ -48,6 +48,10 @@   , pgCreateExtension, pgDropExtension   , getPgExtension +    -- ** Utilities for defining custom instances+  , fromPgIntegral+  , fromPgScientificOrIntegral+     -- ** Debug support    , PgDebugStmt@@ -67,7 +71,8 @@   ) where  import Database.Beam.Postgres.Connection-import Database.Beam.Postgres.Syntax hiding (PostgresInaccessible)+import Database.Beam.Postgres.Full () -- for BeamHasInsertOnConflict instance+import Database.Beam.Postgres.Syntax import Database.Beam.Postgres.Types import Database.Beam.Postgres.PgSpecific import Database.Beam.Postgres.Migrate ( tsquery, tsvector, text, bytea, unboundedArray
Database/Beam/Postgres/Conduit.hs view
@@ -29,6 +29,8 @@ import           Data.Semigroup #endif +import qualified Control.Monad.Fail as Fail+ #if MIN_VERSION_conduit(1,3,0) #define CONDUIT_TRANSFORMER C.ConduitT #else@@ -38,7 +40,7 @@ -- * @SELECT@  -- | Run a PostgreSQL @SELECT@ statement in any 'MonadIO'.-runSelect :: ( MonadIO m,  MonadBaseControl IO m, FromBackendRow Postgres a )+runSelect :: ( MonadIO m, Fail.MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a )           => Pg.Connection -> SqlSelect Postgres a           -> (CONDUIT_TRANSFORMER () a m () -> m b) -> m b runSelect conn (SqlSelect (PgSelectSyntax syntax)) withSrc =@@ -56,7 +58,7 @@  -- | Run a PostgreSQL @INSERT ... RETURNING ...@ statement in any 'MonadIO' and -- get a 'C.Source' of the newly inserted rows.-runInsertReturning :: ( MonadIO m,  MonadBaseControl IO m, FromBackendRow Postgres a )+runInsertReturning :: ( MonadIO m, Fail.MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a )                    => Pg.Connection                    -> PgInsertReturning a                    -> (CONDUIT_TRANSFORMER () a m () -> m b)@@ -77,7 +79,7 @@  -- | Run a PostgreSQL @UPDATE ... RETURNING ...@ statement in any 'MonadIO' and -- get a 'C.Source' of the newly updated rows.-runUpdateReturning :: ( MonadIO m, MonadBaseControl IO m, FromBackendRow Postgres a)+runUpdateReturning :: ( MonadIO m, Fail.MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a)                    => Pg.Connection                    -> PgUpdateReturning a                    -> (CONDUIT_TRANSFORMER () a m () -> m b)@@ -98,7 +100,7 @@  -- | Run a PostgreSQl @DELETE ... RETURNING ...@ statement in any -- 'MonadIO' and get a 'C.Source' of the deleted rows.-runDeleteReturning :: ( MonadIO m, MonadBaseControl IO m, FromBackendRow Postgres a )+runDeleteReturning :: ( MonadIO m, Fail.MonadFail m, MonadBaseControl IO m, FromBackendRow Postgres a )                    => Pg.Connection -> PgDeleteReturning a                    -> (CONDUIT_TRANSFORMER () a m () -> m b) -> m b runDeleteReturning conn (PgDeleteReturning d) withSrc =@@ -115,7 +117,7 @@  -- | Runs any query that returns a set of values runQueryReturning-  :: ( MonadIO m, MonadBaseControl IO m, Functor m, FromBackendRow Postgres r )+  :: ( MonadIO m, Fail.MonadFail m, MonadBaseControl IO m, Functor m, FromBackendRow Postgres r )   => Pg.Connection -> PgSyntax   -> (CONDUIT_TRANSFORMER () r m () -> m b)   -> m b@@ -130,10 +132,10 @@       singleRowModeSet <- liftIO (Pg.withConnection conn Pg.setSingleRowMode)       if singleRowModeSet          then withSrc (streamResults Nothing) `finally` gracefulShutdown-         else fail "Could not enable single row mode"+         else Fail.fail "Could not enable single row mode"     else do       errMsg <- fromMaybe "No libpq error provided" <$> liftIO (Pg.withConnection conn Pg.errorMessage)-      fail (show errMsg)+      Fail.fail (show errMsg)    where     streamResults fields = do@@ -152,15 +154,15 @@                      do C.yield parsedRow'                         streamResults (Just fields')             Pg.TuplesOk -> liftIO (Pg.withConnection conn finishQuery)-            Pg.EmptyQuery -> fail "No query"+            Pg.EmptyQuery -> Fail.fail "No query"             Pg.CommandOk -> pure ()             _ -> do errMsg <- liftIO (Pg.resultErrorMessage row)-                    fail ("Postgres error: " <> show errMsg)+                    Fail.fail ("Postgres error: " <> show errMsg)      bailEarly row errorString = do       Pg.unsafeFreeResult row       Pg.withConnection conn $ cancelQuery-      fail errorString+      Fail.fail errorString      cancelQuery conn' = do       cancel <- Pg.getCancel conn'@@ -170,7 +172,7 @@           res <- Pg.cancel cancel'           case res of             Right () -> liftIO (finishQuery conn')-            Left err -> fail ("Could not cancel: " <> show err)+            Left err -> Fail.fail ("Could not cancel: " <> show err)      finishQuery conn' = do       nextRow <- Pg.getResult conn'
Database/Beam/Postgres/Connection.hs view
@@ -15,6 +15,8 @@ module Database.Beam.Postgres.Connection   ( Pg(..), PgF(..) +  , liftIOWithHandle+   , runBeamPostgres, runBeamPostgresDebug    , pgRenderSyntax, runPgRowReader, getFields@@ -32,7 +34,6 @@ import           Database.Beam.Backend.SQL.Row ( FromBackendRowF(..), FromBackendRowM(..)                                                , BeamRowReadError(..), ColumnParseError(..) ) import           Database.Beam.Backend.URI-import           Database.Beam.Query.Types (QGenExpr(..)) import           Database.Beam.Schema.Tables  import           Database.Beam.Postgres.Syntax@@ -53,7 +54,6 @@  import           Control.Monad.Reader import           Control.Monad.State-import           Control.Monad.Fail (MonadFail) import qualified Control.Monad.Fail as Fail  import           Data.ByteString (ByteString)@@ -64,11 +64,7 @@ import           Data.String import qualified Data.Text as T import           Data.Text.Encoding (decodeUtf8)-#if MIN_VERSION_base(4,12,0) import           Data.Typeable (cast)-#else-import           Data.Typeable (cast, typeOf)-#endif #if !MIN_VERSION_base(4, 11, 0) import           Data.Semigroup #endif@@ -188,7 +184,8 @@       step (PgLiftIO io next) = io >>= next       step (PgLiftWithHandle withConn next) = withConn conn >>= next       step (PgFetchNext next) = next Nothing-      step (PgRunReturning (PgCommandSyntax PgCommandTypeQuery syntax)+      step (PgRunReturning CursorBatching+                           (PgCommandSyntax PgCommandTypeQuery syntax)                            (mkProcess :: Pg (Maybe x) -> Pg a')                            next) =         do query <- pgRenderSyntax conn syntax@@ -205,31 +202,39 @@                     columnCount = fromIntegral $ valuesNeeded (Proxy @Postgres) (Proxy @x)                in Pg.foldWith_ (Pg.RP (put columnCount >> ask)) conn (Pg.Query query) (PgStreamContinue nextStream) runConsumer >>= finishUp-      step (PgRunReturning (PgCommandSyntax PgCommandTypeDataUpdateReturning syntax) mkProcess next) =+      step (PgRunReturning AtOnce+                           (PgCommandSyntax PgCommandTypeQuery syntax)+                           (mkProcess :: Pg (Maybe x) -> Pg a')+                           next) =+        renderExecReturningList "No tuples returned to Postgres query" syntax mkProcess next+      step (PgRunReturning _ (PgCommandSyntax PgCommandTypeDataUpdateReturning syntax) mkProcess next) =+        renderExecReturningList "No tuples returned to Postgres update/insert returning" syntax mkProcess next+      step (PgRunReturning _ (PgCommandSyntax _ syntax) mkProcess next) =         do query <- pgRenderSyntax conn syntax            dbg (T.unpack (decodeUtf8 query))+           _ <- Pg.execute_ conn (Pg.Query query) +           let Pg process = mkProcess (Pg (liftF (PgFetchNext id)))+           runF process next stepReturningNone++      renderExecReturningList :: (FromBackendRow Postgres x) => _ -> PgSyntax -> (Pg (Maybe x) -> Pg a') -> _ -> _+      renderExecReturningList errMsg syntax mkProcess next =+        do query <- pgRenderSyntax conn syntax+           dbg (T.unpack (decodeUtf8 query))+            res <- Pg.exec conn query            sts <- Pg.resultStatus res            case sts of              Pg.TuplesOk -> do                let Pg process = mkProcess (Pg (liftF (PgFetchNext id)))                runF process (\x _ -> Pg.unsafeFreeResult res >> next x) (stepReturningList res) 0-             _ -> Pg.throwResultError "No tuples returned to Postgres update/insert returning"-                                      res sts-      step (PgRunReturning (PgCommandSyntax _ syntax) mkProcess next) =-        do query <- pgRenderSyntax conn syntax-           dbg (T.unpack (decodeUtf8 query))-           _ <- Pg.execute_ conn (Pg.Query query)--           let Pg process = mkProcess (Pg (liftF (PgFetchNext id)))-           runF process next stepReturningNone+             _ -> Pg.throwResultError errMsg res sts        stepReturningNone :: forall a. PgF (IO (Either BeamRowReadError a)) -> IO (Either BeamRowReadError a)       stepReturningNone (PgLiftIO action' next) = action' >>= next       stepReturningNone (PgLiftWithHandle withConn next) = withConn conn >>= next       stepReturningNone (PgFetchNext next) = next Nothing-      stepReturningNone (PgRunReturning _ _ _) = pure (Left (BeamRowReadError Nothing (ColumnErrorInternal  "Nested queries not allowed")))+      stepReturningNone (PgRunReturning {}) = pure (Left (BeamRowReadError Nothing (ColumnErrorInternal  "Nested queries not allowed")))        stepReturningList :: forall a. Pg.Result -> PgF (CInt -> IO (Either BeamRowReadError a)) -> CInt -> IO (Either BeamRowReadError a)       stepReturningList _   (PgLiftIO action' next) rowIdx = action' >>= \x -> next x rowIdx@@ -241,7 +246,7 @@              else runPgRowReader conn (Pg.Row rowIdx) res fields fromBackendRow >>= \case                     Left err -> pure (Left err)                     Right r -> next (Just r) (rowIdx + 1)-      stepReturningList _   (PgRunReturning _ _ _) _ = pure (Left (BeamRowReadError Nothing (ColumnErrorInternal "Nested queries not allowed")))+      stepReturningList _   (PgRunReturning {}) _ = pure (Left (BeamRowReadError Nothing (ColumnErrorInternal "Nested queries not allowed")))       stepReturningList _   (PgLiftWithHandle {}) _ = pure (Left (BeamRowReadError Nothing (ColumnErrorInternal "Nested queries not allowed")))        finishProcess :: forall a. a -> Maybe PgI.Row -> IO (PgStream a)@@ -263,7 +268,7 @@         runPgRowReader conn rowIdx res fields fromBackendRow >>= \case           Left err -> pure (PgStreamDone (Left err))           Right r -> pure (PgStreamContinue (next (Just r)))-      stepProcess (PgRunReturning _ _ _) _ = pure (PgStreamDone (Left (BeamRowReadError Nothing (ColumnErrorInternal "Nested queries not allowed"))))+      stepProcess (PgRunReturning {}) _ = pure (PgStreamDone (Left (BeamRowReadError Nothing (ColumnErrorInternal "Nested queries not allowed"))))       stepProcess (PgLiftWithHandle _ _) _ = pure (PgStreamDone (Left (BeamRowReadError Nothing (ColumnErrorInternal "Nested queries not allowed"))))        runConsumer :: forall a. PgStream a -> PgI.Row -> IO (PgStream a)@@ -277,13 +282,18 @@     PgLiftIO :: IO a -> (a -> next) -> PgF next     PgRunReturning ::         FromBackendRow Postgres x =>-        PgCommandSyntax -> (Pg (Maybe x) -> Pg a) -> (a -> next) -> PgF next+        FetchMode -> PgCommandSyntax -> (Pg (Maybe x) -> Pg a) -> (a -> next) -> PgF next     PgFetchNext ::         FromBackendRow Postgres x =>         (Maybe x -> next) -> PgF next     PgLiftWithHandle :: (Pg.Connection -> IO a) -> (a -> next) -> PgF next deriving instance Functor PgF +-- | How to fetch results.+data FetchMode+    = CursorBatching -- ^ Fetch in batches of ~256 rows via cursor for SELECT.+    | AtOnce         -- ^ Fetch all rows at once.+ -- | 'MonadBeam' in which we can run Postgres commands. See the documentation -- for 'MonadBeam' on examples of how to use. --@@ -293,12 +303,15 @@ newtype Pg a = Pg { runPg :: F PgF a }     deriving (Monad, Applicative, Functor, MonadFree PgF) -instance MonadFail Pg where-    fail e = fail $ "Internal Error with: " <> show e+instance Fail.MonadFail Pg where+    fail e =  liftIO (Fail.fail $ "Internal Error with: " <> show e)  instance MonadIO Pg where     liftIO x = liftF (PgLiftIO x id) +liftIOWithHandle :: (Pg.Connection -> IO a) -> Pg a+liftIOWithHandle f = liftF (PgLiftWithHandle f id)+ runBeamPostgresDebug :: (String -> IO ()) -> Pg.Connection -> Pg a -> IO a runBeamPostgresDebug dbg conn action =     withPgDebug dbg conn action >>= either throwIO pure@@ -308,7 +321,31 @@  instance MonadBeam Postgres Pg where     runReturningMany cmd consume =-        liftF (PgRunReturning cmd consume id)+        liftF (PgRunReturning CursorBatching cmd consume id)++    runReturningOne cmd =+        liftF (PgRunReturning AtOnce cmd consume id)+      where+        consume next = do+          a <- next+          case a of+            Nothing -> pure Nothing+            Just x -> do+              a' <- next+              case a' of+                Nothing -> pure (Just x)+                Just _ -> pure Nothing++    runReturningList cmd =+        liftF (PgRunReturning AtOnce cmd consume id)+      where+        consume next =+          let collectM acc = do+                a <- next+                case a of+                  Nothing -> pure (acc [])+                  Just x -> collectM (acc . (x:))+          in collectM id  instance MonadBeamInsertReturning Postgres Pg where     runInsertReturningList i = do
Database/Beam/Postgres/Debug.hs view
@@ -4,7 +4,8 @@ import           Database.Beam.Query import           Database.Beam.Postgres.Types (Postgres(..)) import           Database.Beam.Postgres.Connection-  ( Pg, PgF(..)+  ( Pg+  , liftIOWithHandle   , pgRenderSyntax ) import           Database.Beam.Postgres.Full   ( PgInsertReturning(..)@@ -17,10 +18,7 @@   , PgUpdateSyntax(..)   , PgDeleteSyntax(..) ) -import           Control.Monad.Free ( liftF )- import qualified Data.ByteString.Char8 as BC-import           Data.Maybe (maybe)  import qualified Database.PostgreSQL.Simple as Pg @@ -69,5 +67,5 @@  pgTraceStmt :: PgDebugStmt statement => statement -> Pg () pgTraceStmt stmt =-  liftF (PgLiftWithHandle (flip pgTraceStmtIO stmt) id)+  liftIOWithHandle (flip pgTraceStmtIO stmt) 
Database/Beam/Postgres/Extensions.hs view
@@ -39,7 +39,7 @@ -- database, -- -- @--- import Database.Beam.Migrate.PgCrypto+-- import Database.Beam.Postgres.PgCrypto -- -- data MyDatabase entity --     = MyDatabase
+ Database/Beam/Postgres/Extensions/Internal.hs view
@@ -0,0 +1,17 @@+module Database.Beam.Postgres.Extensions.Internal where++import Data.Text (Text)++import Database.Beam+import Database.Beam.Backend.SQL+import Database.Beam.Postgres++type PgExpr ctxt s = QGenExpr ctxt Postgres s++type family LiftPg ctxt s fn where+  LiftPg ctxt s (Maybe a -> b) = Maybe (PgExpr ctxt s a) -> LiftPg ctxt s b+  LiftPg ctxt s (a -> b) = PgExpr ctxt s a -> LiftPg ctxt s b+  LiftPg ctxt s a = PgExpr ctxt s a++funcE :: IsSql99ExpressionSyntax expr => Text -> [expr] -> expr+funcE nm args = functionCallE (fieldE (unqualifiedField nm)) args
+ Database/Beam/Postgres/Extensions/UuidOssp.hs view
@@ -0,0 +1,63 @@+-- | The @uuid-ossp@ extension provides functions for constructing UUIDs.+--+-- For an example of usage, see the documentation for 'PgExtensionEntity'.+module Database.Beam.Postgres.Extensions.UuidOssp+  ( UuidOssp(..)+  ) where++import           Data.Proxy (Proxy(..))+import           Data.Text (Text)+import           Data.UUID.Types (UUID)++import           Database.Beam+import           Database.Beam.Postgres.Extensions+import           Database.Beam.Postgres.Extensions.Internal++-- | Data type representing definitions contained in the @uuid-ossp@ extension+data UuidOssp = UuidOssp+  { pgUuidNil ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidNsDns ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidNsUrl ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidNsOid ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidNsX500 ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidGenerateV1 ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidGenerateV1Mc ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidGenerateV3 ::+      forall ctxt s. LiftPg ctxt s (UUID -> Text -> UUID)+  , pgUuidGenerateV4 ::+      forall ctxt s. LiftPg ctxt s UUID+  , pgUuidGenerateV5 ::+      forall ctxt s. LiftPg ctxt s (UUID -> Text -> UUID)+  }++instance IsPgExtension UuidOssp where+  pgExtensionName Proxy = "uuid-ossp"+  pgExtensionBuild = UuidOssp+    { pgUuidNil =+        QExpr $ funcE "uuid_nil" <$> sequenceA []+    , pgUuidNsDns =+        QExpr $ funcE "uuid_ns_dns" <$> sequenceA []+    , pgUuidNsUrl =+        QExpr $ funcE "uuid_ns_url" <$> sequenceA []+    , pgUuidNsOid =+        QExpr $ funcE "uuid_ns_oid" <$> sequenceA []+    , pgUuidNsX500 =+        QExpr $ funcE "uuid_ns_x500" <$> sequenceA []+    , pgUuidGenerateV1 =+        QExpr $ funcE "uuid_generate_v1" <$> sequenceA []+    , pgUuidGenerateV1Mc =+        QExpr $ funcE "uuid_generate_v1mc" <$> sequenceA []+    , pgUuidGenerateV3 = \(QExpr ns) (QExpr t) ->+        QExpr $ funcE "uuid_generate_v3" <$> sequenceA [ns, t]+    , pgUuidGenerateV4 =+        QExpr $ funcE "uuid_generate_v4" <$> sequenceA []+    , pgUuidGenerateV5 = \(QExpr ns) (QExpr t) ->+        QExpr $ funcE "uuid_generate_v5" <$> sequenceA [ns, t]+    }
Database/Beam/Postgres/Full.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TupleSections #-}@@ -30,14 +31,13 @@    -- ** Specifying conflict actions -  , PgInsertOnConflict(..), PgInsertOnConflictTarget(..)-  , PgConflictAction(..)+  , PgInsertOnConflict(..) -  , onConflictDefault, onConflict, anyConflict, conflictingFields-  , conflictingFieldsWhere, conflictingConstraint-  , onConflictDoNothing, onConflictUpdateSet-  , onConflictUpdateSetWhere, onConflictUpdateInstead-  , onConflictSetAll+  , onConflictDefault, onConflict+  , conflictingConstraint+  , BeamHasInsertOnConflict(..)+  , onConflictUpdateAll+  , onConflictUpdateInstead    -- * @UPDATE RETURNING@   , PgUpdateReturning(..)@@ -56,15 +56,14 @@ import           Database.Beam hiding (insert, insertValues) import           Database.Beam.Query.Internal import           Database.Beam.Backend.SQL+import           Database.Beam.Backend.SQL.BeamExtensions import           Database.Beam.Schema.Tables  import           Database.Beam.Postgres.Types import           Database.Beam.Postgres.Syntax  import           Control.Monad.Free.Church-import           Control.Monad.Writer (execWriter, tell) -import           Data.Functor.Const import           Data.Proxy (Proxy(..)) import qualified Data.Text as T #if !MIN_VERSION_base(4, 11, 0)@@ -94,7 +93,7 @@ lockAll_ = PgWithLocking mempty  -- | Return and lock the given tables. Typically used as an infix operator. See the--- <http://tathougies.github.io/beam/user-guide/backends/beam-postgres/ the user guide> for usage+-- <https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres/ the user guide> for usage -- examples withLocks_ :: a -> PgLockedTables s -> PgWithLocking s a withLocks_ = flip PgWithLocking@@ -113,7 +112,7 @@  -- | Lock some tables during the execution of a query. This is rather complicated, and there are -- several usage examples in--- <http://tathougies.github.io/beam/user-guide/backends/beam-postgres/ the user guide>+-- <https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres/ the user guide> -- -- The Postgres locking clause is rather complex, and beam currently does not check several -- pre-conditions. It is assumed you kinda know what you're doing.@@ -231,15 +230,7 @@ -- | What to do when an @INSERT@ statement inserts a row into the table @tbl@ -- that violates a constraint. newtype PgInsertOnConflict (tbl :: (* -> *) -> *) =-    PgInsertOnConflict (tbl (QField PostgresInaccessible) -> PgInsertOnConflictSyntax)---- | Specifies the kind of constraint that must be violated for the action to occur-newtype PgInsertOnConflictTarget (tbl :: (* -> *) -> *) =-    PgInsertOnConflictTarget (tbl (QExpr Postgres PostgresInaccessible) -> PgInsertOnConflictTargetSyntax)---- | A description of what to do when a constraint or index is violated.-newtype PgConflictAction (tbl :: (* -> *) -> *) =-    PgConflictAction (tbl (QField PostgresInaccessible) -> PgConflictActionSyntax)+    PgInsertOnConflict (tbl (QField QInternal) -> PgInsertOnConflictSyntax)  -- | Postgres @LATERAL JOIN@ support --@@ -296,8 +287,8 @@ -- See the -- <https://www.postgresql.org/docs/current/static/sql-insert.html Postgres documentation>. onConflict :: Beamable tbl-           => PgInsertOnConflictTarget tbl-           -> PgConflictAction tbl+           => SqlConflictTarget Postgres tbl+           -> SqlConflictAction Postgres tbl            -> PgInsertOnConflict tbl onConflict (PgInsertOnConflictTarget tgt) (PgConflictAction update_) =   PgInsertOnConflict $ \tbl ->@@ -308,123 +299,13 @@      emit "ON CONFLICT " <> fromPgInsertOnConflictTarget (tgt exprTbl)                          <> fromPgConflictAction (update_ tbl) --- | Perform the conflict action when any constraint or index conflict occurs.--- Syntactically, this is the @ON CONFLICT@ clause, without any /conflict target/.-anyConflict :: PgInsertOnConflictTarget tbl-anyConflict = PgInsertOnConflictTarget (\_ -> PgInsertOnConflictTargetSyntax mempty)---- | Perform the conflict action only when these fields conflict. The first--- argument gets the current row as a table of expressions. Return the conflict--- key. For more information, see the @beam-postgres@ manual.-conflictingFields :: Projectible Postgres proj-                  => (tbl (QExpr Postgres PostgresInaccessible) -> proj)-                  -> PgInsertOnConflictTarget tbl-conflictingFields makeProjection =-  PgInsertOnConflictTarget $ \tbl ->-  PgInsertOnConflictTargetSyntax $-  pgParens (pgSepBy (emit ", ") $-            map fromPgExpression $-            project (Proxy @Postgres) (makeProjection tbl) "t") <>-  emit " "---- | Like 'conflictingFields', but only perform the action if the condition--- given in the second argument is met. See the postgres--- <https://www.postgresql.org/docs/current/static/sql-insert.html manual> for--- more information.-conflictingFieldsWhere :: Projectible Postgres proj-                       => (tbl (QExpr Postgres PostgresInaccessible) -> proj)-                       -> (tbl (QExpr Postgres PostgresInaccessible) ->-                           QExpr Postgres PostgresInaccessible Bool)-                       -> PgInsertOnConflictTarget tbl-conflictingFieldsWhere makeProjection makeWhere =-  PgInsertOnConflictTarget $ \tbl ->-  PgInsertOnConflictTargetSyntax $-  pgParens (pgSepBy (emit ", ") $-            map fromPgExpression (project (Proxy @Postgres)-                                          (makeProjection tbl) "t")) <>-  emit " WHERE " <>-  pgParens (let QExpr mkE = makeWhere tbl-                PgExpressionSyntax e = mkE "t"-            in e) <>-  emit " "- -- | Perform the action only if the given named constraint is violated-conflictingConstraint :: T.Text -> PgInsertOnConflictTarget tbl+conflictingConstraint :: T.Text -> SqlConflictTarget Postgres tbl conflictingConstraint nm =   PgInsertOnConflictTarget $ \_ ->   PgInsertOnConflictTargetSyntax $   emit "ON CONSTRAINT " <> pgQuotedIdentifier nm <> emit " " --- | The Postgres @DO NOTHING@ action-onConflictDoNothing :: PgConflictAction tbl-onConflictDoNothing = PgConflictAction $ \_ -> PgConflictActionSyntax (emit "DO NOTHING")---- | The Postgres @DO UPDATE SET@ action, without the @WHERE@ clause. The--- argument takes an updatable row (like the one used in 'update') and the--- conflicting row. Use 'current_' on the first argument to get the current--- value of the row in the database.-onConflictUpdateSet :: Beamable tbl-                    => (tbl (QField PostgresInaccessible) ->-                        tbl (QExpr Postgres PostgresInaccessible)  ->-                        QAssignment Postgres PostgresInaccessible)-                    -> PgConflictAction tbl-onConflictUpdateSet mkAssignments =-  PgConflictAction $ \tbl ->-  let QAssignment assignments = mkAssignments tbl tblExcluded-      tblExcluded = changeBeamRep (\(Columnar' (QField _ _ nm)) -> Columnar' (QExpr (\_ -> fieldE (qualifiedField "excluded" nm)))) tbl--      assignmentSyntaxes =-        [ fromPgFieldName fieldNm <> emit "=" <> pgParens (fromPgExpression expr)-        | (fieldNm, expr) <- assignments ]-  in PgConflictActionSyntax $-     emit "DO UPDATE SET " <> pgSepBy (emit ", ") assignmentSyntaxes---- | The Postgres @DO UPDATE SET@ action, with the @WHERE@ clause. This is like--- 'onConflictUpdateSet', but only rows satisfying the given condition are--- updated. Sometimes this results in more efficient locking. See the Postgres--- <https://www.postgresql.org/docs/current/static/sql-insert.html manual> for--- more information.-onConflictUpdateSetWhere :: Beamable tbl-                         => (tbl (QField PostgresInaccessible) ->-                             tbl (QExpr Postgres PostgresInaccessible)  ->-                             QAssignment Postgres PostgresInaccessible)-                         -> (tbl (QExpr Postgres PostgresInaccessible) -> QExpr Postgres PostgresInaccessible Bool)-                         -> PgConflictAction tbl-onConflictUpdateSetWhere mkAssignments where_ =-  PgConflictAction $ \tbl ->-  let QAssignment assignments = mkAssignments tbl tblExcluded-      QExpr where_' = where_ (changeBeamRep (\(Columnar' f) -> Columnar' (current_ f)) tbl)-      tblExcluded = changeBeamRep (\(Columnar' (QField _ _ nm)) -> Columnar' (QExpr (\_ -> fieldE (qualifiedField "excluded" nm)))) tbl--      assignmentSyntaxes =-        [ fromPgFieldName fieldNm <> emit "=" <> pgParens (fromPgExpression expr)-        | (fieldNm, expr) <- assignments ]-  in PgConflictActionSyntax $-     emit "DO UPDATE SET " <> pgSepBy (emit ", ") assignmentSyntaxes <> emit " WHERE " <> fromPgExpression (where_' "t")---- | Sometimes you want to update certain columns in the row. Given a--- projection from a row to the fields you want, Beam can auto-generate--- an assignment that assigns the corresponding fields of the conflicting row.-onConflictUpdateInstead :: (Beamable tbl, ProjectibleWithPredicate AnyType () T.Text proj)-                        => (tbl (Const T.Text) -> proj)-                        -> PgConflictAction tbl-onConflictUpdateInstead mkProj =-  onConflictUpdateSet $ \tbl _ ->-  let tblFields = changeBeamRep (\(Columnar' (QField _ _ nm) :: Columnar' (QField PostgresInaccessible) a) -> Columnar' (Const nm) :: Columnar' (Const T.Text) a) tbl-      proj = execWriter (project' (Proxy @AnyType) (Proxy @((), T.Text))-                                  (\_ _ e -> tell [e] >> pure e)-                                  (mkProj tblFields))--  in QAssignment (map (\fieldNm -> (unqualifiedField fieldNm, fieldE (qualifiedField "excluded" fieldNm))) proj)---- | Sometimes you want to update every value in the row. Beam can auto-generate--- an assignment that assigns the conflicting row to every field in the database--- row. This may not always be what you want.-onConflictSetAll :: ( Beamable tbl-                    , ProjectibleWithPredicate AnyType () T.Text (tbl (Const T.Text)) )-                 => PgConflictAction tbl-onConflictSetAll = onConflictUpdateInstead id- -- * @UPDATE@  -- | The most general kind of @UPDATE@ that postgres can perform@@ -555,3 +436,77 @@      where       tblQ = changeBeamRep (\(Columnar' f) -> Columnar' (QExpr . pure . fieldE . unqualifiedField . _fieldName $ f)) tblSettings++instance BeamHasInsertOnConflict Postgres where+  newtype SqlConflictTarget Postgres table =+    PgInsertOnConflictTarget (table (QExpr Postgres QInternal) -> PgInsertOnConflictTargetSyntax)+  newtype SqlConflictAction Postgres table =+    PgConflictAction (table (QField QInternal) -> PgConflictActionSyntax)++  insertOnConflict tbl vs target action = insert tbl vs $ onConflict target action++  -- | Perform the conflict action when any constraint or index conflict occurs.+  -- Syntactically, this is the @ON CONFLICT@ clause, without any /conflict target/.+  anyConflict = PgInsertOnConflictTarget (\_ -> PgInsertOnConflictTargetSyntax mempty)++  -- | The Postgres @DO NOTHING@ action+  onConflictDoNothing = PgConflictAction $ \_ -> PgConflictActionSyntax (emit "DO NOTHING")++  -- | The Postgres @DO UPDATE SET@ action, without the @WHERE@ clause. The+  -- argument takes an updatable row (like the one used in 'update') and the+  -- conflicting row. Use 'current_' on the first argument to get the current+  -- value of the row in the database.+  onConflictUpdateSet mkAssignments =+    PgConflictAction $ \tbl ->+    let QAssignment assignments = mkAssignments tbl tblExcluded+        tblExcluded = changeBeamRep (\(Columnar' (QField _ _ nm)) -> Columnar' (QExpr (\_ -> fieldE (qualifiedField "excluded" nm)))) tbl++        assignmentSyntaxes =+          [ fromPgFieldName fieldNm <> emit "=" <> pgParens (fromPgExpression expr)+          | (fieldNm, expr) <- assignments ]+    in PgConflictActionSyntax $+       emit "DO UPDATE SET " <> pgSepBy (emit ", ") assignmentSyntaxes++  -- | The Postgres @DO UPDATE SET@ action, with the @WHERE@ clause. This is like+  -- 'onConflictUpdateSet', but only rows satisfying the given condition are+  -- updated. Sometimes this results in more efficient locking. See the Postgres+  -- <https://www.postgresql.org/docs/current/static/sql-insert.html manual> for+  -- more information.+  onConflictUpdateSetWhere mkAssignments where_ =+    PgConflictAction $ \tbl ->+    let QAssignment assignments = mkAssignments tbl tblExcluded+        QExpr where_' = where_ tbl tblExcluded+        tblExcluded = changeBeamRep (\(Columnar' (QField _ _ nm)) -> Columnar' (QExpr (\_ -> fieldE (qualifiedField "excluded" nm)))) tbl++        assignmentSyntaxes =+          [ fromPgFieldName fieldNm <> emit "=" <> pgParens (fromPgExpression expr)+          | (fieldNm, expr) <- assignments ]+    in PgConflictActionSyntax $+       emit "DO UPDATE SET " <> pgSepBy (emit ", ") assignmentSyntaxes <> emit " WHERE " <> fromPgExpression (where_' "t")++  -- | Perform the conflict action only when these fields conflict. The first+  -- argument gets the current row as a table of expressions. Return the conflict+  -- key. For more information, see the @beam-postgres@ manual.+  conflictingFields makeProjection =+    PgInsertOnConflictTarget $ \tbl ->+    PgInsertOnConflictTargetSyntax $+    pgParens (pgSepBy (emit ", ") $+              map fromPgExpression $+              project (Proxy @Postgres) (makeProjection tbl) "t") <>+    emit " "++  -- | Like 'conflictingFields', but only perform the action if the condition+  -- given in the second argument is met. See the postgres+  -- <https://www.postgresql.org/docs/current/static/sql-insert.html manual> for+  -- more information.+  conflictingFieldsWhere makeProjection makeWhere =+    PgInsertOnConflictTarget $ \tbl ->+    PgInsertOnConflictTargetSyntax $+    pgParens (pgSepBy (emit ", ") $+              map fromPgExpression (project (Proxy @Postgres)+                                            (makeProjection tbl) "t")) <>+    emit " WHERE " <>+    pgParens (let QExpr mkE = makeWhere tbl+                  PgExpressionSyntax e = mkE "t"+              in e) <>+    emit " "
Database/Beam/Postgres/Migrate.hs view
@@ -14,6 +14,7 @@   , postgresDataTypeDeserializers   , pgPredConverter   , getDbConstraints+  , getDbConstraintsForSchemas   , pgTypeToHs   , migrateScript   , writeMigrationScript@@ -54,7 +55,6 @@ import           Control.Arrow import           Control.Exception (bracket) import           Control.Monad-import           Control.Monad.Free.Church (liftF)  import           Data.Aeson hiding (json) import           Data.Bits@@ -89,7 +89,7 @@                                  , "  postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]"                                  , ""                                  , "See <https://www.postgresql.org/docs/9.5/static/libpq-connect.html#LIBPQ-CONNSTRING> for more information" ])-                        (liftF (PgLiftWithHandle getDbConstraints id))+                        (liftIOWithHandle getDbConstraints)                         (Db.sql92Deserializers <> Db.sql99DataTypeDeserializers <>                          Db.sql2008BigIntDataTypeDeserializers <>                          postgresDataTypeDeserializers <>@@ -324,8 +324,13 @@ -- * Create constraints from a connection  getDbConstraints :: Pg.Connection -> IO [ Db.SomeDatabasePredicate ]-getDbConstraints conn =-  do tbls <- Pg.query_ conn "SELECT cl.oid, relname FROM pg_catalog.pg_class \"cl\" join pg_catalog.pg_namespace \"ns\" on (ns.oid = relnamespace) where nspname = any (current_schemas(false)) and relkind='r'"+getDbConstraints = getDbConstraintsForSchemas Nothing++getDbConstraintsForSchemas :: Maybe [String] -> Pg.Connection -> IO [ Db.SomeDatabasePredicate ]+getDbConstraintsForSchemas subschemas conn =+  do tbls <- case subschemas of+        Nothing -> Pg.query_ conn "SELECT cl.oid, relname FROM pg_catalog.pg_class \"cl\" join pg_catalog.pg_namespace \"ns\" on (ns.oid = relnamespace) where nspname = any (current_schemas(false)) and relkind='r'"+        Just ss -> Pg.query  conn "SELECT cl.oid, relname FROM pg_catalog.pg_class \"cl\" join pg_catalog.pg_namespace \"ns\" on (ns.oid = relnamespace) where nspname IN ? and relkind='r'" (Pg.Only (Pg.In ss))      let tblsExist = map (\(_, tbl) -> Db.SomeDatabasePredicate (Db.TableExistsPredicate (Db.QualifiedName Nothing tbl))) tbls       enumerationData <-@@ -362,12 +367,17 @@                                            , "CROSS JOIN unnest(i.indkey) WITH ORDINALITY k(attid, n)"                                            , "JOIN pg_attribute a ON a.attnum=k.attid AND a.attrelid=i.indrelid"                                            , "JOIN pg_class c ON c.oid=i.indrelid"-                                           , "WHERE c.relkind='r' AND i.indisprimary GROUP BY relname, i.indrelid" ]))+                                           , "JOIN pg_namespace ns ON ns.oid=c.relnamespace"+                                           , "WHERE ns.nspname = any (current_schemas(false)) AND c.relkind='r' AND i.indisprimary GROUP BY relname, i.indrelid" ]))       let enumerations =            map (\(enumNm, _, options) -> Db.SomeDatabasePredicate (PgHasEnum enumNm (V.toList options))) enumerationData -     pure (tblsExist ++ columnChecks ++ primaryKeys ++ enumerations)+     extensions <-+       map (\(Pg.Only extname) -> Db.SomeDatabasePredicate (PgHasExtension extname)) <$>+       Pg.query_ conn "SELECT extname from pg_extension"++     pure (tblsExist ++ columnChecks ++ primaryKeys ++ enumerations ++ extensions)  -- * Postgres-specific data types 
Database/Beam/Postgres/PgCrypto.hs view
@@ -1,3 +1,4 @@+ -- | The @pgcrypto@ extension provides several cryptographic functions to -- Postgres. This module provides a @beam-postgres@ extension to access this -- functionality. For an example of usage, see the documentation for@@ -8,21 +9,15 @@ import Database.Beam import Database.Beam.Backend.SQL -import Database.Beam.Postgres.Types import Database.Beam.Postgres.Extensions+import Database.Beam.Postgres.Extensions.Internal +import Data.Int import Data.Text (Text) import Data.ByteString (ByteString) import Data.Vector (Vector) import Data.UUID.Types (UUID) -type PgExpr ctxt s = QGenExpr ctxt Postgres s--type family LiftPg ctxt s fn where-  LiftPg ctxt s (Maybe a -> b) = Maybe (PgExpr ctxt s a) -> LiftPg ctxt s b-  LiftPg ctxt s (a -> b) = PgExpr ctxt s a -> LiftPg ctxt s b-  LiftPg ctxt s a = PgExpr ctxt s a- -- | Data type representing definitions contained in the @pgcrypto@ extension -- -- Each field maps closely to the underlying @pgcrypto@ function, which are@@ -41,7 +36,7 @@   , pgCryptoCrypt ::       forall ctxt s. LiftPg ctxt s (Text -> Text -> Text)   , pgCryptoGenSalt ::-      forall ctxt s. LiftPg ctxt s (Text -> Maybe Int -> Text)+      forall ctxt s. LiftPg ctxt s (Text -> Maybe Int32 -> Text)    -- Pgp functions   , pgCryptoPgpSymEncrypt ::@@ -83,9 +78,6 @@   , pgCryptoGenRandomUUID ::       forall ctxt s. PgExpr ctxt s UUID   }--funcE :: IsSql99ExpressionSyntax expr => Text -> [expr] -> expr-funcE nm args = functionCallE (fieldE (unqualifiedField nm)) args  instance IsPgExtension PgCrypto where   pgExtensionName _ = "pgcrypto"
Database/Beam/Postgres/PgSpecific.hs view
@@ -38,6 +38,7 @@   , withoutKeys    , pgJsonArrayLength+  , pgArrayToJson   , pgJsonbUpdate, pgJsonbSet   , pgJsonbPretty @@ -56,6 +57,12 @@   , PgBox(..), PgPath(..), PgPolygon(..)   , PgCircle(..) +    -- ** Regular expressions+  , PgRegex(..), pgRegex_+  , (~.), (~*.), (!~.), (!~*.)+  , pgRegexpReplace_, pgRegexpMatch_+  , pgRegexpSplitToTable, pgRegexpSplitToArray+     -- ** Set-valued functions     -- $set-valued-funs   , PgSetOf, pgUnnest@@ -86,7 +93,7 @@      -- *** Building ranges from expressions   , range_-  +     -- *** Building @PgRangeBound@s   , inclusive, exclusive, unbounded @@ -98,7 +105,7 @@   , rLower_, rUpper_, isEmpty_   , lowerInc_, upperInc_, lowerInf_, upperInf_   , rangeMerge_-  +     -- ** Postgres functions and aggregates   , pgBoolOr, pgBoolAnd, pgStringAgg, pgStringAggOver @@ -127,7 +134,9 @@ import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as BL import           Data.Foldable+import           Data.Functor import           Data.Hashable+import           Data.Int import qualified Data.List.NonEmpty as NE import           Data.Proxy import           Data.Scientific (Scientific, formatScientific, FPFormat(Fixed))@@ -703,9 +712,10 @@   fromField field d =     if Pg.typeOid field /= Pg.typoid Pg.json     then Pg.returnError Pg.Incompatible field ""-    else case decodeStrict =<< d of-           Just d' -> pure (PgJSON d')+    else case eitherDecodeStrict <$> d of            Nothing -> Pg.returnError Pg.UnexpectedNull field ""+           Just (Left e) -> Pg.returnError Pg.ConversionFailed field e+           Just (Right d') -> pure (PgJSON d')  instance (Typeable a, FromJSON a) => FromBackendRow Postgres (PgJSON a) instance ToJSON a => HasSqlValueSyntax PgValueSyntax (PgJSON a) where@@ -715,7 +725,7 @@  -- | The Postgres @JSONB@ type, which stores JSON-encoded data in a -- postgres-specific binary format. Like 'PgJSON', the type parameter indicates--- the Hgaskell type which the JSON encodes.+-- the Haskell type which the JSON encodes. -- -- Fields with this type are automatically given the Postgres @JSONB@ type newtype PgJSONB a = PgJSONB a@@ -728,9 +738,10 @@   fromField field d =     if Pg.typeOid field /= Pg.typoid Pg.jsonb     then Pg.returnError Pg.Incompatible field ""-    else case decodeStrict =<< d of-           Just d' -> pure (PgJSONB d')+    else case eitherDecodeStrict <$> d of            Nothing -> Pg.returnError Pg.UnexpectedNull field ""+           Just (Left e) -> Pg.returnError Pg.ConversionFailed field e+           Just (Right d') -> pure (PgJSONB d')  instance (Typeable a, FromJSON a) => FromBackendRow Postgres (PgJSONB a) instance ToJSON a => HasSqlValueSyntax PgValueSyntax (PgJSONB a) where@@ -867,10 +878,10 @@ -- | Postgres @&#x40;>@ and @<&#x40;@ operators for JSON. Return true if the -- json object pointed to by the arrow is completely contained in the other. See -- the Postgres documentation for more in formation on what this means.-(@>), (<@) :: IsPgJSON json-           => QGenExpr ctxt Postgres s (json a)-           -> QGenExpr ctxt Postgres s (json b)-           -> QGenExpr ctxt Postgres s Bool+(@>), (<@)+  :: QGenExpr ctxt Postgres s (PgJSONB a)+  -> QGenExpr ctxt Postgres s (PgJSONB b)+  -> QGenExpr ctxt Postgres s Bool QExpr a @> QExpr b =   QExpr (pgBinOp "@>" <$> a <*> b) QExpr a <@ QExpr b =@@ -880,7 +891,7 @@ -- See '(->$)' for the corresponding operator for object access. (->#) :: IsPgJSON json       => QGenExpr ctxt Postgres s (json a)-      -> QGenExpr ctxt Postgres s Int+      -> QGenExpr ctxt Postgres s Int32       -> QGenExpr ctxt Postgres s (json b) QExpr a -># QExpr b =   QExpr (pgBinOp "->" <$> a <*> b)@@ -899,7 +910,7 @@ -- corresponding operator on objects. (->>#) :: IsPgJSON json        => QGenExpr ctxt Postgres s (json a)-       -> QGenExpr ctxt Postgres s Int+       -> QGenExpr ctxt Postgres s Int32        -> QGenExpr ctxt Postgres s T.Text QExpr a ->># QExpr b =   QExpr (pgBinOp "->>" <$> a <*> b)@@ -936,19 +947,19 @@  -- | Postgres @?@ operator. Checks if the given string exists as top-level key -- of the json object.-(?) :: IsPgJSON json-    => QGenExpr ctxt Postgres s (json a)-    -> QGenExpr ctxt Postgres s T.Text-    -> QGenExpr ctxt Postgres s Bool+(?)+  :: QGenExpr ctxt Postgres s (PgJSONB a)+  -> QGenExpr ctxt Postgres s T.Text+  -> QGenExpr ctxt Postgres s Bool QExpr a ? QExpr b =   QExpr (pgBinOp "?" <$> a <*> b)  -- | Postgres @?|@ and @?&@ operators. Check if any or all of the given strings -- exist as top-level keys of the json object respectively.-(?|), (?&) :: IsPgJSON json-           => QGenExpr ctxt Postgres s (json a)-           -> QGenExpr ctxt Postgres s (V.Vector T.Text)-           -> QGenExpr ctxt Postgres s Bool+(?|), (?&)+  :: QGenExpr ctxt Postgres s (PgJSONB a)+  -> QGenExpr ctxt Postgres s (V.Vector T.Text)+  -> QGenExpr ctxt Postgres s Bool QExpr a ?| QExpr b =   QExpr (pgBinOp "?|" <$> a <*> b) QExpr a ?& QExpr b =@@ -957,39 +968,48 @@ -- | Postgres @-@ operator on json objects. Returns the supplied json object -- with the supplied key deleted. See 'withoutIdx' for the corresponding -- operator on arrays.-withoutKey :: IsPgJSON json-           => QGenExpr ctxt Postgres s (json a)-           -> QGenExpr ctxt Postgres s T.Text-           -> QGenExpr ctxt Postgres s (json b)+withoutKey+  :: QGenExpr ctxt Postgres s (PgJSONB a)+  -> QGenExpr ctxt Postgres s T.Text+  -> QGenExpr ctxt Postgres s (PgJSONB b) QExpr a `withoutKey` QExpr b =   QExpr (pgBinOp "-" <$> a <*> b)  -- | Postgres @-@ operator on json arrays. See 'withoutKey' for the -- corresponding operator on objects.-withoutIdx :: IsPgJSON json-           => QGenExpr ctxt Postgres s (json a)-           -> QGenExpr ctxt Postgres s Int-           -> QGenExpr ctxt Postgres s (json b)+withoutIdx+  :: QGenExpr ctxt Postgres s (PgJSONB a)+  -> QGenExpr ctxt Postgres s Int32+  -> QGenExpr ctxt Postgres s (PgJSONB b) QExpr a `withoutIdx` QExpr b =   QExpr (pgBinOp "-" <$> a <*> b)  -- | Postgres @#-@ operator. Removes all the keys specificied from the JSON -- object and returns the result.-withoutKeys :: IsPgJSON json-            => QGenExpr ctxt Postgres s (json a)-            -> QGenExpr ctxt Postgres s (V.Vector T.Text)-            -> QGenExpr ctxt Postgres s (json b)+withoutKeys+  :: QGenExpr ctxt Postgres s (PgJSONB a)+  -> QGenExpr ctxt Postgres s (V.Vector T.Text)+  -> QGenExpr ctxt Postgres s (PgJSONB b) QExpr a `withoutKeys` QExpr b =   QExpr (pgBinOp "#-" <$> a <*> b)  -- | Postgres @json_array_length@ function. The supplied json object should be -- an array, but this isn't checked at compile-time. pgJsonArrayLength :: IsPgJSON json => QGenExpr ctxt Postgres s (json a)-                  -> QGenExpr ctxt Postgres s Int+                  -> QGenExpr ctxt Postgres s Int32 pgJsonArrayLength (QExpr a) =   QExpr $ \tbl ->   PgExpressionSyntax (emit "json_array_length(" <> fromPgExpression (a tbl) <> emit ")") +-- | Postgres @array_to_json@ function.+pgArrayToJson+  :: QGenExpr ctxt Postgres s (V.Vector e)+  -> QGenExpr ctxt Postgres s (PgJSON a)+pgArrayToJson (QExpr a) = QExpr $ a <&> PgExpressionSyntax .+  mappend (emit "array_to_json") .+  pgParens .+  fromPgExpression+ -- | The postgres @jsonb_set@ function. 'pgJsonUpdate' expects the value -- specified by the path in the second argument to exist. If it does not, the -- first argument is not modified. 'pgJsonbSet' will create any intermediate@@ -1260,7 +1280,101 @@                             <*> pgPointParser instance FromBackendRow Postgres PgBox +-- ** Regular expressions +-- | The type of Postgres regular expressions. Only a+-- 'HasSqlValueSyntax' instance is supplied, because you won't need to+-- be reading these back from the database.+--+-- If you're generating regexes dynamically, then use 'pgRegex_' to+-- convert a string expression into a regex one.+newtype PgRegex = PgRegex T.Text+  deriving (Show, Eq, Ord, IsString)++instance HasSqlValueSyntax PgValueSyntax PgRegex where+  sqlValueSyntax (PgRegex r) = sqlValueSyntax r++-- | Convert a string valued expression (which could be generated+-- dynamically) into a 'PgRegex'-typed one.+pgRegex_ :: BeamSqlBackendIsString Postgres text => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+pgRegex_ (QExpr e) = QExpr e++-- | Match regular expression, case-sensitive+(~.) :: BeamSqlBackendIsString Postgres text+     => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+     -> QGenExpr ctxt Postgres s Bool+QExpr t ~. QExpr re = QExpr (pgBinOp "~" <$> t <*> re)++-- | Match regular expression, case-insensitive+(~*.) :: BeamSqlBackendIsString Postgres text+      => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+      -> QGenExpr ctxt Postgres s Bool+QExpr t ~*. QExpr re = QExpr (pgBinOp "~*" <$> t <*> re)++-- | Does not match regular expression, case-sensitive+(!~.) :: BeamSqlBackendIsString Postgres text+      => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+      -> QGenExpr ctxt Postgres s Bool+QExpr t !~. QExpr re = QExpr (pgBinOp "!~" <$> t <*> re)++-- | Does not match regular expression, case-insensitive+(!~*.) :: BeamSqlBackendIsString Postgres text+       => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+       -> QGenExpr ctxt Postgres s Bool+QExpr t !~*. QExpr re = QExpr (pgBinOp "!~*" <$> t <*> re)++-- | Postgres @regexp_replace@. Replaces all instances of the regex in+-- the first argument with the third argument. The fourth argument is+-- the postgres regex options to provide.+pgRegexpReplace_ :: BeamSqlBackendIsString Postgres text+                 => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+                 -> QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s T.Text+                 -> QGenExpr ctxt Postgres s txt+pgRegexpReplace_ (QExpr haystack) (QExpr needle) (QExpr replacement) (QExpr opts) =+  QExpr (\t -> PgExpressionSyntax $+               emit "regexp_replace(" <> fromPgExpression (haystack t) <> emit ", "+                                      <> fromPgExpression (needle t) <> emit ", "+                                      <> fromPgExpression (replacement t) <> emit ", "+                                      <> fromPgExpression (opts t) <> emit ")")++-- | Postgres @regexp_match@. Matches the regular expression against+-- the string given and returns an array where each element+-- corresponds to a match in the string, or @NULL@ if nothing was+-- found+pgRegexpMatch_ :: BeamSqlBackendIsString Postgres text+               => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+               -> QGenExpr ctxt Postgres s (Maybe (V.Vector text))+pgRegexpMatch_ (QExpr s) (QExpr re) =+  QExpr (\t -> PgExpressionSyntax $+               emit "regexp_match(" <> fromPgExpression (s t) <> emit ", "+                                    <> fromPgExpression (re t) <> emit ")")++-- | Postgres @regexp_split_to_array@. Splits the given string by the+-- given regex and returns the result as an array.+pgRegexpSplitToArray :: BeamSqlBackendIsString Postgres text+                     => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex+                     -> QGenExpr ctxt Postgres s (V.Vector text)+pgRegexpSplitToArray (QExpr s) (QExpr re) =+  QExpr (\t -> PgExpressionSyntax $+               emit "regexp_split_to_array(" <> fromPgExpression (s t) <> emit ", "+                                             <> fromPgExpression (re t) <> emit ")")++newtype PgReResultT f+  = PgReResultT { reResult :: C f T.Text }+  deriving Generic+instance Beamable PgReResultT++-- | Postgres @regexp_split_to_table@. Splits the given string by the+-- given regex and return a result set that can be joined against.+pgRegexpSplitToTable :: BeamSqlBackendIsString Postgres text+                     => QGenExpr ctxt Postgres s text -> QGenExpr ctxt Postgres s PgRegex++                     -> Q Postgres db s (QExpr Postgres s T.Text)+pgRegexpSplitToTable (QExpr s) (QExpr re) =+  fmap reResult $+  pgUnnest' (\t -> emit "regexp_split_to_table(" <> fromPgExpression (s t) <> emit ", "+                                                 <> fromPgExpression (re t) <> emit ")")+ -- ** Set-valued functions  data PgSetOf (tbl :: (* -> *) -> *)@@ -1288,6 +1402,7 @@                                       pure (Columnar' (TableField (pure fieldNm) fieldNm)))                                 tblSkeleton tblSkeleton) (0 :: Int) +-- | Join the results of the given set-valued function to the query pgUnnest :: forall tbl db s           . Beamable tbl          => QExpr Postgres s (PgSetOf tbl)@@ -1299,18 +1414,21 @@   deriving Generic instance Beamable (PgUnnestArrayTbl a) +-- | Introduce each element of the array as a row pgUnnestArray :: QExpr Postgres s (V.Vector a)               -> Q Postgres db s (QExpr Postgres s a) pgUnnestArray (QExpr q) =   fmap (\(PgUnnestArrayTbl x) -> x) $   pgUnnest' (\t -> emit "UNNEST" <> pgParens (fromPgExpression (q t))) -data PgUnnestArrayWithOrdinalityTbl a f = PgUnnestArrayWithOrdinalityTbl (C f Int) (C f a)+data PgUnnestArrayWithOrdinalityTbl a f = PgUnnestArrayWithOrdinalityTbl (C f Int64) (C f a)   deriving Generic instance Beamable (PgUnnestArrayWithOrdinalityTbl a) +-- | Introduce each element of the array as a row, along with the+-- element's index pgUnnestArrayWithOrdinality :: QExpr Postgres s (V.Vector a)-                            -> Q Postgres db s (QExpr Postgres s Int, QExpr Postgres s a)+                            -> Q Postgres db s (QExpr Postgres s Int64, QExpr Postgres s a) pgUnnestArrayWithOrdinality (QExpr q) =   fmap (\(PgUnnestArrayWithOrdinalityTbl i x) -> (i, x)) $   pgUnnest' (\t -> emit "UNNEST" <> pgParens (fromPgExpression (q t)) <> emit " WITH ORDINALITY")@@ -1406,7 +1524,7 @@ -- know the shape of the data stored, substitute 'Value' for this type -- parameter. ----- For more information on Psotgres json support see the postgres+-- For more information on Postgres JSON support see the postgres -- <https://www.postgresql.org/docs/current/static/functions-json.html manual>.  
Database/Beam/Postgres/Syntax.hs view
@@ -11,6 +11,7 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE UndecidableInstances #-}  -- | Data types for Postgres syntax. Access is given mainly for extension -- modules. The types and definitions here are likely to change.@@ -86,9 +87,9 @@     , PostgresInaccessible ) where  import           Database.Beam hiding (insert)+import           Database.Beam.Backend.Internal.Compat import           Database.Beam.Backend.SQL import           Database.Beam.Migrate-import           Database.Beam.Migrate.Checks (HasDataTypeCreatedCheck(..)) import           Database.Beam.Migrate.SQL.Builder hiding (fromSqlConstraintAttributes) import           Database.Beam.Migrate.Serialization @@ -122,6 +123,7 @@ import           Data.UUID.Types (UUID) import           Data.Word import qualified Data.Vector as V+import           GHC.TypeLits  import qualified Database.PostgreSQL.Simple.ToField as Pg import qualified Database.PostgreSQL.Simple.TypeInfo.Static as Pg@@ -541,7 +543,7 @@                                       (emit "NUMERIC" <> pgOptNumericPrec prec)                                       (numericType prec)   decimalType prec = PgDataTypeSyntax (PgDataTypeDescrOid (Pg.typoid Pg.numeric) (mkNumericPrec prec))-                                      (emit "DOUBLE" <> pgOptNumericPrec prec)+                                      (emit "DECIMAL" <> pgOptNumericPrec prec)                                       (decimalType prec)    intType = PgDataTypeSyntax (PgDataTypeDescrOid (Pg.typoid Pg.int4) Nothing) (emit "INT") intType@@ -1177,13 +1179,11 @@ DEFAULT_SQL_SYNTAX(Bool) DEFAULT_SQL_SYNTAX(Double) DEFAULT_SQL_SYNTAX(Float)-DEFAULT_SQL_SYNTAX(Int) DEFAULT_SQL_SYNTAX(Int8) DEFAULT_SQL_SYNTAX(Int16) DEFAULT_SQL_SYNTAX(Int32) DEFAULT_SQL_SYNTAX(Int64) DEFAULT_SQL_SYNTAX(Integer)-DEFAULT_SQL_SYNTAX(Word) DEFAULT_SQL_SYNTAX(Word8) DEFAULT_SQL_SYNTAX(Word16) DEFAULT_SQL_SYNTAX(Word32)@@ -1226,6 +1226,12 @@   sqlValueSyntax = defaultPgValueSyntax . Pg.Binary  instance Pg.ToField a => HasSqlValueSyntax PgValueSyntax (V.Vector a) where+  sqlValueSyntax = defaultPgValueSyntax++instance TypeError (PreferExplicitSize Int Int32) => HasSqlValueSyntax PgValueSyntax Int where+  sqlValueSyntax = defaultPgValueSyntax++instance TypeError (PreferExplicitSize Word Word32) => HasSqlValueSyntax PgValueSyntax Word where   sqlValueSyntax = defaultPgValueSyntax  pgQuotedIdentifier :: T.Text -> PgSyntax
Database/Beam/Postgres/Types.hs view
@@ -4,14 +4,20 @@ {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}  module Database.Beam.Postgres.Types-  ( Postgres(..) ) where+  ( Postgres(..)+  , fromPgIntegral+  , fromPgScientificOrIntegral+  ) where  import           Database.Beam import           Database.Beam.Backend+import           Database.Beam.Backend.Internal.Compat import           Database.Beam.Migrate.Generics import           Database.Beam.Migrate.SQL (BeamMigrateOnlySqlBackend) import           Database.Beam.Postgres.Syntax@@ -28,6 +34,7 @@ import qualified Data.ByteString.Lazy as BL import           Data.CaseInsensitive (CI) import           Data.Int+import           Data.Proxy import           Data.Ratio (Ratio) import           Data.Scientific (Scientific, toBoundedInteger) import           Data.Tagged@@ -37,11 +44,12 @@ import           Data.UUID.Types (UUID) import           Data.Vector (Vector) import           Data.Word+import           GHC.TypeLits  -- | The Postgres backend type, used to parameterize 'MonadBeam'. See the -- definitions there for more information. The corresponding query monad is -- 'Pg'. See documentation for 'MonadBeam' and the--- <https://tathougies.github/beam/ user guide> for more information on using+-- <https://haskell-beam.github/beam/ user guide> for more information on using -- this backend. data Postgres   = Postgres@@ -49,11 +57,16 @@ instance BeamBackend Postgres where   type BackendFromField Postgres = Pg.FromField +instance HasSqlInTable Postgres where+ instance Pg.FromField SqlNull where   fromField field d = fmap (\Pg.Null -> SqlNull) (Pg.fromField field d) -fromScientificOrIntegral :: (Bounded a, Integral a) => FromBackendRowM Postgres a-fromScientificOrIntegral = do+-- | Deserialize integral fields, possibly downcasting from a larger numeric type+-- via 'Scientific' if we won't lose data, and then falling back to any integral+-- type via 'Integer'+fromPgScientificOrIntegral :: (Bounded a, Integral a) => FromBackendRowM Postgres a+fromPgScientificOrIntegral = do   sciVal <- fmap (toBoundedInteger =<<) peekField   case sciVal of     Just sciVal' -> do@@ -83,24 +96,28 @@ instance FromBackendRow Postgres Bool instance FromBackendRow Postgres Char instance FromBackendRow Postgres Double-instance FromBackendRow Postgres Int where-  fromBackendRow = fromPgIntegral instance FromBackendRow Postgres Int16 where   fromBackendRow = fromPgIntegral instance FromBackendRow Postgres Int32 where   fromBackendRow = fromPgIntegral instance FromBackendRow Postgres Int64 where   fromBackendRow = fromPgIntegral++instance TypeError (PreferExplicitSize Int Int32) => FromBackendRow Postgres Int where+  fromBackendRow = fromPgIntegral+ -- Word values are serialized as SQL @NUMBER@ types to guarantee full domain coverage.--- However, we wan them te be serialized/deserialized as whichever type makes sense-instance FromBackendRow Postgres Word where-  fromBackendRow = fromScientificOrIntegral+-- However, we want them te be serialized/deserialized as whichever type makes sense instance FromBackendRow Postgres Word16 where-  fromBackendRow = fromScientificOrIntegral+  fromBackendRow = fromPgScientificOrIntegral instance FromBackendRow Postgres Word32 where-  fromBackendRow = fromScientificOrIntegral+  fromBackendRow = fromPgScientificOrIntegral instance FromBackendRow Postgres Word64 where-  fromBackendRow = fromScientificOrIntegral+  fromBackendRow = fromPgScientificOrIntegral++instance TypeError (PreferExplicitSize Word Word32) => FromBackendRow Postgres Word where+  fromBackendRow = fromPgScientificOrIntegral+ instance FromBackendRow Postgres Integer instance FromBackendRow Postgres ByteString instance FromBackendRow Postgres Scientific@@ -168,10 +185,24 @@ instance HasDefaultSqlDataType Postgres LocalTime where   defaultSqlDataType _ _ _ = timestampType Nothing False -instance HasDefaultSqlDataType Postgres (SqlSerial Int) where+instance HasDefaultSqlDataType Postgres UTCTime where+  defaultSqlDataType _ _ _ = timestampType Nothing True++instance HasDefaultSqlDataType Postgres (SqlSerial Int16) where+  defaultSqlDataType _ _ False = pgSmallSerialType+  defaultSqlDataType _ _ _ = smallIntType++instance HasDefaultSqlDataType Postgres (SqlSerial Int32) where   defaultSqlDataType _ _ False = pgSerialType   defaultSqlDataType _ _ _ = intType +instance HasDefaultSqlDataType Postgres (SqlSerial Int64) where+  defaultSqlDataType _ _ False = pgBigSerialType+  defaultSqlDataType _ _ _ = bigIntType++instance TypeError (PreferExplicitSize Int Int32) => HasDefaultSqlDataType Postgres (SqlSerial Int) where+  defaultSqlDataType _ = defaultSqlDataType (Proxy @(SqlSerial Int32))+ instance HasDefaultSqlDataType Postgres UUID where   defaultSqlDataType _ _ _ = pgUuidType @@ -184,13 +215,11 @@ PG_HAS_EQUALITY_CHECK(Bool) PG_HAS_EQUALITY_CHECK(Double) PG_HAS_EQUALITY_CHECK(Float)-PG_HAS_EQUALITY_CHECK(Int) PG_HAS_EQUALITY_CHECK(Int8) PG_HAS_EQUALITY_CHECK(Int16) PG_HAS_EQUALITY_CHECK(Int32) PG_HAS_EQUALITY_CHECK(Int64) PG_HAS_EQUALITY_CHECK(Integer)-PG_HAS_EQUALITY_CHECK(Word) PG_HAS_EQUALITY_CHECK(Word8) PG_HAS_EQUALITY_CHECK(Word16) PG_HAS_EQUALITY_CHECK(Word32)@@ -219,6 +248,11 @@ PG_HAS_EQUALITY_CHECK(Vector a) PG_HAS_EQUALITY_CHECK(CI Text) PG_HAS_EQUALITY_CHECK(CI TL.Text)++instance TypeError (PreferExplicitSize Int Int32) => HasSqlEqualityCheck Postgres Int+instance TypeError (PreferExplicitSize Int Int32) => HasSqlQuantifiedEqualityCheck Postgres Int+instance TypeError (PreferExplicitSize Word Word32) => HasSqlEqualityCheck Postgres Word+instance TypeError (PreferExplicitSize Word Word32) => HasSqlQuantifiedEqualityCheck Postgres Word  instance HasSqlEqualityCheck Postgres a =>   HasSqlEqualityCheck Postgres (Tagged t a)
beam-postgres.cabal view
@@ -1,8 +1,8 @@ name:                 beam-postgres-version:              0.4.0.0+version:              0.5.0.0 synopsis:             Connection layer between beam and postgres description:          Beam driver for <https://www.postgresql.org/ PostgreSQL>, an advanced open-source RDBMS-homepage:             http://tathougies.github.io/beam/user-guide/backends/beam-postgres+homepage:             https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres license:              MIT license-file:         LICENSE author:               Travis Athougies@@ -11,27 +11,30 @@ build-type:           Simple cabal-version:        1.18 extra-doc-files:      ChangeLog.md-bug-reports:          https://github.com/tathougies/beam/issues+bug-reports:          https://github.com/haskell-beam/beam/issues  library   exposed-modules:    Database.Beam.Postgres                       Database.Beam.Postgres.Migrate-                      Database.Beam.Postgres.PgCrypto                       Database.Beam.Postgres.Syntax                       Database.Beam.Postgres.CustomTypes                        Database.Beam.Postgres.Conduit                       Database.Beam.Postgres.Full +                      Database.Beam.Postgres.PgCrypto+                      Database.Beam.Postgres.Extensions.UuidOssp+   other-modules:      Database.Beam.Postgres.Connection                       Database.Beam.Postgres.Debug                       Database.Beam.Postgres.Extensions+                      Database.Beam.Postgres.Extensions.Internal                       Database.Beam.Postgres.PgSpecific                       Database.Beam.Postgres.Types -  build-depends:      base                 >=4.7  && <5.0,-                      beam-core            >=0.8  && <0.9,-                      beam-migrate         >=0.4  && <0.5,+  build-depends:      base                 >=4.9  && <5.0,+                      beam-core            >=0.9  && <0.10,+                      beam-migrate         >=0.5  && <0.6,                        postgresql-libpq     >=0.8  && <0.10,                       postgresql-simple    >=0.5  && <0.7,@@ -40,7 +43,7 @@                       bytestring           >=0.10 && <0.11,                        attoparsec           >=0.13 && <0.14,-                      hashable             >=1.1  && <1.3,+                      hashable             >=1.1  && <1.4,                       lifted-base          >=0.2  && <0.3,                       free                 >=4.12 && <5.2,                       time                 >=1.6  && <1.10,@@ -56,14 +59,14 @@                       unordered-containers >= 0.2 && <0.3,                       tagged               >=0.8  && <0.9, -                      haskell-src-exts     >=1.18 && <1.22+                      haskell-src-exts     >=1.18 && <1.24   default-language:   Haskell2010   default-extensions: ScopedTypeVariables, OverloadedStrings, MultiParamTypeClasses, RankNTypes, FlexibleInstances,                       DeriveDataTypeable, DeriveGeneric, StandaloneDeriving, TypeFamilies, GADTs, OverloadedStrings,                       CPP, TypeApplications, FlexibleContexts   ghc-options:        -Wall   if flag(werror)-    ghc-options:       -Werror+    ghc-options: -Werror  test-suite beam-postgres-tests   type: exitcode-stdio-1.0@@ -74,8 +77,21 @@                  Database.Beam.Postgres.Test.Select,                  Database.Beam.Postgres.Test.DataTypes,                  Database.Beam.Postgres.Test.Migrate-  build-depends: base, beam-core, beam-migrate, beam-postgres, text, bytestring, tasty, tasty-hunit,-                 postgresql-simple, process, temporary, hedgehog, uuid, filepath, directory+  build-depends:+    aeson,+    base,+    beam-core,+    beam-migrate,+    beam-postgres,+    bytestring,+    hedgehog,+    postgresql-simple,+    tasty-hunit,+    tasty,+    text,+    tmp-postgres,+    uuid,+    vector   default-language: Haskell2010   default-extensions: OverloadedStrings, FlexibleInstances, FlexibleContexts, TypeFamilies,                       ScopedTypeVariables, MultiParamTypeClasses, TypeApplications, DeriveGeneric,@@ -88,5 +104,5 @@  source-repository head   type: git-  location: https://github.com/tathougies/beam.git+  location: https://github.com/haskell-beam/beam.git   subdir: beam-postgres
test/Database/Beam/Postgres/Test.hs view
@@ -7,8 +7,7 @@  import qualified Database.PostgreSQL.Simple as Pg -import           Control.Exception (SomeException(..), bracket, catch)-import           Control.Concurrent (threadDelay)+import           Control.Exception (bracket)  import           Control.Monad (void) #if MIN_VERSION_base(4,12,0)@@ -16,16 +15,10 @@ #endif  import           Data.ByteString (ByteString)-import           Data.Semigroup import           Data.String  import qualified Hedgehog -import           System.IO.Temp-import           System.Process-import           System.Exit-import           System.FilePath-import           System.Directory  withTestPostgres :: String -> IO ByteString -> (Pg.Connection -> IO a) -> IO a withTestPostgres dbName getConnStr action = do@@ -38,51 +31,22 @@       withTemplate1 = bracket (Pg.connectPostgreSQL connStrTemplate1) Pg.close        createDatabase = withTemplate1 $ \c -> do-                         Pg.execute_ c (fromString ("CREATE DATABASE " <> dbName))+                         void $ Pg.execute_ c (fromString ("CREATE DATABASE " <> dbName))                           Pg.connectPostgreSQL connStrDb       dropDatabase c = do         Pg.close c-        withTemplate1 $ \c' -> do-            Pg.execute_ c' (fromString ("DROP DATABASE " <> dbName))-            pure ()+        withTemplate1 $ \c' -> void $+          Pg.execute_ c' (fromString ("DROP DATABASE " <> dbName))    bracket createDatabase dropDatabase action -startTempPostgres :: IO (ByteString, IO ())-startTempPostgres = do-  tmpDir <- getCanonicalTemporaryDirectory-  pgDataDir <- createTempDirectory tmpDir "postgres-data"--  callProcess "pg_ctl" [ "init", "-D", pgDataDir ]--  -- Use 'D' because otherwise, the path is too long on OS X-  pgHdl <- spawnProcess "postgres"-                        [ "-D", pgDataDir-                        , "-k", pgDataDir, "-h", "" ]--  putStrLn ("Using " ++ pgDataDir ++ " as postgres host")--  let waitForPort 10 = fail "Could not connect to postgres"-      waitForPort n = do-        (code, stdout, stderr) <- readProcessWithExitCode "pg_ctl" [ "status", "-D", pgDataDir ] ""-        case code of-          ExitSuccess -> waitForSocket 0-          ExitFailure _ -> threadDelay 1000000 >> waitForPort (n + 1)--      waitForSocket 10 = fail "Could not connect to postgres (waitForSocket)"-      waitForSocket n = do-        skExists <- doesFileExist (pgDataDir </> ".s.PGSQL.5432")-        if skExists then pure () else threadDelay 1000000 >> waitForSocket (n + 1)--  waitForPort 0-  putStrLn "Completed waiting for postgres"--  pure ( fromString ("host=" ++ pgDataDir)-       , void (callProcess "pg_ctl" [ "stop", "-D", pgDataDir ]))- #if MIN_VERSION_base(4,12,0)+#if !MIN_VERSION_hedgehog(1,0,0) -- TODO orphan instances are bad+-- Would be easier to say 'build-depends: hedgehog >= 1.0',+-- but it's difficult to propagate to older Stackage snapshots instance Monad m => MonadFail (Hedgehog.PropertyT m) where     fail _ = Hedgehog.failure+#endif #endif
test/Database/Beam/Postgres/Test/DataTypes.hs view
@@ -4,7 +4,6 @@  import Database.Beam import Database.Beam.Postgres-import Database.Beam.Postgres.Migrate import Database.Beam.Postgres.Test import Database.Beam.Migrate import Database.Beam.Backend.SQL.BeamExtensions@@ -12,6 +11,7 @@ import Control.Exception (SomeException(..), handle)  import Data.ByteString (ByteString)+import Data.Int import Data.Text (Text)  import Test.Tasty@@ -25,12 +25,12 @@  data JsonT f     = JsonT-    { _key :: C f Int+    { _key :: C f Int32     , _field1 :: C f (PgJSON String) }     deriving (Generic, Beamable)  instance Table JsonT where-    data PrimaryKey JsonT f = JsonKey (C f Int)+    data PrimaryKey JsonT f = JsonKey (C f Int32)       deriving (Generic, Beamable)     primaryKey = JsonKey <$> _key @@ -39,7 +39,7 @@     { jsonTable :: entity (TableEntity JsonT) }     deriving (Generic, Database Postgres) --- | Regression test for <https://github.com/tathougies/beam/issues/297 #297>+-- | Regression test for <https://github.com/haskell-beam/beam/issues/297 #297> jsonNulTest :: IO ByteString -> TestTree jsonNulTest pgConn =     testCase "JSON NUL handling (#297)" $@@ -68,7 +68,7 @@           fmap (fmap (\(PgJSON v) -> v)) $             runSelectReturningList $ select $             fmap (\(JsonT _ v) -> v) $-            orderBy_ (\(JsonT pk _) -> asc_ pk) $+            orderBy_ (\(JsonT k _) -> asc_ k) $             all_ (jsonTable db)        readback @?= [ "hello\0world"@@ -81,23 +81,23 @@       return ()  data TblT f-    = Tbl { _tblKey :: C f Int, _tblValue :: C f Text }+    = Tbl { _tblKey :: C f Int32, _tblValue :: C f Text }       deriving (Generic, Beamable)  deriving instance Show (TblT Identity) deriving instance Eq (TblT Identity)  instance Table TblT where-    data PrimaryKey TblT f = TblKey (C f Int)+    data PrimaryKey TblT f = TblKey (C f Int32)       deriving (Generic, Beamable)     primaryKey = TblKey <$> _tblKey  data WrongTblT f-    = WrongTbl { _wrongTblKey :: C f Int, _wrongTblValue :: C f Int }+    = WrongTbl { _wrongTblKey :: C f Int32, _wrongTblValue :: C f Int32 }       deriving (Generic, Beamable)  instance Table WrongTblT where-    data PrimaryKey WrongTblT f = WrongTblKey (C f Int)+    data PrimaryKey WrongTblT f = WrongTblKey (C f Int32)       deriving (Generic, Beamable)     primaryKey = WrongTblKey <$> _wrongTblKey @@ -109,7 +109,7 @@     = WrongDb { _wrongTbl :: entity (TableEntity WrongTblT) }       deriving (Generic, Database Postgres) --- | Regression test for <https://github.com/tathougies/beam/issues/112>+-- | Regression test for <https://github.com/haskell-beam/beam/issues/112> errorOnSchemaMismatch :: IO ByteString -> TestTree errorOnSchemaMismatch pgConn =     testCase "runInsertReturningList should error on schema mismatch (#112)" $@@ -129,7 +129,7 @@                                                         (WrongTbl (field "key" int notNull)                                                                   (field "value" int notNull))) -      didFail <- handle (\(e :: SomeException) -> pure True) $+      didFail <- handle (\(_ :: SomeException) -> pure True) $         runBeamPostgres conn $ do           _ <- runInsertReturningList $ insert (_wrongTbl wrongDb) $ insertValues [ WrongTbl 4 23, WrongTbl 5 24, WrongTbl 6 24 ]           pure False
test/Database/Beam/Postgres/Test/Marshal.hs view
@@ -9,15 +9,12 @@ import           Database.Beam.Postgres import           Database.Beam.Postgres.Migrate (migrationBackend) import           Database.Beam.Postgres.Test-import qualified Database.PostgreSQL.Simple as Pg  import           Data.ByteString (ByteString) import           Data.Functor.Classes import           Data.Int import           Data.Proxy (Proxy(..))-import           Data.Semigroup import qualified Data.Text as T-import qualified Data.Text.Lazy as TL import           Data.Typeable import           Data.UUID (UUID, fromWords) import           Data.Word@@ -32,6 +29,9 @@  import           Unsafe.Coerce +textGen :: Hedgehog.Gen T.Text+textGen = Gen.text (Range.constant 0 1000) $ Gen.filter (/= '\NUL') Gen.unicode+ uuidGen :: Hedgehog.Gen UUID uuidGen = fromWords <$> Gen.integral Range.constantBounded                     <*> Gen.integral Range.constantBounded@@ -72,7 +72,7 @@     , marshalTest (Gen.integral (Range.constantBounded @Word16)) postgresConn     , marshalTest (Gen.integral (Range.constantBounded @Word32)) postgresConn     , marshalTest (Gen.integral (Range.constantBounded @Word64)) postgresConn-    , marshalTest (Gen.text (Range.constant 0 1000) Gen.unicode) postgresConn+    , marshalTest textGen postgresConn     , marshalTest uuidGen postgresConn      , marshalTest' (\a b -> Hedgehog.assert (ptCmp a b))  pointGen postgresConn@@ -85,7 +85,7 @@     , marshalTest (Gen.maybe (Gen.integral (Range.constantBounded @Word16))) postgresConn     , marshalTest (Gen.maybe (Gen.integral (Range.constantBounded @Word32))) postgresConn     , marshalTest (Gen.maybe (Gen.integral (Range.constantBounded @Word64))) postgresConn-    , marshalTest (Gen.maybe (Gen.text (Range.constant 0 1000) Gen.unicode)) postgresConn+    , marshalTest (Gen.maybe textGen) postgresConn     , marshalTest (Gen.maybe uuidGen) postgresConn      , marshalTest' (\a b -> Hedgehog.assert (liftEq ptCmp a b))  (Gen.maybe pointGen) postgresConn@@ -104,13 +104,13 @@  data MarshalTable a f     = MarshalTable-    { _marshalTableId    :: C f (SqlSerial Int)+    { _marshalTableId    :: C f (SqlSerial Int32)     , _marshalTableEntry :: C f a     } deriving (Generic) instance Beamable (MarshalTable a)  instance Typeable a => Table (MarshalTable a) where-    data PrimaryKey (MarshalTable a) f = MarshalTableKey (C f (SqlSerial Int))+    data PrimaryKey (MarshalTable a) f = MarshalTableKey (C f (SqlSerial Int32))       deriving (Generic, Beamable)     primaryKey = MarshalTableKey . _marshalTableId 
test/Database/Beam/Postgres/Test/Migrate.hs view
@@ -3,6 +3,7 @@ import Database.Beam import Database.Beam.Postgres import Database.Beam.Postgres.Migrate+import Database.Beam.Postgres.PgCrypto (PgCrypto) import Database.Beam.Postgres.Test import Database.Beam.Migrate import Database.Beam.Migrate.Simple@@ -20,6 +21,7 @@       , charNoWidthVerification postgresConn "VARCHAR" varchar       , charWidthVerification postgresConn "CHAR" char       , charNoWidthVerification postgresConn "CHAR" char+      , extensionVerification postgresConn       ]  data CharT f@@ -37,6 +39,11 @@     { vcTbl :: entity (TableEntity CharT) }     deriving (Generic, Database Postgres) +data CryptoDb entity+    = CryptoDb+    { cryptoExtension :: entity (PgExtensionEntity PgCrypto) }+    deriving (Generic, Database Postgres)+ -- | Verifies that 'verifySchema' correctly checks the width of -- @VARCHAR@ or @CHAR@ columns. charWidthVerification :: IO ByteString -> String -> (Maybe Word -> DataType Postgres Text) -> TestTree@@ -68,5 +75,24 @@           res <- verifySchema migrationBackend db            case res of+            VerificationSucceeded -> return ()+            VerificationFailed failures -> fail ("Verification failed: " ++ show failures)++-- | Verifies that 'verifySchema' correctly checks enabled PgCrypto extension+extensionVerification :: IO ByteString -> TestTree+extensionVerification pgConn =+    testCase "verifySchema correctly checks enabled PgCrypto extension" $+      withTestPostgres "db_extension_pgcrypto" pgConn $ \conn ->+        runBeamPostgres conn $ do+          let migration = CryptoDb <$> pgCreateExtension+          dbBefore <- executeMigration (const $ return ()) migration+          resBefore <- verifySchema migrationBackend dbBefore+          case resBefore of+            VerificationSucceeded -> fail "Verification succeeded before migration when it should have failed"+            VerificationFailed _ -> return ()++          dbAfter <- executeMigration runNoReturn migration+          resAfter <- verifySchema migrationBackend dbAfter+          case resAfter of             VerificationSucceeded -> return ()             VerificationFailed failures -> fail ("Verification failed: " ++ show failures)
test/Database/Beam/Postgres/Test/Select.hs view
@@ -1,36 +1,105 @@-module Database.Beam.Postgres.Test.Select where+{-# LANGUAGE LambdaCase #-} +module Database.Beam.Postgres.Test.Select (tests) where++import           Data.Aeson+import           Data.ByteString (ByteString)+import           Data.Int+import           Data.Text (Text)+import qualified Data.Vector as V+import           Test.Tasty+import           Test.Tasty.HUnit+import           Data.UUID (UUID, nil)+ import           Database.Beam-import           Database.Beam.Backend.SQL-import           Database.Beam.Backend.SQL.BeamExtensions+import           Database.Beam.Backend.SQL.SQL92 import           Database.Beam.Migrate-import           Database.Beam.Migrate.Simple (autoMigrate) import           Database.Beam.Postgres-import           Database.Beam.Postgres.Migrate (migrationBackend)+import           Database.Beam.Postgres.Extensions.UuidOssp+ import           Database.Beam.Postgres.Test-import qualified Database.PostgreSQL.Simple as Pg -import           Data.ByteString (ByteString)-import           Data.Functor.Classes-import           Data.Int-import           Data.Proxy (Proxy(..))-import           Data.Semigroup-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import           Data.Typeable-import           Data.UUID (UUID, fromWords)-import           Data.Word+tests :: IO ByteString -> TestTree+tests getConn = testGroup "Selection Tests"+  [ testGroup "JSON"+      [ testPgArrayToJSON getConn+      ]+  , testGroup "UUID"+      [ testUuidFunction getConn "uuid_nil" pgUuidNil+      , testUuidFunction getConn "uuid_ns_dns" pgUuidNsDns+      , testUuidFunction getConn "uuid_ns_url" pgUuidNsUrl+      , testUuidFunction getConn "uuid_ns_oid" pgUuidNsOid+      , testUuidFunction getConn "uuid_ns_x500" pgUuidNsX500+      , testUuidFunction getConn "uuid_generate_v1" pgUuidGenerateV1+      , testUuidFunction getConn "uuid_generate_v1mc" pgUuidGenerateV1Mc+      , testUuidFunction getConn "uuid_generate_v3" $ \ext ->+          pgUuidGenerateV3 ext (val_ nil) "nil"+      , testUuidFunction getConn "uuid_generate_v4" pgUuidGenerateV4+      , testUuidFunction getConn "uuid_generate_v5" $ \ext ->+          pgUuidGenerateV5 ext (val_ nil) "nil"+      ]+  , testInRowValues getConn+  , testReturningMany getConn+  ] -import qualified Hedgehog-import           Hedgehog ((===))-import qualified Hedgehog.Gen as Gen-import qualified Hedgehog.Range as Range+testPgArrayToJSON :: IO ByteString -> TestTree+testPgArrayToJSON getConn = testFunction getConn "array_to_json" $ \conn -> do+  let values :: [Int32] = [1, 2, 3]+  actual :: [PgJSON Value] <-+    runBeamPostgres conn $ runSelectReturningList $ select $+      return $ pgArrayToJson $ val_ $ V.fromList values+  assertEqual "JSON list" [PgJSON $ toJSON values] actual -import           Test.Tasty-import           Test.Tasty.HUnit+data UuidSchema f = UuidSchema+  { _uuidOssp :: f (PgExtensionEntity UuidOssp)+  } deriving (Generic, Database Postgres) -import           Unsafe.Coerce+testUuidFunction+  :: IO ByteString+  -> String+  -> (forall s. UuidOssp -> QExpr Postgres s UUID)+  -> TestTree+testUuidFunction getConn name mkUuid = testFunction getConn name $ \conn ->+  runBeamPostgres conn $ do+    db <- executeMigration runNoReturn $ UuidSchema <$>+      pgCreateExtension @UuidOssp+    [_] <- runSelectReturningList $ select $+      return $ mkUuid $ getPgExtension $ _uuidOssp $ unCheckDatabase db+    return () -tests :: IO ByteString -> TestTree-tests postgresConn =-    testGroup "Postgres Select Tests" []+data Pair f = Pair+  { _left :: C f Bool+  , _right :: C f Bool+  } deriving (Generic, Beamable)++testInRowValues :: IO ByteString -> TestTree+testInRowValues getConn = testCase "IN with row values works" $+  withTestPostgres "db_in_row_values" getConn $ \conn -> do+    result <- runBeamPostgres conn $ runSelectReturningList $ select $ do+      let p :: forall ctx s. Pair (QGenExpr ctx Postgres s)+          p = val_ $ Pair False False+      return $ p `in_` [p, p]+    assertEqual "result" [True] result++testReturningMany :: IO ByteString -> TestTree+testReturningMany getConn = testCase "runReturningMany (batching via cursor) works" $+  withTestPostgres "run_returning_many_cursor" getConn $ \conn -> do+    result <- runBeamPostgres conn $ runSelectReturningMany+      (select $ pgUnnestArray $ array_ $ (as_ @Int32 . val_) <$> [0..rowCount - 1])+      (\fetch ->+        let count n = fetch >>= \case+              Nothing -> pure n+              Just _  -> count (n + 1)+        in count 0)+    assertEqual "result" rowCount result+ where+  rowCount = 500+  runSelectReturningMany ::+    (FromBackendRow Postgres x) =>+    SqlSelect Postgres x -> (Pg (Maybe x) -> Pg a) -> Pg a+  runSelectReturningMany (SqlSelect s) =+    runReturningMany (selectCmd s)++testFunction :: IO ByteString -> String -> (Connection -> Assertion) -> TestTree+testFunction getConn name mkAssertion = testCase name $+  withTestPostgres name getConn mkAssertion
test/Main.hs view
@@ -1,17 +1,23 @@ module Main where +import qualified Database.Postgres.Temp as TempDb import Test.Tasty -import Database.Beam.Postgres.Test (startTempPostgres) import qualified Database.Beam.Postgres.Test.Select as Select import qualified Database.Beam.Postgres.Test.Marshal as Marshal import qualified Database.Beam.Postgres.Test.DataTypes as DataType import qualified Database.Beam.Postgres.Test.Migrate as Migrate  main :: IO ()-main = defaultMain (withResource startTempPostgres snd $ \getConnStr ->-                    testGroup "beam-postgres tests"-                              [ Marshal.tests (fst <$> getConnStr)-                              , Select.tests  (fst <$> getConnStr)-                              , DataType.tests (fst <$> getConnStr)-                              , Migrate.tests (fst <$> getConnStr) ])+main = defaultMain $ withDb $ \getDb ->+  let getConnStr = TempDb.toConnectionString <$> getDb+  in testGroup "beam-postgres tests"+      [ Marshal.tests getConnStr+      , Select.tests getConnStr+      , DataType.tests getConnStr+      , Migrate.tests getConnStr+      ]+  where+    withDb = withResource+      (either (\e -> error $ "Failed to start DB: " <> show e) pure =<< TempDb.startConfig mempty)+      TempDb.stop