|
5 | 5 | -- | Defines common 'DatabasePredicate's that are shared among backends
|
6 | 6 | module Database.Beam.Migrate.Checks where
|
7 | 7 |
|
| 8 | +import Control.Monad (guard) |
| 9 | + |
8 | 10 | import Database.Beam.Migrate.Serialization
|
9 | 11 | import Database.Beam.Migrate.Types.Predicates
|
10 | 12 | import Database.Beam.Migrate.SQL.SQL92
|
11 | 13 | import Database.Beam.Schema.Indices
|
12 | 14 | import Database.Beam.Schema.Tables
|
13 | 15 |
|
| 16 | +import Data.Proxy (Proxy (..)) |
14 | 17 | import Data.Aeson ((.:), (.=), withObject, object)
|
15 | 18 | import Data.Aeson.Types (Parser, Value)
|
16 | 19 | import Data.Hashable (Hashable(..))
|
17 | 20 | import Data.Text (Text)
|
18 |
| -import Data.Typeable (Typeable, cast) |
| 21 | +import Data.Typeable (typeOf, splitTyConApp, typeRep, Typeable, cast) |
19 | 22 | #if !MIN_VERSION_base(4, 11, 0)
|
20 | 23 | import Data.Semigroup
|
21 | 24 | #endif
|
22 | 25 |
|
23 | 26 | import GHC.Generics (Generic)
|
24 | 27 | import GHC.Exts (fromList, toList)
|
25 | 28 |
|
| 29 | +import Unsafe.Coerce (unsafeCoerce) |
26 | 30 |
|
27 | 31 | -- * Table checks
|
28 | 32 |
|
@@ -152,12 +156,24 @@ instance DatabasePredicate TableHasIndex where
|
152 | 156 | | Just (TableExistsPredicate tblNm') <- cast p' = tblNm' == tblNm
|
153 | 157 | | otherwise = False
|
154 | 158 |
|
155 |
| - -- TODO: how to say that we cannot delete a column while an index on it exists? |
156 |
| - -- The following does not work since 'TableHasColumn' is polymorphic other used syntax, and |
157 |
| - -- we don't know which index to get here |
158 |
| - -- |
159 |
| - -- predicateRestrictDropOf (TableHasIndex tblNm _) p' |
160 |
| - -- | Just (TableHasColumn tblNm' _ _) <- cast p' = tblNm' == tblNm |
| 159 | + predicateRestrictsDropOf (TableHasIndex tblNm colNms _) p' |
| 160 | + | Just (tblNm', colNm') <- |
| 161 | + withTyCon (\(TableHasColumn tblNm' colNm' _) -> (tblNm', colNm')) p' = |
| 162 | + tblNm == tblNm' && (colNm' `elem` colNms) |
| 163 | + | otherwise = False |
| 164 | + |
| 165 | +-- | Match a given item's type against a type-level application with the given |
| 166 | +-- type constructor. Applies the given function and returns 'Just' its result on match, |
| 167 | +-- 'Nothing' otherwise. |
| 168 | +withTyCon |
| 169 | + :: forall (con :: * -> *) (item :: *) r. |
| 170 | + (Typeable con, Typeable item) |
| 171 | + => (forall c. con c -> r) -> item -> Maybe r |
| 172 | +withTyCon f x = do |
| 173 | + let (tyItemCon, _) = splitTyConApp $ typeRep (Proxy @item) |
| 174 | + (tyCon, _) = splitTyConApp (typeOf x) |
| 175 | + guard (tyItemCon == tyCon) |
| 176 | + return (f $ unsafeCoerce x) |
161 | 177 |
|
162 | 178 | -- | Convert gathered indices into checks.
|
163 | 179 | entityIndicesToChecks
|
|
0 commit comments