I have a post that has an Include' as I've fetched it with a fetchRelated, so it has this type:
post :: Include' ["comments"] Post
If I'd like to save it, I'd get an error
post
|> set #title "Foo"
|> updateRecord
The compiler will complain it's not a Post. It's an Include ... Post
My question is - can the Post be extracted out of the include, so I won't have to fetch it again from the DB?
There's no built-in function in IHP to do this. But you can use a custom helper like this:
clearComments :: Include "comments" Post -> Post
clearComments post = updateField @"comments" (newRecord @Post).comments post
And then use it like this:
post
|> set #title "Foo"
|> clearComments
|> updateRecord
Things can get slightly more complex when we have multiple Include. The compiler will error out,
clearIncludes :: Include ["comments", "tags"] Post -> Post
clearIncludes post = post
|> updateField @"comments" (newRecord @Post).comments
|> updateField @"tags" (newRecord @Post).tags
We need to split this into multiple functions, each with types annotations:
clear1 :: Include' ["comments", "tags"] Post -> Include "tags" Post
clear1 post = post
|> updateField @"comments" (newRecord @Post).comments
clear2 :: Include "tags" Post -> Post
clear2 post = post
|> updateField @"tags" (newRecord @Post).tags
March has explained the reason:
TL;DR: updateField has a more open type signature than set and sometimes GHC needs a bit of help
In very early IHP versions updateField was actually set and it was later changed (because it was causing errors like these). The core problem with updateField is, that it's type definition is very open. It's defined as updateField :: value' -> model -> model'. Here model and model' are two independent type variables. This means a call to updateField can actually change the return type of the record (e.g. turning Post to Post "tags" LandingPage). The problem with your first version was that GHC could not figure out the model' variable because multiple updateField were chained (the model type argument is easy for GHC to figure out, it's just that the model' is independent of that).
For comparison set is defined as set :: value -> model -> model. In that case when GHC can figure out model it will never error. So set is typically easy to figure out and unlikely to error. One the other side the problem with set is that it's less flexible and cannot change the output type (e.g. with model = Post it will be set :: value -> Post -> Post, so there's no way to express e.g. the Include stuff). That's why updateField exists.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With