Skip to content

Commit 09eee26

Browse files
authored
Port subset of Mutations (#2257)
* Add stubs for missing tests in model/mutation_test.cc * Port SetMutation::ApplyToRemoteDocument() Also involves porting MutationResult. * Port PatchMutation::ApplyToRemoteDocument() * Port DeleteMutation::ApplyToLocalView() * Add MaybeDocumentPtr alias This is to enable porting of the local serializer.
1 parent feadeec commit 09eee26

File tree

4 files changed

+313
-25
lines changed

4 files changed

+313
-25
lines changed

Firestore/core/src/firebase/firestore/model/mutation.cc

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
#include "Firestore/core/src/firebase/firestore/model/mutation.h"
1818

19+
#include <cstdlib>
1920
#include <utility>
2021

2122
#include "Firestore/core/src/firebase/firestore/model/document.h"
2223
#include "Firestore/core/src/firebase/firestore/model/field_path.h"
24+
#include "Firestore/core/src/firebase/firestore/model/no_document.h"
2325
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
2426

2527
namespace firebase {
@@ -53,8 +55,24 @@ SetMutation::SetMutation(DocumentKey&& key,
5355
value_(std::move(value)) {
5456
}
5557

56-
std::shared_ptr<const MaybeDocument> SetMutation::ApplyToLocalView(
57-
const std::shared_ptr<const MaybeDocument>& maybe_doc,
58+
MaybeDocumentPtr SetMutation::ApplyToRemoteDocument(
59+
const MaybeDocumentPtr& maybe_doc,
60+
const MutationResult& mutation_result) const {
61+
VerifyKeyMatches(maybe_doc.get());
62+
63+
HARD_ASSERT(mutation_result.transform_results() == nullptr,
64+
"Transform results received by SetMutation.");
65+
66+
// Unlike applyToLocalView, if we're applying a mutation to a remote document
67+
// the server has accepted the mutation so the precondition must have held.
68+
69+
const SnapshotVersion& version = mutation_result.version();
70+
return absl::make_unique<Document>(FieldValue(value_), key(), version,
71+
DocumentState::kCommittedMutations);
72+
}
73+
74+
MaybeDocumentPtr SetMutation::ApplyToLocalView(
75+
const MaybeDocumentPtr& maybe_doc,
5876
const MaybeDocument*,
5977
const Timestamp&) const {
6078
VerifyKeyMatches(maybe_doc.get());
@@ -77,8 +95,35 @@ PatchMutation::PatchMutation(DocumentKey&& key,
7795
mask_(std::move(mask)) {
7896
}
7997

80-
std::shared_ptr<const MaybeDocument> PatchMutation::ApplyToLocalView(
81-
const std::shared_ptr<const MaybeDocument>& maybe_doc,
98+
MaybeDocumentPtr PatchMutation::ApplyToRemoteDocument(
99+
const MaybeDocumentPtr& maybe_doc,
100+
const MutationResult& mutation_result) const {
101+
VerifyKeyMatches(maybe_doc.get());
102+
HARD_ASSERT(mutation_result.transform_results() == nullptr,
103+
"Transform results received by PatchMutation.");
104+
105+
if (!precondition().IsValidFor(maybe_doc.get())) {
106+
// Since the mutation was not rejected, we know that the precondition
107+
// matched on the backend. We therefore must not have the expected version
108+
// of the document in our cache and return an UnknownDocument with the known
109+
// updateTime.
110+
111+
// TODO(rsgowman): heldwriteacks: Implement. Like this (once UnknownDocument
112+
// is ported):
113+
// return absl::make_unique<UnknownDocument>(key(),
114+
// mutation_result.version());
115+
116+
abort();
117+
}
118+
119+
const SnapshotVersion& version = mutation_result.version();
120+
FieldValue new_data = PatchDocument(maybe_doc.get());
121+
return absl::make_unique<Document>(std::move(new_data), key(), version,
122+
DocumentState::kCommittedMutations);
123+
}
124+
125+
MaybeDocumentPtr PatchMutation::ApplyToLocalView(
126+
const MaybeDocumentPtr& maybe_doc,
82127
const MaybeDocument*,
83128
const Timestamp&) const {
84129
VerifyKeyMatches(maybe_doc.get());
@@ -116,6 +161,31 @@ FieldValue PatchMutation::PatchObject(FieldValue obj) const {
116161
return obj;
117162
}
118163

164+
DeleteMutation::DeleteMutation(DocumentKey&& key, Precondition&& precondition)
165+
: Mutation(std::move(key), std::move(precondition)) {
166+
}
167+
168+
MaybeDocumentPtr DeleteMutation::ApplyToRemoteDocument(
169+
const MaybeDocumentPtr& /*maybe_doc*/,
170+
const MutationResult& /*mutation_result*/) const {
171+
// TODO(rsgowman): Implement.
172+
abort();
173+
}
174+
175+
MaybeDocumentPtr DeleteMutation::ApplyToLocalView(
176+
const MaybeDocumentPtr& maybe_doc,
177+
const MaybeDocument*,
178+
const Timestamp&) const {
179+
VerifyKeyMatches(maybe_doc.get());
180+
181+
if (!precondition().IsValidFor(maybe_doc.get())) {
182+
return maybe_doc;
183+
}
184+
185+
return absl::make_unique<NoDocument>(key(), SnapshotVersion::None(),
186+
/*hasCommittedMutations=*/false);
187+
}
188+
119189
} // namespace model
120190
} // namespace firestore
121191
} // namespace firebase

Firestore/core/src/firebase/firestore/model/mutation.h

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_H_
1919

2020
#include <memory>
21+
#include <utility>
22+
#include <vector>
2123

2224
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2325
#include "Firestore/core/src/firebase/firestore/model/field_mask.h"
@@ -30,6 +32,56 @@ namespace firebase {
3032
namespace firestore {
3133
namespace model {
3234

35+
using MaybeDocumentPtr = std::shared_ptr<const MaybeDocument>;
36+
37+
/**
38+
* The result of applying a mutation to the server. This is a model of the
39+
* WriteResult proto message.
40+
*
41+
* Note that MutationResult does not name which document was mutated. The
42+
* association is implied positionally: for each entry in the array of
43+
* Mutations, there's a corresponding entry in the array of MutationResults.
44+
*/
45+
class MutationResult {
46+
public:
47+
MutationResult(
48+
SnapshotVersion&& version,
49+
const std::shared_ptr<const std::vector<FieldValue>>& transform_results)
50+
: version_(std::move(version)),
51+
transform_results_(std::move(transform_results)) {
52+
}
53+
54+
/**
55+
* The version at which the mutation was committed.
56+
*
57+
* - For most operations, this is the update_time in the WriteResult.
58+
* - For deletes, it is the commit_time of the WriteResponse (because
59+
* deletes are not stored and have no update_time).
60+
*
61+
* Note that these versions can be different: No-op writes will not change
62+
* the update_time even though the commit_time advances.
63+
*/
64+
const SnapshotVersion& version() const {
65+
return version_;
66+
}
67+
68+
/**
69+
* The resulting fields returned from the backend after a TransformMutation
70+
* has been committed. Contains one FieldValue for each FieldTransform
71+
* that was in the mutation.
72+
*
73+
* Will be null if the mutation was not a TransformMutation.
74+
*/
75+
const std::shared_ptr<const std::vector<FieldValue>>& transform_results()
76+
const {
77+
return transform_results_;
78+
}
79+
80+
private:
81+
const SnapshotVersion version_;
82+
const std::shared_ptr<const std::vector<FieldValue>> transform_results_;
83+
};
84+
3385
/**
3486
* Represents a Mutation of a document. Different subclasses of Mutation will
3587
* perform different kinds of changes to a base document. For example, a
@@ -85,7 +137,24 @@ class Mutation {
85137
return precondition_;
86138
}
87139

88-
// TODO(rsgowman): ApplyToRemoteDocument()
140+
/**
141+
* Applies this mutation to the given MaybeDocument for the purposes of
142+
* computing a new remote document. If the input document doesn't match the
143+
* expected state (e.g. it is null or outdated), an `UnknownDocument` can be
144+
* returned.
145+
*
146+
* @param maybe_doc The document to mutate. The input document can be nullptr
147+
* if the client has no knowledge of the pre-mutation state of the
148+
* document.
149+
* @param mutation_result The result of applying the mutation from the
150+
* backend.
151+
* @return The mutated document. The returned document may be an
152+
* UnknownDocument if the mutation could not be applied to the locally
153+
* cached base document.
154+
*/
155+
virtual MaybeDocumentPtr ApplyToRemoteDocument(
156+
const MaybeDocumentPtr& maybe_doc,
157+
const MutationResult& mutation_result) const = 0;
89158

90159
/**
91160
* Applies this mutation to the given MaybeDocument for the purposes of
@@ -104,8 +173,8 @@ class Mutation {
104173
* only if maybe_doc was nullptr and the mutation would not create a new
105174
* document.
106175
*/
107-
virtual std::shared_ptr<const MaybeDocument> ApplyToLocalView(
108-
const std::shared_ptr<const MaybeDocument>& maybe_doc,
176+
virtual MaybeDocumentPtr ApplyToLocalView(
177+
const MaybeDocumentPtr& maybe_doc,
109178
const MaybeDocument* base_doc,
110179
const Timestamp& local_write_time) const = 0;
111180

@@ -131,10 +200,12 @@ class SetMutation : public Mutation {
131200
FieldValue&& value,
132201
Precondition&& precondition);
133202

134-
// TODO(rsgowman): ApplyToRemoteDocument()
203+
MaybeDocumentPtr ApplyToRemoteDocument(
204+
const MaybeDocumentPtr& maybe_doc,
205+
const MutationResult& mutation_result) const override;
135206

136-
std::shared_ptr<const MaybeDocument> ApplyToLocalView(
137-
const std::shared_ptr<const MaybeDocument>& maybe_doc,
207+
MaybeDocumentPtr ApplyToLocalView(
208+
const MaybeDocumentPtr& maybe_doc,
138209
const MaybeDocument* base_doc,
139210
const Timestamp& local_write_time) const override;
140211

@@ -162,10 +233,12 @@ class PatchMutation : public Mutation {
162233
FieldMask&& mask,
163234
Precondition&& precondition);
164235

165-
// TODO(rsgowman): ApplyToRemoteDocument()
236+
MaybeDocumentPtr ApplyToRemoteDocument(
237+
const MaybeDocumentPtr& maybe_doc,
238+
const MutationResult& mutation_result) const override;
166239

167-
std::shared_ptr<const MaybeDocument> ApplyToLocalView(
168-
const std::shared_ptr<const MaybeDocument>& maybe_doc,
240+
MaybeDocumentPtr ApplyToLocalView(
241+
const MaybeDocumentPtr& maybe_doc,
169242
const MaybeDocument* base_doc,
170243
const Timestamp& local_write_time) const override;
171244

@@ -177,6 +250,21 @@ class PatchMutation : public Mutation {
177250
const FieldMask mask_;
178251
};
179252

253+
/** Represents a Delete operation. */
254+
class DeleteMutation : public Mutation {
255+
public:
256+
DeleteMutation(DocumentKey&& key, Precondition&& precondition);
257+
258+
MaybeDocumentPtr ApplyToRemoteDocument(
259+
const MaybeDocumentPtr& maybe_doc,
260+
const MutationResult& mutation_result) const override;
261+
262+
MaybeDocumentPtr ApplyToLocalView(
263+
const MaybeDocumentPtr& maybe_doc,
264+
const MaybeDocument* base_doc,
265+
const Timestamp& local_write_time) const override;
266+
};
267+
180268
} // namespace model
181269
} // namespace firestore
182270
} // namespace firebase

0 commit comments

Comments
 (0)