Skip to content

Commit f861d40

Browse files
committed
Implement predicateRestrictsDropOf
1 parent 0ac91ca commit f861d40

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

Diff for: beam-migrate/Database/Beam/Migrate/Actions.hs

+3
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@ dropColumnProvider = ActionProvider provider
418418
-- TableHasColumn tblNm' colNm' colType' :: TableHasColumn (Sql92DdlCommandColumnSchemaSyntax cmd) <-
419419
-- findPostConditions
420420
-- guard (tblNm' == tblNm && colNm == colNm' && colType == colType') -- This column exists as a different type
421+
ensuringNot_ $ do
422+
SomeDatabasePredicate pred' <- findPreConditions
423+
guard (pred' `predicateRestrictsDropOf` colP)
421424

422425
relatedPreds <- --pure []
423426
pure $ do p'@(SomeDatabasePredicate pred') <- findPreConditions

Diff for: beam-migrate/Database/Beam/Migrate/Checks.hs

+25-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
-- | Defines common 'DatabasePredicate's that are shared among backends
66
module Database.Beam.Migrate.Checks where
77

8+
import Control.Monad (guard)
89
import Database.Beam.Backend.SQL.SQL92
10+
911
import Database.Beam.Migrate.Serialization
1012
import Database.Beam.Migrate.SQL.SQL92
1113
import Database.Beam.Migrate.SQL.Types
@@ -16,15 +18,18 @@ import Database.Beam.Schema.Tables
1618
import Data.Aeson (object, withObject, (.:), (.=))
1719
import Data.Aeson.Types (Parser, Value)
1820
import Data.Hashable (Hashable (..))
21+
import Data.Proxy (Proxy (..))
1922
import Data.Text (Text)
20-
import Data.Typeable (Typeable, cast)
23+
import Data.Typeable (Typeable, cast, splitTyConApp, typeOf, typeRep)
2124
#if !MIN_VERSION_base(4, 11, 0)
2225
import Data.Semigroup
2326
#endif
2427

2528
import GHC.Exts (fromList, toList)
2629
import GHC.Generics (Generic)
2730

31+
import Unsafe.Coerce (unsafeCoerce)
32+
2833
-- * Table checks
2934

3035
-- | Asserts that a table with the given name exists in a database
@@ -153,12 +158,25 @@ instance DatabasePredicate TableHasIndex where
153158
| Just (TableExistsPredicate tblNm') <- cast p' = tblNm' == tblNm
154159
| otherwise = False
155160

156-
-- TODO: how to say that we cannot delete a column while an index on it exists?
157-
-- The following does not work since 'TableHasColumn' is polymorphic other used syntax, and
158-
-- we don't know which index to get here
159-
--
160-
-- predicateRestrictDropOf (TableHasIndex tblNm _) p'
161-
-- | Just (TableHasColumn tblNm' _ _) <- cast p' = tblNm' == tblNm
161+
predicateRestrictsDropOf (TableHasIndex tblNm colNms _) p'
162+
| Just (tblNm', colNm') <-
163+
withTyCon (\(TableHasColumn tblNm' colNm' _) -> (tblNm', colNm')) p' =
164+
tblNm == tblNm' && (colNm' `elem` colNms)
165+
| otherwise = False
166+
167+
-- | Match a given item's type against a type-level application with the given
168+
-- type constructor. Applies the given function and returns 'Just' its result on match,
169+
-- 'Nothing' otherwise.
170+
-- Unlike 'cast', this function does not require @a@ type to be instance of 'Typeable'.
171+
withTyCon
172+
:: forall (con :: * -> *) (item :: *) r.
173+
(Typeable con, Typeable item)
174+
=> (forall a. con a -> r) -> item -> Maybe r
175+
withTyCon f x = do
176+
(itemTyCon, itemTyArgs@(_ : _)) <- pure $ splitTyConApp (typeOf x)
177+
(conTyCon, conTyArgs) <- pure $ splitTyConApp (typeRep (Proxy @con))
178+
guard (itemTyCon == conTyCon && init itemTyArgs == conTyArgs)
179+
return (f $ unsafeCoerce x)
162180

163181
-- | Convert gathered indices into checks.
164182
entityIndicesToChecks

Diff for: beam-migrate/Database/Beam/Migrate/Types/Predicates.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ class (Typeable p, Hashable p, Eq p) => DatabasePredicate p where
5757
-- needs another one to be true in order to exist. The difference is, the other
5858
-- predicate cannot be removed until this one exists, this predicate has to be
5959
-- explicitely removed with a corresponding action first.
60-
predicateRestrictDropOf :: DatabasePredicate p' => p -> p' -> Bool
61-
predicateRestrictDropOf _ _ = False
60+
predicateRestrictsDropOf :: DatabasePredicate p' => p -> p' -> Bool
61+
predicateRestrictsDropOf _ _ = False
6262

6363
-- | A Database predicate is a value of any type which satisfies
6464
-- 'DatabasePredicate'. We often want to store these in lists and sets, so we

0 commit comments

Comments
 (0)