|
1 | 1 | {-# LANGUAGE CPP #-} |
| 2 | +{-# language AllowAmbiguousTypes #-} |
2 | 3 | {-# LANGUAGE RoleAnnotations #-} |
3 | 4 | {-# LANGUAGE DeriveFunctor #-} |
4 | 5 | {-# LANGUAGE DataKinds #-} |
|
36 | 37 | -- tracker so we can safely support it. |
37 | 38 | module Database.Esqueleto.Internal.Internal where |
38 | 39 |
|
| 40 | +import Data.Typeable (TypeRep, typeRep) |
| 41 | +import Data.Coerce (Coercible) |
39 | 42 | import Control.Applicative ((<|>)) |
40 | 43 | import Control.Arrow (first, (***)) |
41 | 44 | import Control.Exception (Exception, throw, throwIO) |
@@ -1283,6 +1286,65 @@ case_ = unsafeSqlCase |
1283 | 1286 | toBaseId :: ToBaseId ent => SqlExpr (Value (Key ent)) -> SqlExpr (Value (Key (BaseEnt ent))) |
1284 | 1287 | toBaseId = veryUnsafeCoerceSqlExprValue |
1285 | 1288 |
|
| 1289 | +-- | Like 'toBaseId', but works on 'Maybe' keys. |
| 1290 | +-- |
| 1291 | +-- @since 3.6.0.0 |
| 1292 | +toBaseIdMaybe |
| 1293 | + :: (ToBaseId ent) |
| 1294 | + => SqlExpr (Value (Maybe (Key ent))) |
| 1295 | + -> SqlExpr (Value (Maybe (Key (BaseEnt ent)))) |
| 1296 | +toBaseIdMaybe = veryUnsafeCoerceSqlExprValue |
| 1297 | + |
| 1298 | +-- | The inverse of 'toBaseId'. Note that this is somewhat less "safe" than |
| 1299 | +-- 'toBaseId'. Calling 'toBaseId' will usually mean that a foreign key |
| 1300 | +-- constraint is present that guarantees the presence of the base ID. |
| 1301 | +-- 'fromBaseId' has no such guarantee. Consider the code example given in |
| 1302 | +-- 'toBaseId': |
| 1303 | +-- |
| 1304 | +-- @ |
| 1305 | +-- Bar |
| 1306 | +-- barNum Int |
| 1307 | +-- Foo |
| 1308 | +-- bar BarId |
| 1309 | +-- fooNum Int |
| 1310 | +-- Primary bar |
| 1311 | +-- @ |
| 1312 | +-- |
| 1313 | +-- @ |
| 1314 | +-- instance ToBaseId Foo where |
| 1315 | +-- type BaseEnt Foo = Bar |
| 1316 | +-- toBaseIdWitness barId = FooKey barId |
| 1317 | +-- @ |
| 1318 | +-- |
| 1319 | +-- The type of 'toBaseId' for @Foo@ would be: |
| 1320 | +-- |
| 1321 | +-- @ |
| 1322 | +-- toBaseId :: SqlExpr (Value FooId) -> SqlExpr (Value BarId) |
| 1323 | +-- @ |
| 1324 | +-- |
| 1325 | +-- The foreign key constraint on @Foo@ means that every @FooId@ points to |
| 1326 | +-- a @BarId@ in the database. However, 'fromBaseId' will not have this: |
| 1327 | +-- |
| 1328 | +-- @ |
| 1329 | +-- fromBaseId :: SqlExpr (Value BarId) -> SqlExpr (Value FooId) |
| 1330 | +-- @ |
| 1331 | +-- |
| 1332 | +-- @since 3.6.0.0 |
| 1333 | +fromBaseId |
| 1334 | + :: (ToBaseId ent) |
| 1335 | + => SqlExpr (Value (Key (BaseEnt ent))) |
| 1336 | + -> SqlExpr (Value (Key ent)) |
| 1337 | +fromBaseId = veryUnsafeCoerceSqlExprValue |
| 1338 | + |
| 1339 | +-- | As 'fromBaseId', but works on 'Maybe' keys. |
| 1340 | +-- |
| 1341 | +-- @since 3.6.0.0 |
| 1342 | +fromBaseIdMaybe |
| 1343 | + :: (ToBaseId ent) |
| 1344 | + => SqlExpr (Value (Maybe (Key (BaseEnt ent)))) |
| 1345 | + -> SqlExpr (Value (Maybe (Key ent))) |
| 1346 | +fromBaseIdMaybe = veryUnsafeCoerceSqlExprValue |
| 1347 | + |
1286 | 1348 | -- Fixity declarations |
1287 | 1349 | infixl 9 ^., ?. |
1288 | 1350 | infixl 7 *., /. |
@@ -2451,6 +2513,23 @@ type role SqlExpr nominal |
2451 | 2513 | veryUnsafeCoerceSqlExpr :: SqlExpr a -> SqlExpr b |
2452 | 2514 | veryUnsafeCoerceSqlExpr (ERaw m k) = ERaw m k |
2453 | 2515 |
|
| 2516 | +-- | While 'veryUnsafeCoerceSqlExpr' allows you to coerce anything at all, this |
| 2517 | +-- requires that the two types are 'Coercible' in Haskell. This is not truly |
| 2518 | +-- safe: after all, the point of @newtype@ is to allow you to provide different |
| 2519 | +-- instances of classes like 'PersistFieldSql' and 'SqlSelect'. Using this may |
| 2520 | +-- break your code if you change the underlying SQL representation. |
| 2521 | +-- |
| 2522 | +-- @since 3.6.0.0 |
| 2523 | +unsafeCoerceSqlExpr :: (Coercible a b) => SqlExpr a -> SqlExpr b |
| 2524 | +unsafeCoerceSqlExpr = veryUnsafeCoerceSqlExpr |
| 2525 | + |
| 2526 | +-- | Like 'unsafeCoerceSqlExpr' but for the common case where you are |
| 2527 | +-- coercing a 'Value'. |
| 2528 | +-- |
| 2529 | +-- @since 3.6.0.0 |
| 2530 | +unsafeCoerceSqlExprValue :: (Coercible a b) => SqlExpr (Value a) -> SqlExpr (Value b) |
| 2531 | +unsafeCoerceSqlExprValue = veryUnsafeCoerceSqlExpr |
| 2532 | + |
2454 | 2533 | -- | Folks often want the ability to promote a Haskell function into the |
2455 | 2534 | -- 'SqlExpr' expression language - and naturally reach for 'fmap'. |
2456 | 2535 | -- Unfortunately, this is impossible. We cannot send *functions* to the |
|
0 commit comments