-
Notifications
You must be signed in to change notification settings - Fork 292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EntityFields generated from sum tables are partial #987
Comments
To elaborate on the problem: take the definition from
For simplicity, I've made λ> :i Vehicle
data Vehicle
= VehicleBicycleSum (Key Bicycle) | VehicleCarSum (Key Car)
-- Defined at /home/matt/Projects/persistent/persistent-test/src/SumTypeTest.hs:11:1
-- snipping instances ...
data instance EntityField Vehicle typ
= (typ ~ Key Vehicle) => VehicleId
| (typ ~ Key Bicycle) => VehicleBicycle
| (typ ~ Key Car) => VehicleCar
-- Defined at /home/matt/Projects/persistent/persistent-test/src/SumTypeTest.hs:11:1 This is another way of writing a GADT, and can also be written as: data instance EntityField Vehicle where
VehicleId :: EntityField Vehicle VehicleId
VehicleBicycle :: EntityField Vehicle BycicleId
VehicleCar :: EntityField Vehicle CarId This definition is wrong - it should really be: data instance EntityField Vehicle where
VehicleId :: EntityField Vehicle VehicleId
VehicleBicycle :: EntityField Vehicle (Maybe BycicleId)
VehicleCar :: EntityField Vehicle (Maybe CarId) The generated SQL results in a table like this: CREATE TABLE vehicle (
id SERIAL PRIMARY KEY,
bicycle INTEGER REFERENCES bicycle(id),
car INTEGER REFERENCES car(id)
); Notably absent are the
bicycleIds :: SqlPersistM [BicycleId]
bicycleIds =
select $
from $ \vehicle -> do
pure (vehicle ^. VehicleBicycle) This says it returns a Let's look at fieldLens VehicleId =
lensPTH entityKey (\ (Entity _ x) k -> Entity k x)
fieldLens VehicleBicycle =
lensPTH
(\ (Entity _ val) -> case val of
VehicleBicycleSum x -> x
_ -> error "Tried to use fieldLens on a Sum type")
(\ (Entity k _) x -> Entity k (VehicleBicycleSum x)
fieldLens VehicleCar =
lensPTH
(\ (Entity _ value)
-> case value of
VehicleCarSum x ->
x
_ ->
error "Tried to use fieldLens on a Sum type")
(\ (Entity key _) x -> Entity key (VehicleCarSum x)) SO if we do If we just set What we really want to do here is provide a
I may be wrong, but I think that we can transparently move the fieldLens
:: forall f. Functor f
=> EntityField record field
-> (field -> f field) -> Entity record -> f (Entity record) Testing this out locally, and it works. Can we drop the constraint on We get this error message:
The suggested fix is interesting - if we just add the
So it turns out we need to have that Well. Hmm. I suppose we could have an associated type |
That all makes a lot of sense, thanks! Thinking about it more I think it might make sense to instead try and deprecate the "sum table" support. There is clearly a non-trivial amount of complexity required to properly support it, and as per your blog post as well as my own personal experience, I am not convinced it is the best way to model sum types in SQL. With that said it does look like there are some issues with using the shared primary key strategy in persistent currently. For example: #994 |
Yeah, I think I am going to deprecate sum-type support in 2.14. |
Someone can migrate away from this with the following: mkPersist sqlSettings [persistLowerCase|
Bike
name Text
Car
carbonEmissions Int64
+VehicleDeprecated
bike BikeId
car CarId
Vehicle
bike BikeId Maybe
car CarId Maybe
|]
data VehicleSum = VehicleBike BikeId | VehicleCar CarId
fromDb :: Vehicle -> VehicleSum
fromDb (Vehicle (Just bikeId) _) = VehicleBike bikeId
fromDb (Vehicle _ (Just carId)) = VehicleCar carId
fromDb _ = error "database invariant violated" and manually finagling the values out of the database. Creating a constraint ( |
Specifically when reading the field the output is not wrapped in a
Maybe
, even though the result can benull
. The main examples of this occurring are infieldLens
, and when reading a subset of the fields using libraries likeesqueleto
.The text was updated successfully, but these errors were encountered: