-
Notifications
You must be signed in to change notification settings - Fork 2
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
Api encouraging incorrect implementation #40
Comments
I feel that nowadays people are using unliftio or similar "lifter IO" lib to catch exceptions, which already makes it possible to catch exceptions thrown by this library relatively easily. Of course there's still the downside that exceptions are not visible in types. |
Well this issue is not really about exposing exceptions via MonadError. The issue you've created is #27 but I intentionally created this one to avoid talking about general problem in terms of one specific solution.
I agree with this. Especially since the errors thrown in I think there might be some solutions that avoid issues with exposing more exceptions in MonadError. For instance:
to name a few which immediately come to my head. in the end I would like to be able to write something along (pseudo code): executeNamed [sql| query |] [ param =? foo ]
`catching` \IoExceptionThing -> NameTakenError
`catching` \AnotherIOExceptionThing -> AliasTakenError |
I wonder if haskellari/postgresql-simple#108 is going to be any helpful for handling different errors arising out of postgres-simple? @turboMaCk |
This PR rotted a lot and should probably be closed: #28
Anyway I would like to instead open an issue to discuss the core problem it was attempting to address.
This library exposes 2 types of errors:
My claim is that one never wants to handle the 1 (it's implementation error not legitimate runtime error in most cases). But almost always wants to handle some subset of 2.
The problem
Putting
WithNamedError
thing aside lets clarify why IO exceptions matter.Imagine a table with
UNIQUE
constrained. For obvious reasons when inserting data to the table there is an expected error that could happen - violation of unique constrained. This error most likely needs to be clearly communicated to caller - for instance the specific 400 response with information thatname is taken
in some form should be rendered by HTTP server.The solution that this library encourages is to write 2 queries (why is explained bellow). One to check if given unique column doesn't already exist and then performing the insert. This solution is of course incorrect. In presence of concurrency some other thread could create conflicting entry in between the select and insert.
The correct solution is to perform insert and catch unique constrained violation. So what does it take to do this?
With postgresql-simple one works with
IO
so catching this means catching exception in IO monad. However withpostgresql-simple-named
thisIO
is lifted toLiftIO m => m
. To catch the exception one needs to use construct that could catch it in them
(lifted IO context). For instance using Control.Exception.Lifted which is not part base or implement similar exception handler to this one. I claim that this is no good because good API should make correct implementation simpler not harder.Proposed solutions
There are multiple potential solutions. I have some ideas myself but first I would like to see what others think.
Currently there is an issue for one possible approach #27
The text was updated successfully, but these errors were encountered: