diff --git a/Firestore/core/src/model/document.cc b/Firestore/core/src/model/document.cc new file mode 100644 index 00000000000..9f74aa5f764 --- /dev/null +++ b/Firestore/core/src/model/document.cc @@ -0,0 +1,31 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/model/document.h" + +#include + +namespace firebase { +namespace firestore { +namespace model { + +std::ostream& operator<<(std::ostream& os, const Document& doc) { + return os << doc.ToString(); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/model/document.h b/Firestore/core/src/model/document.h index 18fa43591e2..ce4d12f1313 100644 --- a/Firestore/core/src/model/document.h +++ b/Firestore/core/src/model/document.h @@ -18,124 +18,54 @@ #define FIRESTORE_CORE_SRC_MODEL_DOCUMENT_H_ #include -#include #include +#include -#include "Firestore/core/src/model/maybe_document.h" -#include "absl/types/any.h" -#include "absl/types/optional.h" +#include "Firestore/core/src/model/mutable_document.h" namespace firebase { namespace firestore { - -typedef struct _google_firestore_v1_Document google_firestore_v1_Document; -typedef struct _google_firestore_v1_Value google_firestore_v1_Value; - -namespace bundle { -class BundleSerializer; -} // namespace bundle - -namespace local { -class LocalSerializer; -} // namespace local - -namespace nanopb { -class Reader; - -template -class Message; -} // namespace nanopb - -namespace remote { -class Serializer; -} // namespace remote - namespace model { -class FieldPath; -class FieldValue; -class ObjectValue; - -/** Describes the `has_pending_writes` state of a document. */ -enum class DocumentState { - /** - * Local mutations applied via the mutation queue. Document is potentially - * inconsistent. - */ - kLocalMutations, - - /** - * Mutations applied based on a write acknowledgment. Document is potentially - * inconsistent. - */ - kCommittedMutations, - - /** No mutations applied. Document was sent to us by Watch. */ - kSynced, -}; - -std::ostream& operator<<(std::ostream& os, DocumentState state); - -/** - * Represents a document in Firestore with a key, version, data and whether the - * data has local mutations applied to it. - */ -class Document : public MaybeDocument { - public: - Document(ObjectValue data, - DocumentKey key, - SnapshotVersion version, - DocumentState document_state); - - private: - // TODO(b/146372592): Make this public once we can use Abseil across - // iOS/public C++ library boundaries. - friend class remote::Serializer; - friend class bundle::BundleSerializer; - - Document(ObjectValue data, - DocumentKey key, - SnapshotVersion version, - DocumentState document_state, - absl::any proto); - +/** Represents an immutable document in Firestore. */ +class Document { public: - /** - * Casts a MaybeDocument to a Document. This is a checked operation that will - * assert if the type of the MaybeDocument isn't actually Type::Document. - */ - explicit Document(const MaybeDocument& document); + Document(MutableDocument document) // NOLINT(runtime/explicit) + : document_{std::move(document)} { + } - /** Creates an invalid Document instance. */ Document() = default; - const ObjectValue& data() const; - - absl::optional field(const FieldPath& path) const; - - DocumentState document_state() const; + const MutableDocument& get() const { + return document_; + } - bool has_local_mutations() const; + const MutableDocument* operator->() const { + return &document_; + } - bool has_committed_mutations() const; + size_t Hash() const { + return document_.Hash(); + } - const absl::any& proto() const; - - /** Compares against another Document. */ - friend bool operator==(const Document& lhs, const Document& rhs); - - friend std::ostream& operator<<(std::ostream& os, const Document& doc); + std::string ToString() const { + return document_.ToString(); + } private: - class Rep; - - const Rep& doc_rep() const; + MutableDocument document_; }; +inline bool operator==(const Document& lhs, const Document& rhs) { + return lhs.get() == rhs.get(); +} + inline bool operator!=(const Document& lhs, const Document& rhs) { return !(lhs == rhs); } +std::ostream& operator<<(std::ostream& os, const Document& doc); + } // namespace model } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/model/mutable_document.cc b/Firestore/core/src/model/mutable_document.cc index 0aa59396dd0..184b2ac81ff 100644 --- a/Firestore/core/src/model/mutable_document.cc +++ b/Firestore/core/src/model/mutable_document.cc @@ -18,18 +18,18 @@ #include +#include "Firestore/core/src/model/value_util.h" + namespace firebase { namespace firestore { namespace model { -/* static */ MutableDocument MutableDocument::InvalidDocument( const DocumentKey& document_key) { return {document_key, DocumentType::kInvalid, SnapshotVersion::None(), - ObjectValue{}, DocumentState::kSynced}; + std::make_shared(), DocumentState::kSynced}; } -/* static */ MutableDocument MutableDocument::FoundDocument(const DocumentKey& document_key, const SnapshotVersion& version, ObjectValue value) { @@ -37,13 +37,11 @@ MutableDocument MutableDocument::FoundDocument(const DocumentKey& document_key, .ConvertToFoundDocument(version, std::move(value))); } -/* static */ MutableDocument MutableDocument::NoDocument(const DocumentKey& document_key, const SnapshotVersion& version) { return std::move(InvalidDocument(document_key).ConvertToNoDocument(version)); } -/* static */ MutableDocument MutableDocument::UnknownDocument( const DocumentKey& document_key, const SnapshotVersion& version) { return std::move( @@ -54,7 +52,7 @@ MutableDocument& MutableDocument::ConvertToFoundDocument( const SnapshotVersion& version, ObjectValue value) { version_ = version; document_type_ = DocumentType::kFoundDocument; - value_ = std::move(value); + value_ = std::make_shared(std::move(value)); document_state_ = DocumentState::kSynced; return *this; } @@ -63,7 +61,7 @@ MutableDocument& MutableDocument::ConvertToNoDocument( const SnapshotVersion& version) { version_ = version; document_type_ = DocumentType::kNoDocument; - value_ = {}; + value_ = std::make_shared(); document_state_ = DocumentState::kSynced; return *this; } @@ -72,7 +70,7 @@ MutableDocument& MutableDocument::ConvertToUnknownDocument( const SnapshotVersion& version) { version_ = version; document_type_ = DocumentType::kUnknownDocument; - value_ = {}; + value_ = std::make_shared(); document_state_ = DocumentState::kHasCommittedMutations; return *this; } @@ -87,10 +85,14 @@ MutableDocument& MutableDocument::SetHasLocalMutations() { return *this; } +size_t MutableDocument::Hash() const { + return key_.Hash(); +} + std::string MutableDocument::ToString() const { std::stringstream stream; stream << "MutableDocument(key=" << key_ << ", type=" << document_type_ - << ", version=" << version_ << ", value=" << value_ + << ", version=" << version_ << ", value=" << *value_ << ", state=" << document_state_; return stream.str(); } @@ -98,7 +100,12 @@ std::string MutableDocument::ToString() const { bool operator==(const MutableDocument& lhs, const MutableDocument& rhs) { return lhs.key_ == rhs.key_ && lhs.document_type_ == rhs.document_type_ && lhs.version_ == rhs.version_ && - lhs.document_state_ == rhs.document_state_ && lhs.value_ == rhs.value_; + lhs.document_state_ == rhs.document_state_ && + *lhs.value_ == *rhs.value_; +} + +std::ostream& operator<<(std::ostream& os, const MutableDocument& doc) { + return os << doc.ToString(); } std::ostream& operator<<(std::ostream& os, diff --git a/Firestore/core/src/model/mutable_document.h b/Firestore/core/src/model/mutable_document.h index d2d92478b54..0786d0d47ca 100644 --- a/Firestore/core/src/model/mutable_document.h +++ b/Firestore/core/src/model/mutable_document.h @@ -17,17 +17,19 @@ #ifndef FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_ #define FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_ -#include +#include +#include #include #include #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" #include "Firestore/core/src/model/document_key.h" -#include "Firestore/core/src/model/field_value.h" +#include "Firestore/core/src/model/object_value.h" #include "Firestore/core/src/model/snapshot_version.h" -// TODO(mutabledocuments): We might want to call this class Document and replace -// the existing class. +namespace firebase { +namespace firestore { +namespace model { /** * Represents a document in Firestore with a key, version, data and whether it @@ -39,10 +41,6 @@ * applied, `is_valid_document()` returns false and the document should be * removed from all views. */ -namespace firebase { -namespace firestore { -namespace model { - class MutableDocument { private: enum class DocumentType { @@ -84,19 +82,7 @@ class MutableDocument { }; public: - // MutableDocument contain Proto data that cannot be implicitly created or - // copied. - MutableDocument() = delete; - MutableDocument(const MutableDocument&) = delete; - MutableDocument& operator=(const MutableDocument&) = delete; - - MutableDocument(MutableDocument&& other) noexcept - : key_{std::move(other.key_)}, - document_type_{other.document_type_}, - version_{std::move(other.version_)}, - value_{std::move(other.value_)}, - document_state_{other.document_state_} { - } + MutableDocument() = default; /** * Creates a document with no known version or data. This document can serve @@ -169,7 +155,7 @@ class MutableDocument { } const ObjectValue& data() const { - return value_; + return *value_; } /** @@ -179,8 +165,9 @@ class MutableDocument { * @param field_path the path to search. * @return The value at the path or absl::nullopt if it doesn't exist. */ - absl::optional field(const FieldPath& field_path) const { - return value_.Get(field_path); + absl::optional field( + const FieldPath& field_path) const { + return value_->Get(field_path); } bool is_valid_document() const { @@ -199,6 +186,8 @@ class MutableDocument { return document_type_ == DocumentType ::kUnknownDocument; } + size_t Hash() const; + std::string ToString() const; friend bool operator==(const MutableDocument& lhs, @@ -211,11 +200,11 @@ class MutableDocument { MutableDocument(DocumentKey key, DocumentType document_type, SnapshotVersion version, - ObjectValue value, + std::shared_ptr value, DocumentState document_state) : key_{std::move(key)}, document_type_{document_type}, - version_{std::move(version)}, + version_{version}, value_{std::move(value)}, document_state_{document_state} { } @@ -223,15 +212,16 @@ class MutableDocument { DocumentKey key_; DocumentType document_type_ = DocumentType::kInvalid; SnapshotVersion version_; - ObjectValue value_; + // Using a shared pointer to ObjectValue makes MutableDocument copy-assignable + // without having to manually create a deep clone of its Protobuf contents. + std::shared_ptr value_ = + std::make_shared(); DocumentState document_state_ = DocumentState::kSynced; }; bool operator==(const MutableDocument& lhs, const MutableDocument& rhs); -std::ostream& operator<<(std::ostream& os, const MutableDocument& doc) { - return os << doc.ToString(); -} +std::ostream& operator<<(std::ostream& os, const MutableDocument& doc); inline bool operator!=(const MutableDocument& lhs, const MutableDocument& rhs) { return !(lhs == rhs);