mutable_document.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright 2021 Google LLC
  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_MUTABLE_DOCUMENT_H_
  17. #define FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_
  18. #include <iosfwd>
  19. #include <memory>
  20. #include <string>
  21. #include <utility>
  22. #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
  23. #include "Firestore/core/src/model/document_key.h"
  24. #include "Firestore/core/src/model/object_value.h"
  25. #include "Firestore/core/src/model/snapshot_version.h"
  26. namespace firebase {
  27. namespace firestore {
  28. namespace model {
  29. /**
  30. * Represents a document in Firestore with a key, version, data and whether it
  31. * has local mutations applied to it.
  32. *
  33. * Documents can transition between states via `ConvertToFoundDocument()`,
  34. * `ConvertToNoDocument()` and `ConvertToUnknownDocument()`. If a document does
  35. * not transition to one of these states even after all mutations have been
  36. * applied, `is_valid_document()` returns false and the document should be
  37. * removed from all views.
  38. */
  39. class MutableDocument {
  40. private:
  41. enum class DocumentType {
  42. /**
  43. * Represents the initial state of a MutableDocument when only the document
  44. * key is known. Invalid documents transition to other states as mutations
  45. * are applied. If a document remains invalid after applying mutations, it
  46. * should be discarded.
  47. */
  48. kInvalid,
  49. /**
  50. * Represents a document in Firestore with a key, version, data and whether
  51. * the data has local mutations applied to it.
  52. */
  53. kFoundDocument,
  54. /** Represents that no documents exists for the key at the given version. */
  55. kNoDocument,
  56. /**
  57. * Represents an existing document whose data is unknown (e.g. a document
  58. * that was updated without a known base document).
  59. */
  60. kUnknownDocument
  61. };
  62. /** Describes the `hasPendingWrites` state of a document. */
  63. enum class DocumentState {
  64. /**
  65. * Local mutations applied via the mutation queue. Document is potentially
  66. * inconsistent.
  67. */
  68. kHasLocalMutations,
  69. /**
  70. * Mutations applied based on a write acknowledgment. Document is
  71. * potentially inconsistent.
  72. */
  73. kHasCommittedMutations,
  74. /** No mutations applied. Document was sent to us by Watch. */
  75. kSynced
  76. };
  77. public:
  78. MutableDocument() = default;
  79. /**
  80. * Creates a document with no known version or data. This document can serve
  81. * as a base document for mutations.
  82. */
  83. static MutableDocument InvalidDocument(DocumentKey document_key);
  84. /**
  85. * Creates a new document that is known to exist with the given data at the
  86. * given version.
  87. */
  88. static MutableDocument FoundDocument(DocumentKey document_key,
  89. const SnapshotVersion& version,
  90. ObjectValue value);
  91. /** Creates a new document that is known to not exisr at the given version. */
  92. static MutableDocument NoDocument(DocumentKey document_key,
  93. const SnapshotVersion& version);
  94. /**
  95. * Creates a new document that is known to exist at the given version but
  96. * whose data is not known (e.g. a document that was updated without a known
  97. * base document).
  98. */
  99. static MutableDocument UnknownDocument(const DocumentKey& document_key,
  100. const SnapshotVersion& version);
  101. /**
  102. * Changes the document type to indicate that it exists and that its version
  103. * and data are known.
  104. */
  105. MutableDocument& ConvertToFoundDocument(const SnapshotVersion& version,
  106. ObjectValue value);
  107. /**
  108. * Changes the document type to indicate that it exists and that its version
  109. * and data are known.
  110. */
  111. MutableDocument& ConvertToFoundDocument(const SnapshotVersion& version);
  112. /**
  113. * Changes the document type to indicate that it doesn't exist at the given
  114. * version.
  115. */
  116. MutableDocument& ConvertToNoDocument(const SnapshotVersion& version);
  117. /**
  118. * Changes the document type to indicate that it exists at a given version but
  119. * that its data is not known (e.g. a document that was updated without a
  120. * known base document).
  121. */
  122. MutableDocument& ConvertToUnknownDocument(const SnapshotVersion& version);
  123. MutableDocument& SetHasCommittedMutations();
  124. MutableDocument& SetHasLocalMutations();
  125. MutableDocument& WithReadTime(const SnapshotVersion& read_time);
  126. /** Creates a new document with a copy of the document's data and state. */
  127. MutableDocument Clone() const;
  128. const DocumentKey& key() const {
  129. return key_;
  130. }
  131. const SnapshotVersion& version() const {
  132. return version_;
  133. }
  134. const SnapshotVersion& read_time() const {
  135. return read_time_;
  136. }
  137. bool has_local_mutations() const {
  138. return document_state_ == DocumentState::kHasLocalMutations;
  139. }
  140. bool has_committed_mutations() const {
  141. return document_state_ == DocumentState::kHasCommittedMutations;
  142. }
  143. bool has_pending_writes() const {
  144. return has_local_mutations() || has_committed_mutations();
  145. }
  146. google_firestore_v1_Value value() const {
  147. return value_->Get();
  148. }
  149. ObjectValue& data() const {
  150. return *value_;
  151. }
  152. /**
  153. * Returns the value at the given path or absl::nullopt. If the path is empty,
  154. * an identical copy of the FieldValue is returned.
  155. *
  156. * @param field_path the path to search.
  157. * @return The value at the path or absl::nullopt if it doesn't exist.
  158. */
  159. absl::optional<google_firestore_v1_Value> field(
  160. const FieldPath& field_path) const {
  161. return value_->Get(field_path);
  162. }
  163. bool is_valid_document() const {
  164. return document_type_ != DocumentType ::kInvalid;
  165. }
  166. bool is_found_document() const {
  167. return document_type_ == DocumentType ::kFoundDocument;
  168. }
  169. bool is_no_document() const {
  170. return document_type_ == DocumentType ::kNoDocument;
  171. }
  172. bool is_unknown_document() const {
  173. return document_type_ == DocumentType ::kUnknownDocument;
  174. }
  175. size_t Hash() const;
  176. std::string ToString() const;
  177. friend bool operator==(const MutableDocument& lhs,
  178. const MutableDocument& rhs);
  179. friend std::ostream& operator<<(std::ostream& os, DocumentState state);
  180. friend std::ostream& operator<<(std::ostream& os, DocumentType type);
  181. private:
  182. MutableDocument(DocumentKey key,
  183. DocumentType document_type,
  184. SnapshotVersion version,
  185. SnapshotVersion read_time,
  186. std::shared_ptr<ObjectValue> value,
  187. DocumentState document_state)
  188. : key_{std::move(key)},
  189. document_type_{document_type},
  190. version_{version},
  191. read_time_{read_time},
  192. value_{std::move(value)},
  193. document_state_{document_state} {
  194. }
  195. DocumentKey key_;
  196. DocumentType document_type_ = DocumentType::kInvalid;
  197. SnapshotVersion version_;
  198. SnapshotVersion read_time_;
  199. // Using a shared pointer to ObjectValue makes MutableDocument copy-assignable
  200. // without having to manually create a deep clone of its Protobuf contents.
  201. std::shared_ptr<ObjectValue> value_ = std::make_shared<ObjectValue>();
  202. DocumentState document_state_ = DocumentState::kSynced;
  203. };
  204. bool operator==(const MutableDocument& lhs, const MutableDocument& rhs);
  205. std::ostream& operator<<(std::ostream& os, const MutableDocument& doc);
  206. inline bool operator!=(const MutableDocument& lhs, const MutableDocument& rhs) {
  207. return !(lhs == rhs);
  208. }
  209. } // namespace model
  210. } // namespace firestore
  211. } // namespace firebase
  212. #endif // FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_