This is needed so that immediately re-played requests don't fail.
Consider for example the following scenario: a client makes a batch
request that registers correctly on the server, but fails to return
(e.g. a networking error after the request has been processed). The
client would think that the request failed, but the server will already
have the up to date information. This commit just returns a successful
status if this request is sent again (by the client retrying the
request) instead of returning a conflict.
This however doesn't handle the case of a request failing, a
modification being made by another client, and then the request being
retried. This case will stay fail.
This enables us to have db-constraints for making sure that UIDs are
unique, as well as being more efficient for lookups (which are very
common).
The UID should always be the same as the main_item.uid, though that's
easily enforced as neither of them is allowed to change.
We were failing until now, but since the uid is sure to be unique,
we can just assume that if it's the same uid it's the same content.
This means we can just gracefully fail as the data is the same.
Until now, we were raising an error, but we now just do nothing
and consider it a success.
This is especially useful when a network error caused an item to
be uploaded but not updated on the client side.
Even with the previous check, there could still be a race condition where two
collections with the same UID are created. Adding this extra check after
will prevent that from happening.
If the chunk already has a content and we try to upload it again, we
assume the previous content was correct and this one is the same
(chunks are immutable). We can't actually ensure they are the same due
to the encryption, though they should be.
If a chunk is being uploaded for the first time and doesn't have a
content, throw a validation error rather than throwing an ugly error.
Hard-coding the serialization encoding in the serializers is wrong.
This fix now enables us to change to easily change to msgpack as the
transport layer.
Collections still have a unique encryption key (their collection key), and items
just have a unique key per item in a collection that's derived from the main key
and if we ever want to share items across collections or do something fancy like
that we can just add an encrypted key in there.
Each collection now has an item and the item's UID is the collections
UID. This lets us manipulate collections just like items, and as part of
transactions. This is significant because it lets us change them as part
of transactions!