Hi there,
I’m learning Haskell by implementing a small toy project. I’m stuck implementing an IO action to insert medical reports into a Postgres database.
These reports have many lesions associated with them. I need to insert the report and all its lesions within a transaction.
The reason I’m stuck is because I don’t know how to structure conditional logic for the different conditions that might occur within this IO action.
Lesions should be inserted only if I successfully inserted the report and got the report’s ID. I also need to propagate any potential error from inserting a lesion to the calling function. The action returns IO (Either String Int64), see code sketch below.
This is the sketch of code I’m working on at the moment. It clearly doesn’t even compile but I just want to convey where I’m trying to go. Let me know if it isn’t clear and I’ll provide any clarifications.
data Report = Report
{ procedureDate :: LocalTime,
lesions :: [Lesion]
} deriving (Show, Eq)
insertLesions :: Connection -> Int64 -> [Lesion] -> IO (Either String Int64)
insertLesions db reportID lesions = undefined
insertReport :: Connection -> Int64 -> Report -> IO (Either String Int64)
insertReport db pid report = do
-- Transaction begin omitted
(rs :: [Only Int64]) <-
query
db
"insert into catheterization_reports (user_id, procedure_date)\
\values (?, ?) returning id"
(pid, procedureDate report)
-- I need to make sure `rs` has one element, the ID of the created report, before moving to insert its lesions
-- It would be even better if we can guarantee `rs` contains strictly one element before continuing.
case rs of
[] -> return ()
(Only rid : _) -> do
-- IO action inside a different monad (is this code screaming for monad transformers?)
insertLesions db rid (lesions report)
-- Transaction commit/rollback omitted
-- When the IO action ends I'd like to provide the caller with either the ID of the created report or a string with an error
-- This pattern of error handling might not be the best. I'm trying to understand if exceptions are better in this scenario.
Thanks