Skip to content

Commit e8d9f0f

Browse files
Mutable Documents
1 parent 4f537e7 commit e8d9f0f

File tree

2 files changed

+369
-0
lines changed

2 files changed

+369
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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+
17+
#include "Firestore/core/src/model/mutable_document.h"
18+
19+
#include <ostream>
20+
#include <utility>
21+
22+
namespace firebase {
23+
namespace firestore {
24+
namespace model {
25+
26+
/* static */
27+
MutableDocument MutableDocument::InvalidDocument(
28+
const firebase::firestore::model::DocumentKey& document_key) {
29+
return MutableDocument{document_key, DocumentType::kInvalid,
30+
SnapshotVersion::None(), ObjectValue{},
31+
DocumentState::kSynced};
32+
}
33+
34+
/* static */
35+
MutableDocument MutableDocument::FoundDocument(
36+
const firebase::firestore::model::DocumentKey& document_key,
37+
const firebase::firestore::model::SnapshotVersion& version,
38+
firebase::firestore::model::ObjectValue value) {
39+
return std::move(InvalidDocument(document_key)
40+
.ConvertToFoundDocument(version, std::move(value)));
41+
}
42+
43+
/* static */
44+
MutableDocument MutableDocument::UnknownDocument(
45+
const firebase::firestore::model::DocumentKey& document_key,
46+
const firebase::firestore::model::SnapshotVersion& version) {
47+
return std::move(
48+
InvalidDocument(document_key).ConvertToUnknownDocument(version));
49+
}
50+
51+
/* static */
52+
MutableDocument MutableDocument::NoDocument(
53+
const firebase::firestore::model::DocumentKey& document_key,
54+
const firebase::firestore::model::SnapshotVersion& version) {
55+
return std::move(InvalidDocument(document_key).ConvertToNoDocument(version));
56+
}
57+
58+
MutableDocument& MutableDocument::ConvertToUnknownDocument(
59+
const firebase::firestore::model::SnapshotVersion& version) {
60+
version_ = version;
61+
document_type_ = DocumentType::kUnknownDocument;
62+
value_ = {};
63+
document_state_ = DocumentState::kHasCommittedMutations;
64+
return *this;
65+
}
66+
67+
MutableDocument& MutableDocument::ConvertToFoundDocument(
68+
const firebase::firestore::model::SnapshotVersion& version,
69+
firebase::firestore::model::ObjectValue value) {
70+
version_ = version;
71+
document_type_ = DocumentType::kFoundDocument;
72+
value_ = std::move(value);
73+
document_state_ = DocumentState::kSynced;
74+
return *this;
75+
}
76+
77+
MutableDocument& MutableDocument::ConvertToNoDocument(
78+
const firebase::firestore::model::SnapshotVersion& version) {
79+
version_ = version;
80+
document_type_ = DocumentType::kNoDocument;
81+
value_ = {};
82+
document_state_ = DocumentState::kSynced;
83+
return *this;
84+
}
85+
86+
MutableDocument& MutableDocument::SetHasCommittedMutations() {
87+
document_state_ = DocumentState::kHasCommittedMutations;
88+
return *this;
89+
}
90+
91+
MutableDocument& MutableDocument::SetHasLocalMutations() {
92+
document_state_ = DocumentState::kHasLocalMutations;
93+
return *this;
94+
}
95+
96+
bool operator==(const MutableDocument& lhs, const MutableDocument& rhs) {
97+
return lhs.key_ == rhs.key_ && lhs.document_type_ == rhs.document_type_ &&
98+
lhs.version_ == rhs.version_ && lhs.value_ == rhs.value_ &&
99+
lhs.document_state_ == rhs.document_state_;
100+
}
101+
102+
std::ostream& operator<<(std::ostream& os,
103+
MutableDocument::DocumentState state) {
104+
switch (state) {
105+
case MutableDocument::DocumentState::kHasCommittedMutations:
106+
return os << "kHasCommittedMutations";
107+
case MutableDocument::DocumentState::kHasLocalMutations:
108+
return os << "kHasLocalMutations";
109+
case MutableDocument::DocumentState::kSynced:
110+
return os << "kSynced";
111+
}
112+
}
113+
114+
std::ostream& operator<<(std::ostream& os,
115+
MutableDocument::DocumentType state) {
116+
switch (state) {
117+
case MutableDocument::DocumentType::kInvalid:
118+
return os << "kInvalid";
119+
case MutableDocument::DocumentType::kFoundDocument:
120+
return os << "kFoundDocument";
121+
case MutableDocument::DocumentType::kNoDocument:
122+
return os << "kNoDocument";
123+
case MutableDocument::DocumentType::kUnknownDocument:
124+
return os << "kUnknownDocument";
125+
}
126+
}
127+
128+
std::ostream& operator<<(std::ostream& os, const MutableDocument& doc) {
129+
return os << "MutableDocument(key=" << doc.key_
130+
<< ", type=" << doc.document_type_ << ", version=" << doc.version_
131+
<< ", value=" << doc.value_ << ", state=" << doc.document_state_;
132+
}
133+
134+
} // namespace model
135+
} // namespace firestore
136+
} // namespace firebase
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
#include <utility>
2+
3+
/*
4+
* Copyright 2021 Google LLC
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#ifndef FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_
20+
#define FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_
21+
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/field_value.h"
25+
#include "Firestore/core/src/model/snapshot_version.h"
26+
27+
#include <utility>
28+
29+
// TODO(mutabledocuments): We might want to call this class Document and replace
30+
// the existing class.
31+
32+
/**
33+
* Represents a document in Firestore with a key, version, data and whether it
34+
* has local mutations applied to it.
35+
*
36+
* Documents can transition between states via `ConvertToFoundDocument()`,
37+
* `ConvertToNoDocument()` and `ConvertToUnknownDocument()`. If a document does
38+
* not transition to one of these states even after all mutations have been
39+
* applied, `is_valid_document()` returns false and the document should be
40+
* removed from all views.
41+
*/
42+
namespace firebase {
43+
namespace firestore {
44+
namespace model {
45+
46+
class MutableDocument {
47+
private:
48+
enum class DocumentType {
49+
/**
50+
* Represents the initial state of a MutableDocument when only the document
51+
* key is known. Invalid documents transition to other states as mutations
52+
* are applied. If a document remains invalid after applying mutations, it
53+
* should be discarded.
54+
*/
55+
kInvalid,
56+
/**
57+
* Represents a document in Firestore with a key, version, data and whether
58+
* the data has local mutations applied to it.
59+
*/
60+
kFoundDocument,
61+
/** Represents that no documents exists for the key at the given version. */
62+
kNoDocument,
63+
/**
64+
* Represents an existing document whose data is unknown (e.g. a document
65+
* that was updated without a known base document).
66+
*/
67+
kUnknownDocument
68+
};
69+
70+
/** Describes the `hasPendingWrites` state of a document. */
71+
enum class DocumentState {
72+
/** Local mutations applied via the mutation queue. Document is potentially
73+
inconsistent. */
74+
kHasLocalMutations,
75+
/** Mutations applied based on a write acknowledgment. Document is
76+
potentially inconsistent. */
77+
kHasCommittedMutations,
78+
/** No mutations applied. Document was sent to us by Watch. */
79+
kSynced
80+
};
81+
82+
public:
83+
// MutableDocument contain Proto data that cannot be implicitly created or
84+
// copied.
85+
MutableDocument() = delete;
86+
MutableDocument(const MutableDocument&) = delete;
87+
MutableDocument& operator=(const MutableDocument&) = delete;
88+
89+
MutableDocument(MutableDocument&& other) noexcept
90+
: key_{std::move(other.key_)},
91+
document_type_{other.document_type_},
92+
version_{other.version_},
93+
value_{std::move(other.value_)},
94+
document_state_{other.document_state_} {
95+
}
96+
97+
/**
98+
* Creates a document with no known version or data, but which can serve as
99+
* base document for mutations.
100+
*/
101+
static MutableDocument InvalidDocument(const DocumentKey& document_key);
102+
103+
/** Creates a new document that is known to exist with the given data at the
104+
* given version. */
105+
static MutableDocument FoundDocument(const DocumentKey& document_key,
106+
const SnapshotVersion& version,
107+
ObjectValue value);
108+
109+
/** Creates a new document that is known to not exisr at the given version. */
110+
static MutableDocument NoDocument(const DocumentKey& document_key,
111+
const SnapshotVersion& version);
112+
113+
/**
114+
* Creates a new document that is known to exist at the given version but
115+
* whose data is not known (e.g. a document that was updated without a known
116+
* base document).
117+
*/
118+
static MutableDocument UnknownDocument(const DocumentKey& document_key,
119+
const SnapshotVersion& version);
120+
121+
/**
122+
* Changes the document type to indicate that it exists and that its version
123+
* and data are known.
124+
*/
125+
MutableDocument& ConvertToFoundDocument(const SnapshotVersion& version,
126+
ObjectValue value);
127+
128+
/** Changes the document type to indicate that it doesn't exist at the given
129+
* version. */
130+
MutableDocument& ConvertToNoDocument(const SnapshotVersion& version);
131+
132+
/**
133+
* Changes the document type to indicate that it exists at a given version but
134+
* that its data is not known (e.g. a document that was updated without a
135+
* known base document).
136+
*/
137+
MutableDocument& ConvertToUnknownDocument(const SnapshotVersion& version);
138+
139+
MutableDocument& SetHasCommittedMutations();
140+
141+
MutableDocument& SetHasLocalMutations();
142+
143+
const DocumentKey& key() const {
144+
return key_;
145+
}
146+
147+
const SnapshotVersion& version() const {
148+
return version_;
149+
}
150+
151+
bool has_local_mutations() const {
152+
return document_state_ == DocumentState::kHasLocalMutations;
153+
}
154+
155+
bool has_committed_mutations() const {
156+
return document_state_ == DocumentState::kHasCommittedMutations;
157+
}
158+
159+
bool has_pending_writes() const {
160+
return has_local_mutations() || has_committed_mutations();
161+
}
162+
163+
const model::ObjectValue& data() const {
164+
return value_;
165+
}
166+
167+
/**
168+
* Returns the value at the given path or absl::nullopt. If the path is empty,
169+
* an identical copy of the FieldValue is returned.
170+
*
171+
* @param field_path the path to search.
172+
* @return The value at the path or absl::nullopt if it doesn't exist.
173+
*/
174+
absl::optional<FieldValue> field(const model::FieldPath& field_path) const {
175+
return value_.Get(field_path);
176+
}
177+
178+
bool is_valid_document() const {
179+
return document_type_ != DocumentType ::kInvalid;
180+
}
181+
182+
bool is_found_document() const {
183+
return document_type_ == DocumentType ::kFoundDocument;
184+
}
185+
186+
bool is_no_document() const {
187+
return document_type_ == DocumentType ::kNoDocument;
188+
}
189+
190+
bool is_unknown_document() const {
191+
return document_type_ == DocumentType ::kUnknownDocument;
192+
}
193+
194+
friend bool operator==(const MutableDocument& lhs,
195+
const MutableDocument& rhs);
196+
197+
friend std::ostream& operator<<(std::ostream& os, const MutableDocument& doc);
198+
friend std::ostream& operator<<(std::ostream& os, DocumentState state);
199+
friend std::ostream& operator<<(std::ostream& os, DocumentType type);
200+
201+
private:
202+
MutableDocument(DocumentKey key,
203+
DocumentType document_type,
204+
SnapshotVersion version,
205+
ObjectValue value,
206+
DocumentState document_state)
207+
: key_{std::move(key)},
208+
document_type_{document_type},
209+
version_{version},
210+
value_{std::move(value)},
211+
document_state_{document_state} {
212+
}
213+
214+
DocumentKey key_;
215+
DocumentType document_type_ = DocumentType::kInvalid;
216+
SnapshotVersion version_;
217+
ObjectValue value_;
218+
DocumentState document_state_ = DocumentState::kSynced;
219+
};
220+
221+
bool operator==(const MutableDocument& lhs, const MutableDocument& rhs);
222+
223+
std::ostream& operator<<(std::ostream& os, const MutableDocument& doc);
224+
225+
inline bool operator!=(const MutableDocument& lhs, const MutableDocument& rhs) {
226+
return !(lhs == rhs);
227+
}
228+
229+
} // namespace model
230+
} // namespace firestore
231+
} // namespace firebase
232+
233+
#endif // FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_

0 commit comments

Comments
 (0)