Skip to content

Commit bee6e36

Browse files
author
Brian Chen
committed
port Transaction functionality
1 parent 5568b6c commit bee6e36

File tree

1 file changed

+29
-18
lines changed
  • firebase-firestore/src/main/java/com/google/firebase/firestore/core

1 file changed

+29
-18
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/core/Transaction.java

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ public class Transaction {
6161
*/
6262
private FirebaseFirestoreException lastWriteError;
6363

64+
/**
65+
* Set of documents that have been written in the transaction.
66+
*
67+
* When there's more than one write to the same key in a transaction, any
68+
* writes after the first are handled differently.
69+
*/
70+
private Set<DocumentKey> writtenDocs = new HashSet<>();
71+
6472
public Transaction(Datastore d) {
6573
datastore = d;
6674
}
@@ -95,6 +103,7 @@ public Task<List<MaybeDocument>> lookup(List<DocumentKey> keys) {
95103
/** Stores a set mutation for the given key and value, to be committed when commit() is called. */
96104
public void set(DocumentKey key, ParsedSetData data) {
97105
write(data.toMutationList(key, precondition(key)));
106+
writtenDocs.add(key);
98107
}
99108

100109
/**
@@ -107,13 +116,12 @@ public void update(DocumentKey key, ParsedUpdateData data) {
107116
} catch (FirebaseFirestoreException e) {
108117
lastWriteError = e;
109118
}
119+
this.writtenDocs.add(key);
110120
}
111121

112122
public void delete(DocumentKey key) {
113123
write(Collections.singletonList(new DeleteMutation(key, precondition(key))));
114-
// Since the delete will be applied before all following writes, we need to ensure that the
115-
// precondition for the next write will be exists: false.
116-
readVersions.put(key, SnapshotVersion.NONE);
124+
writtenDocs.add(key);
117125
}
118126

119127
public Task<Void> commit() {
@@ -192,7 +200,7 @@ private void recordVersion(MaybeDocument doc) throws FirebaseFirestoreException
192200
*/
193201
private Precondition precondition(DocumentKey key) {
194202
@Nullable SnapshotVersion version = readVersions.get(key);
195-
if (version != null) {
203+
if (!writtenDocs.contains(key) && version != null) {
196204
return Precondition.updateTime(version);
197205
} else {
198206
return Precondition.NONE;
@@ -205,20 +213,23 @@ private Precondition precondition(DocumentKey key) {
205213
*/
206214
private Precondition preconditionForUpdate(DocumentKey key) throws FirebaseFirestoreException {
207215
@Nullable SnapshotVersion version = this.readVersions.get(key);
208-
if (version != null && version.equals(SnapshotVersion.NONE)) {
209-
// The document to update doesn't exist, so fail the transaction.
210-
//
211-
// This has to be validated locally because you can't send a precondition that a document
212-
// does not exist without changing the semantics of the backend write to be an insert. This is
213-
// the reverse of what we want, since we want to assert that the document doesn't exist but
214-
// then send the update and have it fail. Since we can't express that to the backend, we have
215-
// to validate locally.
216-
//
217-
// Note: this can change once we can send separate verify writes in the transaction.
218-
throw new FirebaseFirestoreException(
219-
"Can't update a document that doesn't exist.", Code.INVALID_ARGUMENT);
220-
} else if (version != null) {
221-
// Document exists, just base precondition on document update time.
216+
// The first time a document is written, we want to take into account the read time and
217+
// existence.
218+
if (!writtenDocs.contains(key) && version != null) {
219+
if (version != null && version.equals(SnapshotVersion.NONE)) {
220+
// The document to update doesn't exist, so fail the transaction.
221+
//
222+
// This has to be validated locally because you can't send a precondition that a document
223+
// does not exist without changing the semantics of the backend write to be an insert. This is
224+
// the reverse of what we want, since we want to assert that the document doesn't exist but
225+
// then send the update and have it fail. Since we can't express that to the backend, we have
226+
// to validate locally.
227+
//
228+
// Note: this can change once we can send separate verify writes in the transaction.
229+
throw new FirebaseFirestoreException(
230+
"Can't update a document that doesn't exist.", Code.INVALID_ARGUMENT);
231+
}
232+
// Document exists, base precondition on document update time.
222233
return Precondition.updateTime(version);
223234
} else {
224235
// Document was not read, so we just use the preconditions for a blind write.

0 commit comments

Comments
 (0)