beam-postgres 0.5.4.2 → 0.5.4.3
raw patch · 10 files changed
+193/−131 lines, 10 filesdep −haskell-src-extsdep ~basedep ~timePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: haskell-src-exts
Dependency ranges changed: base, time
API changes (from Hackage documentation)
- Database.Beam.Postgres.Full: instance GHC.Internal.Base.Monoid (Database.Beam.Postgres.Full.PgLockedTables s)
- Database.Beam.Postgres.Full: instance GHC.Internal.Base.Semigroup (Database.Beam.Postgres.Full.PgLockedTables s)
- Database.Beam.Postgres.Migrate: instance GHC.Internal.Generics.Generic Database.Beam.Postgres.Migrate.SchemaName
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Int.Int16
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Int.Int32
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Int.Int64
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Int.Int8
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Word.Word16
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Word.Word32
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Word.Word64
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Internal.Word.Word8
- Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax x => Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax (GHC.Internal.Maybe.Maybe x)
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Base.Functor Database.Beam.Postgres.Syntax.PgSyntaxF
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Base.Monoid (Database.Beam.Query.CustomSQL.CustomSqlSyntax Database.Beam.Postgres.Syntax.PgExpressionSyntax)
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Base.Monoid Database.Beam.Postgres.Syntax.PgSyntax
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Base.Semigroup (Database.Beam.Query.CustomSQL.CustomSqlSyntax Database.Beam.Postgres.Syntax.PgExpressionSyntax)
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Base.Semigroup Database.Beam.Postgres.Syntax.PgSyntax
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Data.String.IsString (Database.Beam.Query.CustomSQL.CustomSqlSyntax Database.Beam.Postgres.Syntax.PgExpressionSyntax)
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Data.String.IsString Database.Beam.Postgres.Syntax.PgSyntaxPrim
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Enum.Bounded Database.Beam.Postgres.Syntax.PgEscapeType
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Enum.Enum Database.Beam.Postgres.Syntax.PgEscapeType
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Generics.Generic Database.Beam.Postgres.Syntax.PgDataTypeDescr
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Generics.Generic Database.Beam.Postgres.Syntax.PgHasEnum
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Generics.Generic Database.Beam.Postgres.Syntax.PgNullOrdering
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Generics.Generic Database.Beam.Postgres.Syntax.PgSelectLockingOptions
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Generics.Generic Database.Beam.Postgres.Syntax.PgSelectLockingStrength
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgColumnConstraintDefinitionSyntax
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgColumnSchemaSyntax
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgCommandType
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgDataTypeDescr
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgDataTypeSyntax
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgEscapeType
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgHasEnum
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgNullOrdering
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgSelectLockingOptions
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgSelectLockingStrength
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgSyntax
- Database.Beam.Postgres.Syntax: instance GHC.Internal.Show.Show Database.Beam.Postgres.Syntax.PgSyntaxPrim
+ Database.Beam.Postgres.Full: instance GHC.Base.Monoid (Database.Beam.Postgres.Full.PgLockedTables s)
+ Database.Beam.Postgres.Full: instance GHC.Base.Semigroup (Database.Beam.Postgres.Full.PgLockedTables s)
+ Database.Beam.Postgres.Full: pgSelectWith :: forall (db :: (Type -> Type) -> Type) s res. Projectible Postgres res => With Postgres db (Q Postgres db s res) -> Q Postgres db s res
+ Database.Beam.Postgres.Migrate: instance GHC.Generics.Generic Database.Beam.Postgres.Migrate.SchemaName
+ Database.Beam.Postgres.Syntax: instance Data.String.IsString (Database.Beam.Query.CustomSQL.CustomSqlSyntax Database.Beam.Postgres.Syntax.PgExpressionSyntax)
+ Database.Beam.Postgres.Syntax: instance Data.String.IsString Database.Beam.Postgres.Syntax.PgSyntaxPrim
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Int.Int16
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Int.Int32
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Int.Int64
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Int.Int8
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Word.Word16
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Word.Word32
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Word.Word64
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax GHC.Word.Word8
+ Database.Beam.Postgres.Syntax: instance Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax x => Database.Beam.Backend.SQL.SQL92.HasSqlValueSyntax Database.Beam.Postgres.Syntax.PgValueSyntax (GHC.Maybe.Maybe x)
+ Database.Beam.Postgres.Syntax: instance GHC.Base.Functor Database.Beam.Postgres.Syntax.PgSyntaxF
+ Database.Beam.Postgres.Syntax: instance GHC.Base.Monoid (Database.Beam.Query.CustomSQL.CustomSqlSyntax Database.Beam.Postgres.Syntax.PgExpressionSyntax)
+ Database.Beam.Postgres.Syntax: instance GHC.Base.Monoid Database.Beam.Postgres.Syntax.PgSyntax
+ Database.Beam.Postgres.Syntax: instance GHC.Base.Semigroup (Database.Beam.Query.CustomSQL.CustomSqlSyntax Database.Beam.Postgres.Syntax.PgExpressionSyntax)
+ Database.Beam.Postgres.Syntax: instance GHC.Base.Semigroup Database.Beam.Postgres.Syntax.PgSyntax
+ Database.Beam.Postgres.Syntax: instance GHC.Enum.Bounded Database.Beam.Postgres.Syntax.PgEscapeType
+ Database.Beam.Postgres.Syntax: instance GHC.Enum.Enum Database.Beam.Postgres.Syntax.PgEscapeType
+ Database.Beam.Postgres.Syntax: instance GHC.Generics.Generic Database.Beam.Postgres.Syntax.PgDataTypeDescr
+ Database.Beam.Postgres.Syntax: instance GHC.Generics.Generic Database.Beam.Postgres.Syntax.PgHasEnum
+ Database.Beam.Postgres.Syntax: instance GHC.Generics.Generic Database.Beam.Postgres.Syntax.PgNullOrdering
+ Database.Beam.Postgres.Syntax: instance GHC.Generics.Generic Database.Beam.Postgres.Syntax.PgSelectLockingOptions
+ Database.Beam.Postgres.Syntax: instance GHC.Generics.Generic Database.Beam.Postgres.Syntax.PgSelectLockingStrength
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgColumnConstraintDefinitionSyntax
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgColumnSchemaSyntax
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgCommandType
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgDataTypeDescr
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgDataTypeSyntax
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgEscapeType
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgHasEnum
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgNullOrdering
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgSelectLockingOptions
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgSelectLockingStrength
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgSyntax
+ Database.Beam.Postgres.Syntax: instance GHC.Show.Show Database.Beam.Postgres.Syntax.PgSyntaxPrim
Files
- ChangeLog.md +12/−1
- Database/Beam/Postgres/Conduit.hs +0/−3
- Database/Beam/Postgres/Connection.hs +4/−7
- Database/Beam/Postgres/Extensions.hs +0/−3
- Database/Beam/Postgres/Full.hs +42/−4
- Database/Beam/Postgres/Migrate.hs +41/−29
- Database/Beam/Postgres/PgSpecific.hs +0/−3
- Database/Beam/Postgres/Syntax.hs +65/−7
- beam-postgres.cabal +8/−4
- test/Database/Beam/Postgres/Test/Marshal.hs +21/−70
ChangeLog.md view
@@ -1,3 +1,14 @@+# 0.5.4.3++## Added features++ * Added `pgSelectWith`, a combinator like `selectWith` which allows to nest common table expressions in subqueries (#720).++## Bug fixes++ * Added the ability to migrate Postgres' array types (#354).+ * Remove dependency on `haskell-src-exts`, which was not in use anymore.+ # 0.5.4.2 ## Bug fixes@@ -18,7 +29,7 @@ * Added support for creating and dropping database schemas and associated tables with `createDatabaseSchema`, `dropDatabaseSchema`, and `createTableWithSchema` (#716). ## Documentation- + * Make `runBeamPostgres` and `runBeamPostgresDebug` easier to find (#663). # 0.5.3.1
Database/Beam/Postgres/Conduit.hs view
@@ -48,9 +48,6 @@ import qualified Conduit as C import Data.Int (Int64) import Data.Maybe (fromMaybe)-#if !MIN_VERSION_base(4, 11, 0)-import Data.Semigroup-#endif import qualified Control.Monad.Fail as Fail
Database/Beam/Postgres/Connection.hs view
@@ -67,9 +67,6 @@ import qualified Data.Text as T import Data.Text.Encoding (decodeUtf8) import Data.Typeable (cast)-#if !MIN_VERSION_base(4, 11, 0)-import Data.Semigroup-#endif import Foreign.C.Types @@ -155,13 +152,13 @@ Pg.ConversionFailed { Pg.errSQLType = sql , Pg.errHaskellType = hs , Pg.errMessage = msg- , Pg.errSQLField = field } ->- pure (ColumnTypeMismatch hs sql ("Conversion failed for field'" <> field <> "': " <> msg))+ , Pg.errSQLField = errField } ->+ pure (ColumnTypeMismatch hs sql ("Conversion failed for field'" <> errField <> "': " <> msg)) Pg.Incompatible { Pg.errSQLType = sql , Pg.errHaskellType = hs , Pg.errMessage = msg- , Pg.errSQLField = field } ->- pure (ColumnTypeMismatch hs sql ("Incompatible field: '" <> field <> "': " <> msg))+ , Pg.errSQLField = errField } ->+ pure (ColumnTypeMismatch hs sql ("Incompatible field: '" <> errField <> "': " <> msg)) Pg.UnexpectedNull {} -> pure ColumnUnexpectedNull in pure (Left (BeamRowReadError (Just (fromIntegral curCol)) err))
Database/Beam/Postgres/Extensions.hs view
@@ -27,9 +27,6 @@ import Data.Hashable (Hashable) import Data.Proxy import Data.Text (Text)-#if !MIN_VERSION_base(4, 11, 0)-import Data.Semigroup-#endif -- *** Embedding extensions in databases
Database/Beam/Postgres/Full.hs view
@@ -20,6 +20,9 @@ , locked_, lockAll_, withLocks_ + -- ** Inner WITH queries+ , pgSelectWith+ -- ** Lateral joins , lateral_ @@ -55,22 +58,22 @@ ) where import Database.Beam hiding (insert, insertValues)-import Database.Beam.Query.Internal import Database.Beam.Backend.SQL import Database.Beam.Backend.SQL.BeamExtensions+import qualified Database.Beam.Query.CTE as CTE+import Database.Beam.Query.Internal import Database.Beam.Schema.Tables import Database.Beam.Postgres.Types import Database.Beam.Postgres.Syntax import Control.Monad.Free.Church+import Control.Monad.State.Strict (evalState)+import Control.Monad.Writer (runWriterT) import Data.Kind (Type) import Data.Proxy (Proxy(..)) import qualified Data.Text as T-#if !MIN_VERSION_base(4, 11, 0)-import Data.Semigroup-#endif -- * @SELECT@ @@ -273,6 +276,41 @@ fromPgFrom a <> emit " JOIN LATERAL " <> fromPgFrom b <> emit " ON " <> fromPgExpression on'') (\_ -> Nothing) (rewriteThread (Proxy @s))))++-- | The SQL standard only allows CTE expressions (WITH expressions)+-- at the top-level. Postgres allows you to embed these within a+-- subquery.+--+-- For example,+--+-- @+-- SELECT a.column1, b.column2 FROM (WITH RECURSIVE ... ) a JOIN b+-- @+--+-- @beam-core@ offers 'selectWith' to produce a top-level 'SqlSelect'+-- but these cannot be turned into 'Q' objects for use within joins.+--+-- The 'pgSelectWith' function is more flexible and indeed+-- 'selectWith' for @beam-postgres@ is equivalent to se+pgSelectWith :: forall db s res+ . Projectible Postgres res+ => With Postgres db (Q Postgres db s res) -> Q Postgres db s res+pgSelectWith (CTE.With mkQ) =+ let (q, (recursiveness, ctes)) = evalState (runWriterT mkQ) 0+ fromSyntax tblPfx =+ case recursiveness of+ CTE.Nonrecursive -> withSyntax ctes (buildSqlQuery tblPfx q)+ CTE.Recursive -> withRecursiveSyntax ctes (buildSqlQuery tblPfx q)+ in Q (liftF (QAll (\tblPfx tName ->+ let (_, names) = mkFieldNames @Postgres @res (qualifiedField tName)+ in fromTable (PgTableSourceSyntax $+ mconcat [ emit "(", fromPgSelect (fromSyntax tblPfx), emit ")" ])+ (Just (tName, Just names)))+ (\tName ->+ let (projection, _) = mkFieldNames @Postgres @res (qualifiedField tName)+ in projection)+ (\_ -> Nothing)+ snd)) -- | By default, Postgres will throw an error when a conflict is detected. This -- preserves that functionality.
Database/Beam/Postgres/Migrate.hs view
@@ -55,7 +55,7 @@ import Control.Applicative ((<|>)) import Control.Arrow-import Control.Exception (bracket)+import Control.Exception.Lifted (mask, onException) import Control.Monad import Data.Aeson hiding (json)@@ -72,11 +72,7 @@ import Data.Typeable import Data.UUID.Types (UUID) import qualified Data.Vector as V-#if !MIN_VERSION_base(4, 11, 0) import Data.Semigroup-#else-import Data.Monoid (Endo(..))-#endif import Data.Word (Word64) import GHC.Generics ( Generic )@@ -84,30 +80,46 @@ -- | Top-level migration backend for use by @beam-migrate@ tools migrationBackend :: Tool.BeamMigrationBackend Postgres Pg migrationBackend = Tool.BeamMigrationBackend- "postgres"- (unlines [ "For beam-postgres, this is a libpq connection string which can either be a list of key value pairs or a URI"- , ""- , "For example, 'host=localhost port=5432 dbname=mydb connect_timeout=10' or 'dbname=mydb'"- , ""- , "Or use URIs, for which the general form is:"- , " 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" ])- (liftIOWithHandle getDbConstraints)- (Db.sql92Deserializers <> Db.sql99DataTypeDeserializers <>- Db.sql2008BigIntDataTypeDeserializers <>- postgresDataTypeDeserializers <>- Db.beamCheckDeserializers)- (BCL.unpack . (<> ";") . pgRenderSyntaxScript . fromPgCommand) "postgres.sql"- pgPredConverter (mconcat [ defaultActionProvider- , defaultSchemaActionProvider- , pgExtensionActionProvider- , pgCustomEnumActionProvider- ]- )- (\options action ->- bracket (Pg.connectPostgreSQL (fromString options)) Pg.close $ \conn ->- left show <$> withPgDebug (\_ -> pure ()) conn action)+ { Tool.backendName = "postgres"+ , Tool.backendConnStringExplanation =+ unlines [ "For beam-postgres, this is a libpq connection string which can either be a list of key value pairs or a URI"+ , ""+ , "For example, 'host=localhost port=5432 dbname=mydb connect_timeout=10' or 'dbname=mydb'"+ , ""+ , "Or use URIs, for which the general form is:"+ , " 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" ]+ , Tool.backendGetDbConstraints = liftIOWithHandle getDbConstraints+ , Tool.backendPredicateParsers =+ Db.sql92Deserializers <> Db.sql99DataTypeDeserializers <>+ Db.sql2008BigIntDataTypeDeserializers <>+ postgresDataTypeDeserializers <>+ Db.beamCheckDeserializers+ , Tool.backendRenderSyntax = (BCL.unpack . (<> ";") . pgRenderSyntaxScript . fromPgCommand)+ , Tool.backendFileExtension = "postgres.sql"+ , Tool.backendConvertToHaskell = pgPredConverter+ , Tool.backendActionProvider =+ mconcat [ defaultActionProvider+ , defaultSchemaActionProvider+ , pgExtensionActionProvider+ , pgCustomEnumActionProvider+ ]+ , Tool.backendRunSqlScript = \t -> liftIOWithHandle (\hdl -> void $ Pg.execute_ hdl (Pg.Query (TE.encodeUtf8 t)))+ , Tool.backendWithTransaction =+ \go -> mask $ \unmask -> do+ liftIOWithHandle Pg.begin+ x <- unmask go `onException` liftIOWithHandle Pg.rollback+ liftIOWithHandle Pg.commit+ pure x+ , Tool.backendConnect = \options -> do+ conn <- Pg.connectPostgreSQL (fromString options)+ pure Tool.BeamMigrateConnection+ { Tool.backendRun = \action ->+ left show <$> withPgDebug (\_ -> pure ()) conn action+ , Tool.backendClose = Pg.close conn+ }+ } -- | 'BeamDeserializers' for postgres-specific types: --
Database/Beam/Postgres/PgSpecific.hs view
@@ -150,9 +150,6 @@ import Data.Time (LocalTime, NominalDiffTime) import Data.Type.Bool import qualified Data.Vector as V-#if !MIN_VERSION_base(4, 11, 0)-import Data.Semigroup-#endif import qualified Database.PostgreSQL.Simple.FromField as Pg import qualified Database.PostgreSQL.Simple.ToField as Pg
Database/Beam/Postgres/Syntax.hs view
@@ -111,9 +111,6 @@ import Data.Hashable import Data.Int import Data.Maybe-#if !MIN_VERSION_base(4, 11, 0)-import Data.Semigroup-#endif import Data.Scientific (Scientific) import Data.String (IsString(..), fromString) import qualified Data.Text as T@@ -580,8 +577,8 @@ binaryLargeObjectType = pgByteaType { pgDataTypeSerialized = binaryLargeObjectType } booleanType = PgDataTypeSyntax (PgDataTypeDescrOid (Pg.typoid Pg.bool) Nothing) (emit "BOOLEAN") booleanType- arrayType (PgDataTypeSyntax _ syntax serialized) sz =- PgDataTypeSyntax (error "TODO: array migrations")+ arrayType (PgDataTypeSyntax descr syntax serialized) sz =+ PgDataTypeSyntax (PgDataTypeDescrOid (fromMaybe (error "Unsupported array type") (arrayTypeDescr descr)) Nothing) (syntax <> emit "[" <> emit (fromString (show sz)) <> emit "]") (arrayType serialized sz) rowType = error "rowType"@@ -647,11 +644,72 @@ pgLineSegmentType = PgDataTypeSyntax (PgDataTypeDescrOid (Pg.typoid Pg.lseg) Nothing) (emit "LSEG") (pgDataTypeJSON "lseg") pgBoxType = PgDataTypeSyntax (PgDataTypeDescrOid (Pg.typoid Pg.box) Nothing) (emit "BOX") (pgDataTypeJSON "box") +-- TODO: better mechanism to tell, at compile time, that some type+-- cannot be placed in an array pgUnboundedArrayType :: PgDataTypeSyntax -> PgDataTypeSyntax-pgUnboundedArrayType (PgDataTypeSyntax _ syntax serialized) =- PgDataTypeSyntax (error "Can't do array migrations yet")+pgUnboundedArrayType (PgDataTypeSyntax descr syntax serialized) =+ PgDataTypeSyntax (PgDataTypeDescrOid (fromMaybe (error "Unsupported array type") (arrayTypeDescr descr)) Nothing) (syntax <> emit "[]") (pgDataTypeJSON (object [ "unbounded-array" .= fromBeamSerializedDataType serialized ]))++-- TODO: define CPP macro to make sure the left hand side (e.g. `Pg.recordOid`) +-- always matches right hand side (e.g. `Pg.array_recordOid)++-- | Get the Oid of Pg arrays which contains elements of a certain type+arrayTypeDescr :: PgDataTypeDescr -> Maybe Pg.Oid+arrayTypeDescr (PgDataTypeDescrDomain _) = Nothing+arrayTypeDescr (PgDataTypeDescrOid elemOid _)+ | elemOid == Pg.recordOid = Just $ Pg.array_recordOid+ | elemOid == Pg.xmlOid = Just $ Pg.array_xmlOid+ | elemOid == Pg.jsonOid = Just $ Pg.array_jsonOid+ | elemOid == Pg.lineOid = Just $ Pg.array_lineOid+ | elemOid == Pg.cidrOid = Just $ Pg.array_cidOid+ | elemOid == Pg.circleOid = Just $ Pg.array_circleOid+ | elemOid == Pg.moneyOid = Just $ Pg.array_moneyOid+ | elemOid == Pg.boolOid = Just $ Pg.array_boolOid+ | elemOid == Pg.byteaOid = Just $ Pg.array_byteaOid+ | elemOid == Pg.charOid = Just $ Pg.array_charOid+ | elemOid == Pg.nameOid = Just $ Pg.array_nameOid+ | elemOid == Pg.int2Oid = Just $ Pg.array_int2Oid+ | elemOid == Pg.int2vectorOid = Just $ Pg.array_int2vectorOid+ | elemOid == Pg.int4Oid = Just $ Pg.array_int4Oid+ | elemOid == Pg.regprocOid = Just $ Pg.array_regprocOid+ | elemOid == Pg.textOid = Just $ Pg.array_textOid+ | elemOid == Pg.tidOid = Just $ Pg.array_tidOid+ | elemOid == Pg.xidOid = Just $ Pg.array_xidOid+ | elemOid == Pg.cidOid = Just $ Pg.array_cidOid+ | elemOid == Pg.bpcharOid = Just $ Pg.array_bpcharOid+ | elemOid == Pg.varcharOid = Just $ Pg.array_varcharOid+ | elemOid == Pg.int8Oid = Just $ Pg.array_int8Oid+ | elemOid == Pg.pointOid = Just $ Pg.array_pointOid+ | elemOid == Pg.lsegOid = Just $ Pg.array_lsegOid+ | elemOid == Pg.pathOid = Just $ Pg.array_pathOid+ | elemOid == Pg.boxOid = Just $ Pg.array_boxOid+ | elemOid == Pg.float4Oid = Just $ Pg.array_float4Oid+ | elemOid == Pg.float8Oid = Just $ Pg.array_float8Oid+ | elemOid == Pg.polygonOid = Just $ Pg.array_polygonOid+ | elemOid == Pg.oidOid = Just $ Pg.array_oidOid+ | elemOid == Pg.macaddrOid = Just $ Pg.array_macaddrOid+ | elemOid == Pg.inetOid = Just $ Pg.array_inetOid+ | elemOid == Pg.timestampOid = Just $ Pg.array_timestampOid+ | elemOid == Pg.dateOid = Just $ Pg.array_dateOid+ | elemOid == Pg.timeOid = Just $ Pg.array_timeOid+ | elemOid == Pg.timestamptzOid = Just $ Pg.array_timestamptzOid+ | elemOid == Pg.intervalOid = Just $ Pg.array_intervalOid+ | elemOid == Pg.numericOid = Just $ Pg.array_numericOid+ | elemOid == Pg.timetzOid = Just $ Pg.array_timetzOid+ | elemOid == Pg.bitOid = Just $ Pg.array_bitOid+ | elemOid == Pg.varbitOid = Just $ Pg.array_varbitOid+ | elemOid == Pg.refcursorOid = Just $ Pg.array_refcursorOid+ | elemOid == Pg.regprocedureOid = Just $ Pg.array_regprocedureOid+ | elemOid == Pg.regoperOid = Just $ Pg.array_regoperOid+ | elemOid == Pg.regoperatorOid = Just $ Pg.array_regoperatorOid+ | elemOid == Pg.regclassOid = Just $ Pg.array_regclassOid+ | elemOid == Pg.regtypeOid = Just $ Pg.array_regtypeOid+ | elemOid == Pg.uuidOid = Just $ Pg.array_uuidOid+ | elemOid == Pg.jsonbOid = Just $ Pg.array_jsonbOid+ | otherwise = Nothing+ pgTsQueryTypeInfo :: Pg.TypeInfo pgTsQueryTypeInfo = Pg.Basic (Pg.Oid 3615) 'U' ',' "tsquery"
beam-postgres.cabal view
@@ -1,5 +1,5 @@ name: beam-postgres-version: 0.5.4.2+version: 0.5.4.3 synopsis: Connection layer between beam and postgres description: Beam driver for <https://www.postgresql.org/ PostgreSQL>, an advanced open-source RDBMS homepage: https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres@@ -32,7 +32,7 @@ Database.Beam.Postgres.PgSpecific Database.Beam.Postgres.Types - build-depends: base >=4.9 && <5.0,+ build-depends: base >=4.11 && <5.0, beam-core >=0.10 && <0.11, beam-migrate >=0.5 && <0.6, @@ -58,14 +58,18 @@ network-uri >=2.6 && <2.7, unordered-containers >= 0.2 && <0.3, tagged >=0.8 && <0.9,- transformers-base >=0.4 && <0.5,+ transformers-base >=0.4 && <0.5 - 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+ -Widentities+ -Wincomplete-uni-patterns+ -Wincomplete-record-updates+ if impl(ghc >= 8.10)+ ghc-options: -Wunused-packages if flag(werror) ghc-options: -Werror
test/Database/Beam/Postgres/Test/Marshal.hs view
@@ -51,6 +51,10 @@ pure (PgBox (PgPoint (min x1 x2) (min y1 y2)) (PgPoint (max x1 x2) (max y1 y2))) +arrayGen :: Hedgehog.Gen a -> Hedgehog.Gen (Vector.Vector a)+arrayGen = fmap Vector.fromList + . Gen.list (Range.linear 0 5) -- small arrays == quick tests+ boxCmp :: PgBox -> PgBox -> Bool boxCmp (PgBox a1 b1) (PgBox a2 b2) = (a1 `ptCmp` a2 && b1 `ptCmp` b2) ||@@ -90,13 +94,27 @@ , marshalTest (Gen.maybe (Gen.integral (Range.constantBounded @Word64))) postgresConn , marshalTest (Gen.maybe textGen) postgresConn , marshalTest (Gen.maybe uuidGen) postgresConn- , marshalTest692 postgresConn , marshalTest' (\a b -> Hedgehog.assert (liftEq ptCmp a b)) (Gen.maybe pointGen) postgresConn , marshalTest' (\a b -> Hedgehog.assert (liftEq boxCmp a b)) (Gen.maybe boxGen) postgresConn --- , marshalTest (Gen.double (Range.exponentialFloat 0 1e40)) postgresConn--- , marshalTest (Gen.integral (Range.constantBounded @Word)) postgresConn+ -- Arrays+ --+ -- Testing lots of element types for arrays is important, because + -- the mapping between array Oid and element Oid is not type + -- safe, and hence error-prone.+ , marshalTest (arrayGen textGen) postgresConn+ , marshalTest (arrayGen (Gen.double (Range.exponentialFloat 0 1e40))) postgresConn+ , marshalTest (arrayGen ((Gen.integral (Range.constantBounded @Int16)))) postgresConn+ , marshalTest (arrayGen ((Gen.integral (Range.constantBounded @Int32)))) postgresConn+ , marshalTest (arrayGen ((Gen.integral (Range.constantBounded @Int64)))) postgresConn+ , marshalTest (Gen.maybe (arrayGen textGen)) postgresConn+ , marshalTest (Gen.maybe (arrayGen (Gen.double (Range.exponentialFloat 0 1e40)))) postgresConn+ , marshalTest (Gen.maybe (arrayGen ((Gen.integral (Range.constantBounded @Int16))))) postgresConn+ , marshalTest (Gen.maybe (arrayGen ((Gen.integral (Range.constantBounded @Int32))))) postgresConn+ , marshalTest (Gen.maybe (arrayGen ((Gen.integral (Range.constantBounded @Int64))))) postgresConn++ , marshalTest (Gen.double (Range.exponentialFloat 0 1e40)) postgresConn -- , marshalTest (Gen.integral (Range.constantBounded @Int)) postgresConn -- , marshalTest @Int8 postgresConn@@ -164,70 +182,3 @@ v' `cmp` a assertBool "Hedgehog test failed" passes----- Ensure that both `Vector Text` and `Maybe (Vector Text)` can be --- marshalled correctly (see issue 692).------ At this time, the postgres migration backend can't create columns of arrays,--- and hence this test does not use `marshalTest`.-marshalTest692 :: IO ByteString -> TestTree-marshalTest692 postgresConn = - testCase "Can marshal Vector Text and Maybe (Vector Text) (#692)" $ - withTestPostgres ("db_marshal_maybe_vector_text_issue_692") postgresConn $ \conn -> do- liftIO $ execute_ conn $ "CREATE TABLE mytable (\nmyid SERIAL PRIMARY KEY, mycolumn text[], mynullablecolumn text[]\n);"-- passes <- Hedgehog.check . Hedgehog.property $ do- nullable <- Hedgehog.forAll (Gen.maybe (Vector.fromList <$> (Gen.list (Range.linear 0 10) textGen)))- nonnull <- Hedgehog.forAll (Vector.fromList <$> (Gen.list (Range.linear 0 10) textGen))-- [MkTbl692 rowId v vnull] <-- liftIO . runBeamPostgres conn - $ runInsertReturningList - $ insert (_myTable myDB) - $ insertExpressions [ MkTbl692 default_ (val_ nonnull) (val_ nullable) ]-- v === nonnull- vnull === nullable-- Just (MkTbl692 _ v' vnull') <-- liftIO . runBeamPostgres conn - $ runSelectReturningOne (lookup_ (_myTable myDB) (Tbl692Key rowId))- v' === nonnull- vnull' === nullable-- assertBool "Hedgehog test failed" passes- where- myDB :: DatabaseSettings Postgres MyDB692- myDB = defaultDbSettings `withDbModification`- MkMyDB692 {- _myTable =- setEntityName "mytable" <>- modifyTableFields- tableModification {- myid = fieldNamed "myid",- mycolumn = fieldNamed "mycolumn",- mynullablecolumn = fieldNamed "mynullablecolumn"- }- }--data Tbl692 f- = MkTbl692 - { myid :: C f (SqlSerial Int32)- , mycolumn :: C f (Vector.Vector T.Text)- , mynullablecolumn :: C f (Maybe (Vector.Vector T.Text)) - }- deriving (Generic, Beamable)--deriving instance Show (Tbl692 Identity)-deriving instance Eq (Tbl692 Identity)--instance Table Tbl692 where- data PrimaryKey Tbl692 f = Tbl692Key (C f (SqlSerial Int32))- deriving (Generic, Beamable)- primaryKey = Tbl692Key <$> myid-data MyDB692 entity- = MkMyDB692- { _myTable :: entity (TableEntity Tbl692)- } deriving (Generic)-instance Database Postgres MyDB692