Closed NickDarvey closed 2 years ago
TL;DR thats because the semantics of UpdateItem are such that it is valid for it to work if the item is not present (no, the tests dont convey that)
Edits an existing item's attributes, or adds a new item to the table if it does not already exist. You can put, delete, or add attribute values. You can also perform a conditional update on an existing item (insert a new attribute name-value pair if it doesn't exist, or replace an existing name-value pair if it has certain expected attribute values).
doesn't handle 400: ResourceNotFoundException
The GetItem API handles item not found by having the response have response.IsItemSet = false
. ResourceNotFoundException
is about the table or indices etc being missing
That sort of thing is covered by the default TableContext.Create having verifyTable = true
and/or createIfNotExists = true
at some stage
See cleanup work to clarify those semantics in https://github.com/fsprojects/FSharp.AWS.DynamoDB/pull/43
Your choices are:
The AWS SDK's ReturnValues
controls emission of results where there has been a successful outcome.
A condition check failure is handled as an Exception, there is no other way, and you do not get to see the original state if it fails
If you do TransactWriteItems
(which is not handled by TableRecord
atm), you can get it to emit the input Item that triggered a condition check failure, but it does not really confer much power beyond the power of UpdateItem or PutItem (and costs twice as much) (aside from the key feature of making two operations on one or more tables be atomic of course)
A TryGetItem
has been added here recently
Sounds like what you're after is either an optimistic UpdateItem guarded by an exists precondition, or something like:
match! t.TryGet key with
| Some v -> // conditional Put or UpdateItem
| None -> // conditional Put
(Or simply use Equinox.DynamoStore
, which will let you (unit test and) write a decide
function based on folding of events without worrying about all this sort of minutiae :D)
Let me know if you have follow-up questions
Hm I note with interest that the ResourceNotFoundException
that GetItemAsync
and friends throws in this library is a pretty questionable design, which probably did not help matters in this instance (and also makes my explanation a little less clear than it could be - I did not have this in mind when I wrote it)
The xmldoc for ResourceNotFoundException
says:
/// The operation tried to access a nonexistent table or index. The resource might not
/// be specified correctly, or its status might not be <code>ACTIVE</code>.
Changing the exception would obviously be a breaking change that's hard to argue for at this stage (the real fix is to use TryGetItem
)
Added some comments re this in #46
Thanks @bartelink, that does clarify.
(Or simply use Equinox.DynamoStore, which will let you (unit test and) write a decide function based on folding of events without worrying about all this sort of minutiae :D)
This is a nice surprise too!
I notice that
UpdateItemAsync
doesn't handle400: ResourceNotFoundException
s and subsequently returns a'TRecord
, not a'TRecord option
. I have a scenario where I want to use anUpdateIfExists
kind of function so I can achieve something in one request, not two. In my case, it wouldn't be particularly exceptional that it sometimes doesn't exist.Is there a design reason why handling of ResourceNotFoundException isn't part of this library that I should be aware of? Why I might want to avoid that approach? (I'm new to DynamoDB...)
https://github.com/fsprojects/FSharp.AWS.DynamoDB/blob/89ed43f10a199a28ff84a52eee0e8f0b66d3244d/src/FSharp.AWS.DynamoDB/TableContext.fs#L277-L299