mutation.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef FIRESTORE_CORE_SRC_MODEL_MUTATION_H_
  17. #define FIRESTORE_CORE_SRC_MODEL_MUTATION_H_
  18. #include <iosfwd>
  19. #include <map>
  20. #include <memory>
  21. #include <string>
  22. #include <utility>
  23. #include <vector>
  24. #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
  25. #include "Firestore/core/src/model/document_key.h"
  26. #include "Firestore/core/src/model/field_mask.h"
  27. #include "Firestore/core/src/model/field_transform.h"
  28. #include "Firestore/core/src/model/object_value.h"
  29. #include "Firestore/core/src/model/precondition.h"
  30. #include "Firestore/core/src/model/snapshot_version.h"
  31. #include "Firestore/core/src/nanopb/message.h"
  32. #include "absl/types/optional.h"
  33. namespace firebase {
  34. namespace firestore {
  35. namespace model {
  36. class Document;
  37. class MutableDocument;
  38. /**
  39. * The result of applying a mutation to the server. This is a model of the
  40. * WriteResult proto message.
  41. *
  42. * Note that MutationResult does not name which document was mutated. The
  43. * association is implied positionally: for each entry in the array of
  44. * Mutations, there's a corresponding entry in the array of MutationResults.
  45. */
  46. class MutationResult {
  47. public:
  48. /** Takes ownership of `transform_results`. */
  49. MutationResult(
  50. SnapshotVersion version,
  51. nanopb::Message<google_firestore_v1_ArrayValue> transform_results)
  52. : version_(version), transform_results_{std::move(transform_results)} {
  53. }
  54. MutationResult(MutationResult&& other) noexcept
  55. : version_{other.version_},
  56. transform_results_{std::move(other.transform_results_)} {
  57. }
  58. /**
  59. * The version at which the mutation was committed.
  60. *
  61. * - For most operations, this is the update_time in the WriteResult.
  62. * - For deletes, it is the commit_time of the WriteResponse (because
  63. * deletes are not stored and have no update_time).
  64. *
  65. * Note that these versions can be different: No-op writes will not change
  66. * the update_time even though the commit_time advances.
  67. */
  68. const SnapshotVersion& version() const {
  69. return version_;
  70. }
  71. /**
  72. * The resulting fields returned from the backend after a TransformMutation
  73. * has been committed. Contains one FieldValue for each FieldTransform that
  74. * was in the mutation.
  75. *
  76. * Will be nullopt if the mutation was not a TransformMutation.
  77. */
  78. const nanopb::Message<google_firestore_v1_ArrayValue>& transform_results()
  79. const {
  80. return transform_results_;
  81. }
  82. std::string ToString() const;
  83. friend std::ostream& operator<<(std::ostream& os,
  84. const MutationResult& result);
  85. friend bool operator==(const MutationResult& lhs, const MutationResult& rhs);
  86. private:
  87. SnapshotVersion version_;
  88. nanopb::Message<google_firestore_v1_ArrayValue> transform_results_;
  89. };
  90. /**
  91. * Represents a Mutation of a document. Different subclasses of Mutation will
  92. * perform different kinds of changes to a base document. For example, a
  93. * SetMutation replaces the value of a document and a DeleteMutation deletes a
  94. * document.
  95. *
  96. * In addition to the value of the document mutations also operate on the
  97. * version. For local mutations (mutations that haven't been committed yet), we
  98. * preserve the existing version for Set and Patch mutations. For
  99. * local deletes, we reset the version to 0.
  100. *
  101. * Here's the expected transition table.
  102. *
  103. * MUTATION APPLIED TO RESULTS IN
  104. * SetMutation Document(v3) Document(v3)
  105. * SetMutation NoDocument(v3) Document(v0)
  106. * SetMutation null Document(v0)
  107. * PatchMutation Document(v3) Document(v3)
  108. * PatchMutation NoDocument(v3) NoDocument(v3)
  109. * PatchMutation null null
  110. * DeleteMutation Document(v3) NoDocument(v0)
  111. * DeleteMutation NoDocument(v3) NoDocument(v0)
  112. * DeleteMutation null NoDocument(v0)
  113. *
  114. * For acknowledged mutations, we use the update_time of the WriteResponse as
  115. * the resulting version for Set and Patch mutations. As deletes have no
  116. * explicit update time, we use the commit_time of the WriteResponse for
  117. * acknowledged deletes.
  118. *
  119. * If a mutation is acknowledged by the backend but fails the precondition
  120. * check locally, we return an `UnknownDocument` and rely on Watch to send us
  121. * the updated version.
  122. *
  123. * Field transforms are used only with Patch and Set Mutations. We use the
  124. * `updateTransforms` field to store transforms, rather than the `transforms`
  125. * message.
  126. *
  127. * Note: Mutation and its subclasses are specially designed to avoid slicing.
  128. * You can assign a subclass of Mutation to an instance of Mutation and the
  129. * full value is preserved, unsliced. Each subclass declares an explicit
  130. * constructor that can recover the derived type. This means that code like
  131. * this will work:
  132. *
  133. * SetMutation set(...);
  134. * Mutation mutation = set;
  135. * SetMutation recovered(mutation);
  136. *
  137. * The final line results in an explicit check that will fail if the type of
  138. * the underlying data is not actually Type::Set.
  139. */
  140. class Mutation {
  141. public:
  142. /**
  143. * Represents the mutation type. This is used in place of dynamic_cast.
  144. */
  145. enum class Type { Set, Patch, Delete, Verify };
  146. /** Creates an invalid mutation. */
  147. Mutation() = default;
  148. /**
  149. * Returns true if the given mutation is a valid instance. Default constructed
  150. * and moved-from Mutations are not valid.
  151. */
  152. bool is_valid() const {
  153. return rep_ != nullptr;
  154. }
  155. /** The runtime type of this mutation. */
  156. Type type() const {
  157. return rep().type();
  158. }
  159. const DocumentKey& key() const {
  160. return rep().key();
  161. }
  162. const Precondition& precondition() const {
  163. return rep().precondition();
  164. }
  165. const std::vector<FieldTransform>& field_transforms() const {
  166. return rep().field_transforms();
  167. }
  168. const absl::optional<FieldMask>& field_mask() const {
  169. return rep().field_mask();
  170. }
  171. /**
  172. * Applies this mutation to the given Document for the purposes of computing
  173. * the committed state of the document after the server has acknowledged that
  174. * this mutation has been successfully committed.
  175. *
  176. * If the input document doesn't match the expected state (e.g. it is invalid
  177. * or outdated), the document state may transition to unknown.
  178. *
  179. * @param document The document to mutate.
  180. * @param mutation_result The backend's response of successfully applying the
  181. * mutation.
  182. */
  183. void ApplyToRemoteDocument(MutableDocument& document,
  184. const MutationResult& mutation_result) const;
  185. /**
  186. * Estimates the latency compensated view of this mutation applied to the
  187. * given MaybeDocument.
  188. *
  189. * Unlike ApplyToRemoteDocument, this method is used before the mutation has
  190. * been committed and so it's possible that the mutation is operating on a
  191. * locally non-existent document and may produce a non-existent document.
  192. *
  193. * @param document The document to mutate.
  194. * @param previous_mask The fields that have been updated before applying this
  195. * mutation.
  196. * @param local_write_time A timestamp indicating the local write time of the
  197. * batch this mutation is a part of.
  198. * @return A `FieldMask` representing the fields that are changed by applying
  199. * this mutation, or `absl::nullopt` if the entire document is overwritten.
  200. */
  201. absl::optional<FieldMask> ApplyToLocalView(
  202. MutableDocument& document,
  203. absl::optional<FieldMask> previous_mask,
  204. const Timestamp& local_write_time) const;
  205. /**
  206. * If this mutation is not idempotent, returns the base value to persist with
  207. * this mutation. If a base value is returned, the mutation is always
  208. * applied to this base value, even if document has already been updated.
  209. *
  210. * The base value is a sparse object that consists of only the document
  211. * fields for which this mutation contains a non-idempotent transformation
  212. * (e.g. a numeric increment). The provided value guarantees consistent
  213. * behavior for non-idempotent transforms and allow us to return the same
  214. * latency-compensated value even if the backend has already applied the
  215. * mutation. The base value is empty for idempotent mutations, as they can be
  216. * re-played even if the backend has already applied them.
  217. *
  218. * @return a base value to store along with the mutation, or empty for
  219. * idempotent mutations.
  220. */
  221. absl::optional<ObjectValue> ExtractTransformBaseValue(
  222. const Document& document) const {
  223. return rep_->ExtractTransformBaseValue(document);
  224. }
  225. /**
  226. * A utility method to calculate an `Mutation` representing the overlay from
  227. * the final state of the document, and a `FieldMask` representing the fields
  228. * that are mutated by the local mutations, or a `absl::nullopt` if all fields
  229. * should be overwritten.
  230. *
  231. * Returns a mutation that can be applied to a base document to get `doc`, or
  232. * `nullopt` if base document and `doc` is the same.
  233. */
  234. static absl::optional<Mutation> CalculateOverlayMutation(
  235. const MutableDocument& doc, const absl::optional<FieldMask>& mask);
  236. friend bool operator==(const Mutation& lhs, const Mutation& rhs);
  237. size_t Hash() const {
  238. return rep().Hash();
  239. }
  240. std::string ToString() const {
  241. return rep_ ? rep().ToString() : "(invalid)";
  242. }
  243. friend std::ostream& operator<<(std::ostream& os, const Mutation& mutation);
  244. protected:
  245. class Rep {
  246. public:
  247. Rep(DocumentKey&& key, Precondition&& precondition);
  248. Rep(DocumentKey&& key,
  249. Precondition&& precondition,
  250. std::vector<FieldTransform>&& field_transforms);
  251. Rep(DocumentKey&& key,
  252. Precondition&& precondition,
  253. std::vector<FieldTransform>&& field_transforms,
  254. absl::optional<FieldMask>&& mask);
  255. virtual ~Rep() = default;
  256. virtual Type type() const = 0;
  257. const DocumentKey& key() const {
  258. return key_;
  259. }
  260. const Precondition& precondition() const {
  261. return precondition_;
  262. }
  263. const std::vector<FieldTransform>& field_transforms() const {
  264. return field_transforms_;
  265. }
  266. const absl::optional<FieldMask>& field_mask() const {
  267. return mask_;
  268. }
  269. virtual void ApplyToRemoteDocument(
  270. MutableDocument& document,
  271. const MutationResult& mutation_result) const = 0;
  272. virtual absl::optional<FieldMask> ApplyToLocalView(
  273. MutableDocument& document,
  274. absl::optional<FieldMask> previous_mask,
  275. const Timestamp& local_write_time) const = 0;
  276. virtual absl::optional<ObjectValue> ExtractTransformBaseValue(
  277. const Document& document) const;
  278. /**
  279. * Creates a map of "transform results" (a transform result is a field
  280. * value representing the result of applying a transform) for use after a
  281. * mutation containing transforms has been acknowledged by the server.
  282. *
  283. * @param previous_data The state of the data before applying this mutation.
  284. * @param server_transform_results The transform results received by the
  285. * server.
  286. * @return A map of fields to transform results.
  287. */
  288. TransformMap ServerTransformResults(
  289. const ObjectValue& previous_data,
  290. const nanopb::Message<google_firestore_v1_ArrayValue>&
  291. server_transform_results) const;
  292. /**
  293. * Creates a map of "transform results" (a transform result is a field
  294. * value representing the result of applying a transform) for use when
  295. * applying a transform locally.
  296. *
  297. * @param previous_data The state of the data before applying this mutation.
  298. * @param local_write_time The local time of the mutation (used to generate
  299. * ServerTimestampValues).
  300. * @return A map of fields to transform results.
  301. */
  302. TransformMap LocalTransformResults(const ObjectValue& previous_data,
  303. const Timestamp& local_write_time) const;
  304. virtual bool Equals(const Rep& other) const;
  305. virtual size_t Hash() const;
  306. virtual std::string ToString() const = 0;
  307. protected:
  308. void VerifyKeyMatches(const MutableDocument& document) const;
  309. static SnapshotVersion GetPostMutationVersion(
  310. const MutableDocument& document);
  311. private:
  312. DocumentKey key_;
  313. Precondition precondition_;
  314. std::vector<FieldTransform> field_transforms_;
  315. absl::optional<FieldMask> mask_;
  316. };
  317. explicit Mutation(std::shared_ptr<Rep>&& rep) : rep_(std::move(rep)) {
  318. }
  319. const Rep& rep() const {
  320. return *NOT_NULL(rep_);
  321. }
  322. private:
  323. std::shared_ptr<Rep> rep_;
  324. };
  325. inline bool operator!=(const Mutation& lhs, const Mutation& rhs) {
  326. return !(lhs == rhs);
  327. }
  328. } // namespace model
  329. } // namespace firestore
  330. } // namespace firebase
  331. #endif // FIRESTORE_CORE_SRC_MODEL_MUTATION_H_