packages feed

beam-migrate 0.5.3.2 → 0.5.4.0

raw patch · 10 files changed

+282/−17 lines, 10 filesdep ~pqueuePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: pqueue

API changes (from Hackage documentation)

+ Database.Beam.Migrate.Actions: createIndexActionProvider :: (BeamMigrateOnlySqlBackend be, IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be)) => ActionProvider be
+ Database.Beam.Migrate.Actions: dropIndexActionProvider :: (BeamMigrateOnlySqlBackend be, IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be)) => ActionProvider be
+ Database.Beam.Migrate.Checks: TableHasIndex :: QualifiedName -> Text -> NonEmpty Text -> BeamSqlBackendIndexSyntax be -> TableHasIndex be
+ Database.Beam.Migrate.Checks: [hasIndex_columns] :: TableHasIndex be -> NonEmpty Text
+ Database.Beam.Migrate.Checks: [hasIndex_name] :: TableHasIndex be -> Text
+ Database.Beam.Migrate.Checks: [hasIndex_opts] :: TableHasIndex be -> BeamSqlBackendIndexSyntax be
+ Database.Beam.Migrate.Checks: [hasIndex_table] :: TableHasIndex be -> QualifiedName
+ Database.Beam.Migrate.Checks: data TableHasIndex be
+ Database.Beam.Migrate.Checks: instance (Data.Typeable.Internal.Typeable be, Database.Beam.Migrate.SQL.SQL92.IsSql92UniqueIndexSyntax (Database.Beam.Backend.SQL.BeamSqlBackendSyntax be)) => Database.Beam.Migrate.Types.Predicates.DatabasePredicate (Database.Beam.Migrate.Checks.TableHasIndex be)
+ Database.Beam.Migrate.Checks: instance Data.Hashable.Class.Hashable (Database.Beam.Migrate.SQL.Types.BeamSqlBackendIndexSyntax be) => Data.Hashable.Class.Hashable (Database.Beam.Migrate.Checks.TableHasIndex be)
+ Database.Beam.Migrate.Checks: instance GHC.Classes.Eq (Database.Beam.Migrate.SQL.Types.BeamSqlBackendIndexSyntax be) => GHC.Classes.Eq (Database.Beam.Migrate.Checks.TableHasIndex be)
+ Database.Beam.Migrate.Checks: instance GHC.Generics.Generic (Database.Beam.Migrate.Checks.TableHasIndex be)
+ Database.Beam.Migrate.Checks: instance GHC.Show.Show (Database.Beam.Migrate.SQL.Types.BeamSqlBackendIndexSyntax be) => GHC.Show.Show (Database.Beam.Migrate.Checks.TableHasIndex be)
+ Database.Beam.Migrate.SQL: type BeamSqlBackendIndexSyntax be = Sql92CreateIndexOptionsSyntax BeamSqlBackendSyntax be
+ Database.Beam.Migrate.SQL.SQL92: class (IsSql92DdlCommandSyntax syntax, Show Sql92CreateIndexOptionsSyntax syntax, Eq Sql92CreateIndexOptionsSyntax syntax, Hashable Sql92CreateIndexOptionsSyntax syntax) => IsSql92CreateDropIndexSyntax syntax where {
+ Database.Beam.Migrate.SQL.SQL92: class IsSql92CreateDropIndexSyntax syntax => IsSql92UniqueIndexSyntax syntax
+ Database.Beam.Migrate.SQL.SQL92: createIndexCmd :: IsSql92CreateDropIndexSyntax syntax => Text -> Sql92CreateTableTableNameSyntax (Sql92DdlCommandCreateTableSyntax syntax) -> NonEmpty Text -> Sql92CreateIndexOptionsSyntax syntax -> syntax
+ Database.Beam.Migrate.SQL.SQL92: defaultIndexOptions :: IsSql92CreateDropIndexSyntax syntax => Sql92CreateIndexOptionsSyntax syntax
+ Database.Beam.Migrate.SQL.SQL92: deserializeIndexOptions :: IsSql92CreateDropIndexSyntax syntax => Value -> Parser (Sql92CreateIndexOptionsSyntax syntax)
+ Database.Beam.Migrate.SQL.SQL92: dropIndexCmd :: IsSql92CreateDropIndexSyntax syntax => Text -> syntax
+ Database.Beam.Migrate.SQL.SQL92: indexIsUnique :: IsSql92UniqueIndexSyntax syntax => Sql92CreateIndexOptionsSyntax syntax -> Bool
+ Database.Beam.Migrate.SQL.SQL92: serializeIndexOptions :: IsSql92CreateDropIndexSyntax syntax => Sql92CreateIndexOptionsSyntax syntax -> Value
+ Database.Beam.Migrate.SQL.SQL92: setUniqueIndexOptions :: IsSql92UniqueIndexSyntax syntax => Bool -> Sql92CreateIndexOptionsSyntax syntax -> Sql92CreateIndexOptionsSyntax syntax
+ Database.Beam.Migrate.SQL.SQL92: type Sql92CreateIndexOptionsSyntax syntax;
+ Database.Beam.Migrate.Types: addTableIndex :: forall be tbl (db :: (Type -> Type) -> Type). (Typeable be, IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be)) => Text -> BeamSqlBackendIndexSyntax be -> (tbl (TableField tbl) -> NonEmpty Text) -> EntityModification (CheckedDatabaseEntity be db) be (TableEntity tbl)
+ Database.Beam.Migrate.Types: class (IsSql92DdlCommandSyntax syntax, Show Sql92CreateIndexOptionsSyntax syntax, Eq Sql92CreateIndexOptionsSyntax syntax, Hashable Sql92CreateIndexOptionsSyntax syntax) => IsSql92CreateDropIndexSyntax syntax where {
+ Database.Beam.Migrate.Types: createIndexCmd :: IsSql92CreateDropIndexSyntax syntax => Text -> Sql92CreateTableTableNameSyntax (Sql92DdlCommandCreateTableSyntax syntax) -> NonEmpty Text -> Sql92CreateIndexOptionsSyntax syntax -> syntax
+ Database.Beam.Migrate.Types: defaultIndexOptions :: IsSql92CreateDropIndexSyntax syntax => Sql92CreateIndexOptionsSyntax syntax
+ Database.Beam.Migrate.Types: deserializeIndexOptions :: IsSql92CreateDropIndexSyntax syntax => Value -> Parser (Sql92CreateIndexOptionsSyntax syntax)
+ Database.Beam.Migrate.Types: dropIndexCmd :: IsSql92CreateDropIndexSyntax syntax => Text -> syntax
+ Database.Beam.Migrate.Types: foreignKeyColumns :: forall (ref :: (Type -> Type) -> Type) tbl. Beamable (PrimaryKey ref) => (tbl (TableField tbl) -> PrimaryKey ref (TableField tbl)) -> tbl (TableField tbl) -> NonEmpty Text
+ Database.Beam.Migrate.Types: selectorColumnName :: (tbl (TableField tbl) -> TableField tbl a) -> tbl (TableField tbl) -> Text
+ Database.Beam.Migrate.Types: serializeIndexOptions :: IsSql92CreateDropIndexSyntax syntax => Sql92CreateIndexOptionsSyntax syntax -> Value
+ Database.Beam.Migrate.Types: type Sql92CreateIndexOptionsSyntax syntax;
- Database.Beam.Migrate.Checks: beamCheckDeserializers :: (Typeable be, BeamMigrateOnlySqlBackend be, HasDataTypeCreatedCheck (BeamMigrateSqlBackendDataTypeSyntax be)) => BeamDeserializers be
+ Database.Beam.Migrate.Checks: beamCheckDeserializers :: (Typeable be, BeamMigrateOnlySqlBackend be, HasDataTypeCreatedCheck (BeamMigrateSqlBackendDataTypeSyntax be), IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be)) => BeamDeserializers be

Files

ChangeLog.md view
@@ -1,3 +1,18 @@+# 0.5.4.0++## Added features++* Added support for declaring secondary indices on tables. User API is the+  `addTableIndex` function, `selectorColumnName` and `foreignKeyColumns` helpers.+  Backend support goes through new `IsSql92CreateDropIndexSyntax` (which carries+  a per-backend `Sql92CreateIndexOptionsSyntax` type family) and+  `IsSql92UniqueIndexSyntax` (for index uniqueness constraints).++## Updated dependencies++* Updated the upper bound on `parallel` to include `parallel-3.3.0.0`+* Updated the upper bound on `time` to include `time-1.14`+ # 0.5.3.2  ## Dependencies
Database/Beam/Migrate/Actions.hs view
@@ -1,6 +1,7 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE RecordWildCards #-}@@ -83,6 +84,8 @@   , addColumnProvider   , addColumnNullProvider   , dropColumnNullProvider+  , createIndexActionProvider+  , dropIndexActionProvider   , defaultActionProvider   , defaultSchemaActionProvider @@ -112,7 +115,6 @@ import           Data.Text (Text) import qualified Data.Text as T import           Data.Typeable-import           Data.Semigroup  import           GHC.Generics @@ -273,6 +275,10 @@ addColumnWeight = 1 dropColumnWeight = 1 +createIndexWeight, dropIndexWeight :: Int+createIndexWeight = 200+dropIndexWeight = 50+ -- | Proceeds only if no predicate matches the given pattern. See the -- implementation of 'dropTableActionProvider' for an example of usage. ensuringNot_ :: Alternative m => [ a ] -> m ()@@ -516,6 +522,60 @@          pure (PotentialAction (HS.fromList [SomeDatabasePredicate colP]) mempty                                (Seq.singleton (MigrationCommand cmd MigrationKeepsData))                                ("Drop not null constraint for " <> colNm <> " on " <> qnameAsText tblNm) 100)++-- | Action provider for @CREATE INDEX@ actions.+--+-- Generates a @CREATE INDEX@ command whenever the destination schema contains+-- a 'TableHasIndex' predicate that is not satisfied in the current state.+createIndexActionProvider :: forall be+                           . ( BeamMigrateOnlySqlBackend be+                             , IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be) )+                          => ActionProvider be+createIndexActionProvider = ActionProvider provider+  where+    provider :: ActionProviderFn be+    provider findPreConditions findPostConditions =+      do (idxP@(TableHasIndex { hasIndex_table = postTblNm, hasIndex_name = idxNm+                              , hasIndex_columns = idxCols, hasIndex_opts = idxOpts })+            :: TableHasIndex be) <- findPostConditions+         -- Ensure this index doesn't already exist+         ensuringNot_ $+           do (TableHasIndex { hasIndex_table = preTblNm, hasIndex_name = idxNm' }+                :: TableHasIndex be) <- findPreConditions+              guard (preTblNm == postTblNm && idxNm' == idxNm)+         -- Ensure the target table already exists+         TableExistsPredicate tblNm' <- findPreConditions+         guard (tblNm' == postTblNm)++         let cmd = createIndexCmd idxNm (qnameAsTableName postTblNm) idxCols idxOpts+         pure (PotentialAction mempty (HS.singleton (p idxP))+                               (Seq.singleton (MigrationCommand cmd MigrationKeepsData))+                               ("Create index " <> idxNm <> " on " <> qnameAsText postTblNm)+                               createIndexWeight)++-- | Action provider for @DROP INDEX@ actions.+dropIndexActionProvider :: forall be+                         . ( BeamMigrateOnlySqlBackend be+                           , IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be) )+                        => ActionProvider be+dropIndexActionProvider = ActionProvider provider+  where+    provider :: ActionProviderFn be+    provider findPreConditions findPostConditions =+      do (idxP@(TableHasIndex { hasIndex_table = preTblNm, hasIndex_name = idxNm })+            :: TableHasIndex be) <- findPreConditions+         ensuringNot_ $+           do (TableHasIndex { hasIndex_table = postTblNm, hasIndex_name = idxNm' }+                :: TableHasIndex be) <- findPostConditions+              guard (preTblNm == postTblNm && idxNm' == idxNm)++         let cmd = dropIndexCmd idxNm+         pure (PotentialAction (HS.singleton (p idxP)) mempty+           -- Dropping a secondary index doesn't lose data, as the index+           -- can be recalculated.+                               (Seq.singleton (MigrationCommand cmd MigrationKeepsData))+                               ("Drop index " <> idxNm <> " on " <> qnameAsText preTblNm)+                               dropIndexWeight)  -- | Default action providers for any SQL92 compliant syntax. --
Database/Beam/Migrate/Backend.hs view
@@ -54,9 +54,6 @@ import           Control.Applicative import qualified Control.Monad.Fail as Fail -#if ! MIN_VERSION_base(4,11,0)-import           Data.Semigroup-#endif import           Data.Text (Text) import           Data.Time 
Database/Beam/Migrate/Checks.hs view
@@ -4,6 +4,7 @@ -- | Defines common 'DatabasePredicate's that are shared among backends module Database.Beam.Migrate.Checks where +import Database.Beam.Backend.SQL (BeamSqlBackendSyntax) import Database.Beam.Backend.SQL.SQL92 import Database.Beam.Migrate.SQL.SQL92 import Database.Beam.Migrate.SQL.Types@@ -13,6 +14,7 @@ import Data.Aeson ((.:), (.=), withObject, object) import Data.Aeson.Types (Parser, Value) import Data.Hashable (Hashable(..))+import qualified Data.List.NonEmpty as NE (NonEmpty) import Data.Text (Text) import Data.Typeable (Typeable, cast) @@ -111,6 +113,39 @@     | Just (TableHasColumn tblNm' colNm' _ :: TableHasColumn be) <- cast p' = tblNm' == tblNm && colNm' == colNm     | otherwise = False +-- | Asserts that the given table has a secondary index with the given name+-- covering the given columns (in order). Create these predicates with+-- 'Database.Beam.Migrate.Types.CheckedEntities.addTableIndex'.+data TableHasIndex be+  = TableHasIndex+  { hasIndex_table   :: QualifiedName                -- ^ table name+  , hasIndex_name    :: Text                         -- ^ index name+  , hasIndex_columns :: NE.NonEmpty Text             -- ^ ordered column names+  , hasIndex_opts    :: BeamSqlBackendIndexSyntax be -- ^ index options (e.g. uniqueness)+  } deriving Generic+deriving instance Show (BeamSqlBackendIndexSyntax be) => Show (TableHasIndex be)+deriving instance Eq (BeamSqlBackendIndexSyntax be) => Eq (TableHasIndex be)+instance Hashable (BeamSqlBackendIndexSyntax be) => Hashable (TableHasIndex be)+instance ( Typeable be+         , IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be) ) =>+         DatabasePredicate (TableHasIndex be) where+  englishDescription (TableHasIndex { hasIndex_table = tbl, hasIndex_name = nm+                                    , hasIndex_columns = cols, hasIndex_opts = opts }) =+    (if indexIsUnique @(BeamSqlBackendSyntax be) opts then "Unique index " else "Index ") <>+    show nm <> " on table " <> show tbl <> " covering columns " <> show cols++  predicateSpecificity _ = PredicateSpecificityAllBackends++  serializePredicate (TableHasIndex { hasIndex_table = tbl, hasIndex_name = nm+                                    , hasIndex_columns = cols, hasIndex_opts = opts }) =+    object [ "has-index" .= object [ "table" .= tbl, "name" .= nm+                                   , "columns" .= cols+                                   , "options" .= serializeIndexOptions @(BeamSqlBackendSyntax be) opts ] ]++  predicateCascadesDropOn (TableHasIndex { hasIndex_table = tblNm }) p'+    | Just (TableExistsPredicate tblNm') <- cast p' = tblNm' == tblNm+    | otherwise = False+ -- | Asserts that the given table has a primary key made of the given columns. -- The order of the columns is significant. data TableHasPrimaryKey@@ -139,12 +174,14 @@ beamCheckDeserializers   :: forall be    . ( Typeable be, BeamMigrateOnlySqlBackend be-     , HasDataTypeCreatedCheck (BeamMigrateSqlBackendDataTypeSyntax be) )+     , HasDataTypeCreatedCheck (BeamMigrateSqlBackendDataTypeSyntax be)+     , IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be) )   => BeamDeserializers be beamCheckDeserializers = mconcat   [ beamDeserializer (const deserializeSchemaExistsPredicate)   , beamDeserializer (const deserializeTableExistsPredicate)   , beamDeserializer (const deserializeTableHasPrimaryKeyPredicate)+  , beamDeserializer (const deserializeTableHasIndexPredicate)   , beamDeserializer deserializeTableHasColumnPredicate   , beamDeserializer deserializeTableColumnHasConstraintPredicate   ]@@ -165,6 +202,17 @@       v .: "has-primary-key" >>=       (withObject "TableHasPrimaryKey" $ \v' ->        SomeDatabasePredicate <$> (TableHasPrimaryKey <$> v' .: "table" <*> v' .: "columns"))++    deserializeTableHasIndexPredicate :: Value -> Parser SomeDatabasePredicate+    deserializeTableHasIndexPredicate =+      withObject "TableHasIndex" $ \v ->+      v .: "has-index" >>=+      (withObject "TableHasIndex" $ \v' ->+       SomeDatabasePredicate <$>+       fmap (id @(TableHasIndex be))+         (TableHasIndex <$> v' .: "table" <*> v' .: "name"+                        <*> v' .: "columns"+                        <*> (deserializeIndexOptions @(BeamSqlBackendSyntax be) =<< v' .: "options")))      deserializeTableHasColumnPredicate :: BeamDeserializers be'                                        -> Value -> Parser SomeDatabasePredicate
Database/Beam/Migrate/SQL/SQL92.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE CPP #-} @@ -11,13 +12,12 @@ import Database.Beam.Backend.SQL.SQL92  import Data.Aeson (Value)+import Data.Aeson.Types (Parser) import Data.Hashable import Data.Kind (Type)+import qualified Data.List.NonEmpty as NE (NonEmpty) import Data.Text (Text) import Data.Typeable-#if ! MIN_VERSION_base(4,11,0)-import Data.Semigroup-#endif  -- * Convenience type synonyms @@ -99,17 +99,17 @@   dropTableCmd    :: Sql92DdlCommandDropTableSyntax syntax -> syntax   alterTableCmd   :: Sql92DdlCommandAlterTableSyntax syntax -> syntax -class IsSql92SchemaNameSyntax (Sql92CreateSchemaSchemaNameSyntax syntax) => +class IsSql92SchemaNameSyntax (Sql92CreateSchemaSchemaNameSyntax syntax) =>     IsSql92CreateSchemaSyntax syntax where-  +   type Sql92CreateSchemaSchemaNameSyntax syntax :: Type    createSchemaSyntax :: Sql92CreateSchemaSchemaNameSyntax syntax                      -> syntax -class IsSql92SchemaNameSyntax (Sql92DropSchemaSchemaNameSyntax syntax) => +class IsSql92SchemaNameSyntax (Sql92DropSchemaSchemaNameSyntax syntax) =>     IsSql92DropSchemaSyntax syntax where-  +   type Sql92DropSchemaSchemaNameSyntax syntax :: Type    dropSchemaSyntax :: Sql92DropSchemaSchemaNameSyntax syntax@@ -240,3 +240,58 @@ -- | 'IsSql92ColumnConstraintDefinitionSyntax'es that can be serialized to JSON class Sql92SerializableConstraintDefinitionSyntax constraint where   serializeConstraint :: constraint -> Value++-- | Syntax extension for @CREATE INDEX@ and @DROP INDEX@ DDL commands.+--+-- @CREATE INDEX@ is not part of SQL92 proper, but is a widely supported+-- extension.+--+-- @since 0.5.4.0+class ( IsSql92DdlCommandSyntax syntax+      , Show     (Sql92CreateIndexOptionsSyntax syntax)+      , Eq       (Sql92CreateIndexOptionsSyntax syntax)+      , Hashable (Sql92CreateIndexOptionsSyntax syntax)+      ) => IsSql92CreateDropIndexSyntax syntax where+  type family Sql92CreateIndexOptionsSyntax syntax++  -- | Render a @CREATE INDEX@ command.+  createIndexCmd+    :: Text  -- ^ index name+    -> Sql92CreateTableTableNameSyntax (Sql92DdlCommandCreateTableSyntax syntax)+       -- ^ table name+    -> NE.NonEmpty Text -- ^ ordered column names+    -> Sql92CreateIndexOptionsSyntax syntax -- ^ index options+    -> syntax++  -- | Render a @DROP INDEX@ command.+  dropIndexCmd+    :: Text  -- ^ index name+    -> syntax++  -- | Default options for @CREATE INDEX@+  defaultIndexOptions+    :: Sql92CreateIndexOptionsSyntax syntax++  -- | Serialize index options to a JSON 'Value', for predicate storage.+  serializeIndexOptions :: Sql92CreateIndexOptionsSyntax syntax -> Value+  -- | Deserialize index options from the JSON 'Value' produced by+  -- 'serializeIndexOptions'.+  deserializeIndexOptions :: Value -> Parser (Sql92CreateIndexOptionsSyntax syntax)++-- | Class for index syntaxes that support the SQL @UNIQUE@ modifier.+--+-- Backends implementing 'IsSql92CreateDropIndexSyntax' should also implement+-- this class to expose uniqueness as a portable concept, while still allowing+-- their 'Sql92CreateIndexOptionsSyntax' to carry additional backend-specific+-- options (e.g. index type, partial-index predicates).+--+-- @since 0.5.4.0+class IsSql92CreateDropIndexSyntax syntax => IsSql92UniqueIndexSyntax syntax where++  -- | Update index options by setting the uniqueness+  setUniqueIndexOptions :: Bool -- ^ unique?+                        -> Sql92CreateIndexOptionsSyntax syntax+                        -> Sql92CreateIndexOptionsSyntax syntax++  -- | Query whether an index is unique, as specified in the index options.+  indexIsUnique :: Sql92CreateIndexOptionsSyntax syntax -> Bool
Database/Beam/Migrate/SQL/Types.hs view
@@ -18,6 +18,7 @@   , BeamSqlBackendMatchTypeSyntax   , BeamSqlBackendReferentialActionSyntax   , BeamSqlBackendConstraintAttributesSyntax+  , BeamSqlBackendIndexSyntax   ) where  import Database.Beam.Migrate.Types.Predicates@@ -91,3 +92,5 @@   = Sql92DdlCommandReferentialActionSyntax (BeamSqlBackendSyntax be) type BeamSqlBackendConstraintAttributesSyntax be   = Sql92DdlCommandConstraintAttributesSyntax (BeamSqlBackendSyntax be)+type BeamSqlBackendIndexSyntax be+  = Sql92CreateIndexOptionsSyntax (BeamSqlBackendSyntax be)
Database/Beam/Migrate/Serialization.hs view
@@ -218,6 +218,8 @@          , "be-data" .= v ]  -- | Corresponding deserializer for 'beamSerializeJSON'+--+-- @since 0.5.3.2 beamDeserializeJSON :: Text -> (Value -> Parser a) -> Value -> Parser a beamDeserializeJSON backend go =   withObject "backend-specific item" $ \v -> do
Database/Beam/Migrate/Types.hs view
@@ -24,7 +24,12 @@    , modifyCheckedTable   , checkedTableModification+  , addTableIndex+  , selectorColumnName+  , foreignKeyColumns +  , IsSql92CreateDropIndexSyntax(..)+     -- * Predicates   , DatabasePredicate(..)   , SomeDatabasePredicate(..)@@ -50,6 +55,7 @@   , migrateScript, evaluateDatabase, stepNames ) where  import Database.Beam.Backend.SQL+import Database.Beam.Migrate.SQL.SQL92 import Database.Beam.Migrate.Types.CheckedEntities import Database.Beam.Migrate.Types.Predicates import Control.Monad.Free.Church
Database/Beam/Migrate/Types/CheckedEntities.hs view
@@ -8,6 +8,8 @@ import Database.Beam.Schema.Tables  import Database.Beam.Migrate.Checks+import Database.Beam.Migrate.SQL.SQL92+import Database.Beam.Migrate.SQL.Types (BeamSqlBackendIndexSyntax) import Database.Beam.Migrate.Generics.Tables import Database.Beam.Migrate.Types.Predicates @@ -16,6 +18,7 @@ import Control.Monad.Identity  import Data.Kind (Constraint, Type)+import qualified Data.List.NonEmpty as NE (NonEmpty, nonEmpty) import Data.Maybe import Data.Monoid import Data.Proxy@@ -218,6 +221,82 @@                                 (dt { dbTableCurrentName = renamer (dbTableCurrentName dt)                                     , dbTableSettings = fields'})                                 tblChecks fieldChecks') extraChecks++-- | Lift a field accessor into a column-name reference, for use with+-- 'addTableIndex'.+--+-- See also 'foreignKeyColumns'.+selectorColumnName :: (tbl (TableField tbl) -> TableField tbl a)+         -> tbl (TableField tbl)+         -> Text+selectorColumnName f = (^. fieldName) . f++-- | Expand a foreign-key accessor into its constituent column-name references,+-- for use with 'addTableIndex'.+--+-- Example:+--+-- @+-- data UserT f = User+--   { userId   :: C f Int32+--   , userName :: C f Text+--   }+-- instance Table UserT where+--   newtype PrimaryKey UserT f = UserId (C f Int32)+--   primaryKey (User {userId = i}) = UserId i+-- data OrderT f = Order+--   { orderUser :: PrimaryKey UserT f+--   , orderDate :: C f Day+--   }+-- @+--+-- @+-- addTableIndex "idx_orders_user" indexOptions+--   (\\t -> foreignKeyColumns orderUser t)+-- @+--+-- Can be combined with 'selectorColumnName' for composite indices.+foreignKeyColumns :: Beamable (PrimaryKey ref)+                  => (tbl (TableField tbl) -> PrimaryKey ref (TableField tbl))+                  -> tbl (TableField tbl)+                  -> NE.NonEmpty Text+foreignKeyColumns f t =+  case NE.nonEmpty $ allBeamValues (\(Columnar' field) -> field ^. fieldName) pkey of+    Nothing -> error $ "foreignKeyColumns: foreign key has no fields"+    Just cols -> cols+  where+    pkey = f t++-- | Automatically extracts all column names from a table's primary key+primaryKeyColumns :: Table tbl => tbl (TableField tbl) -> NE.NonEmpty Text+primaryKeyColumns tbl =+  case NE.nonEmpty $ allBeamValues (\(Columnar' field) -> field ^. fieldName) (primaryKey tbl) of+    Nothing -> error "primaryKeyColumns: primary key has no fields"+    Just cols -> cols++-- | Declare a secondary index on a checked table entity.+--+-- Example:+--+-- @+-- addTableIndex "table_index" uniqueIndexOptions+--   (\\t -> selectorColumnName tableField1 t NE.:| [selectorColumnName tableField2 t])+-- @+addTableIndex :: forall be tbl db+              . ( Typeable be+                , IsSql92UniqueIndexSyntax (BeamSqlBackendSyntax be) )+              => Text                             -- ^ SQL index name+              -> BeamSqlBackendIndexSyntax be     -- ^ index options (e.g. 'nonUniqueIndexOptions', 'uniqueIndexOptions')+              -> (tbl (TableField tbl) -> NE.NonEmpty Text) -- ^ column names to index (use 'selectorColumnName')+              -> EntityModification (CheckedDatabaseEntity be db) be (TableEntity tbl)+addTableIndex idxNm opts getCols =+  EntityModification $ Endo $+  \(CheckedDatabaseEntity (CheckedDatabaseTable dt tblChecks fieldChecks) extraChecks) ->+    let cols    = getCols (dbTableSettings dt)+        idxCheck = TableCheck $ \ tblNm _flds ->+          Just (SomeDatabasePredicate (TableHasIndex tblNm idxNm cols opts :: TableHasIndex be))+    in CheckedDatabaseEntity (CheckedDatabaseTable dt (tblChecks ++ [idxCheck]) fieldChecks)+                             extraChecks  -- | Produce a table field modification that does nothing --
beam-migrate.cabal view
@@ -1,5 +1,5 @@ name:                beam-migrate-version:             0.5.3.2+version:             0.5.4.0 synopsis:            SQL DDL support and migrations support library for Beam description:         This package provides type classes to allow backends to implement                      SQL DDL support for beam. This allows you to use beam syntax to@@ -59,21 +59,21 @@                        aeson                >=0.11    && <2.3,                        bytestring           >=0.10    && <0.13,                        free                 >=4.12    && <5.3,-                       time                 >=1.6     && <1.13,+                       time                 >=1.6     && <1.15,                        mtl                  >=2.2     && <2.4,                        scientific           >=0.3     && <0.4,                        vector               >=0.11    && <0.14,                        containers           >=0.5     && <0.9,                        unordered-containers >=0.2     && <0.3,                        hashable             >=1.2     && <1.6,-                       microlens            >=0.4     && <0.5,-                       parallel             >=3.2     && <3.3,+                       microlens            >=0.4     && <0.6,+                       parallel             >=3.2     && <3.4,                        deepseq              >=1.4     && <1.7,                        haskell-src-exts     >=1.18    && <1.24,                        pretty               >=1.1     && <1.2,                        dependent-map        >=0.2     && <0.5,                        dependent-sum        >=0.4     && <0.8,-                       pqueue               >=1.3     && <1.6,+                       pqueue               >=1.3     && <1.7,                        uuid-types           >=1.0     && <1.1   default-language:    Haskell2010   default-extensions:  KindSignatures, OverloadedStrings, TypeFamilies, FlexibleContexts,