ACID properties of DB operations
Consider the following (existing) code:
shareNodeWith :: HasNodeError err
=> ShareNodeWith
-> NodeId
-> Cmd err Int
shareNodeWith (ShareNodeWith_User NodeFolderShared u) n = do
nodeToCheck <- getNode n
userIdCheck <- getUserId u
if not (hasNodeType nodeToCheck NodeTeam)
then errorWith "[G.D.A.S.shareNodeWith] Can share node Team only"
else
if (view node_user_id nodeToCheck == userIdCheck)
then errorWith "[G.D.A.S.shareNodeWith] Can share to others only"
else do
folderSharedId <- getFolderId u NodeFolderShared
insertDB ([NodeNode { _nn_node1_id = folderSharedId
, _nn_node2_id = n
, _nn_score = Nothing
, _nn_category = Nothing }]:: [NodeNode])
Due to the fact that this code execute disjointed DB queries, there is no guarantee (as far as I know), that by the time we passed the hasNodeType
check, the node type of nodeToCheck
wouldn't be changed from another asynchronous DB operation, effectively leading us into an inconsistent state.
I haven't looked at the code extensively, but it seems to me we should think about how to use DB transactions to our advantage (which proper types which guarantee composability of operations) to avoid situations like these.
Am I missing something obvious here?