Skip to content

Document/MutableDocument changes #7996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Firestore/core/src/model/document.cc
Original file line number Diff line number Diff line change
@@ -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 <ostream>

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
122 changes: 26 additions & 96 deletions Firestore/core/src/model/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,124 +18,54 @@
#define FIRESTORE_CORE_SRC_MODEL_DOCUMENT_H_

#include <iosfwd>
#include <memory>
#include <string>
#include <utility>

#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 <typename T>
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<FieldValue> 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
Expand Down
27 changes: 17 additions & 10 deletions Firestore/core/src/model/mutable_document.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,30 @@

#include <sstream>

#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<ObjectValue>(), DocumentState::kSynced};
}

/* static */
MutableDocument MutableDocument::FoundDocument(const DocumentKey& document_key,
const SnapshotVersion& version,
ObjectValue value) {
return std::move(InvalidDocument(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(
Expand All @@ -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<ObjectValue>(std::move(value));
document_state_ = DocumentState::kSynced;
return *this;
}
Expand All @@ -63,7 +61,7 @@ MutableDocument& MutableDocument::ConvertToNoDocument(
const SnapshotVersion& version) {
version_ = version;
document_type_ = DocumentType::kNoDocument;
value_ = {};
value_ = std::make_shared<const ObjectValue>();
document_state_ = DocumentState::kSynced;
return *this;
}
Expand All @@ -72,7 +70,7 @@ MutableDocument& MutableDocument::ConvertToUnknownDocument(
const SnapshotVersion& version) {
version_ = version;
document_type_ = DocumentType::kUnknownDocument;
value_ = {};
value_ = std::make_shared<const ObjectValue>();
document_state_ = DocumentState::kHasCommittedMutations;
return *this;
}
Expand All @@ -87,18 +85,27 @@ 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();
}

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,
Expand Down
50 changes: 20 additions & 30 deletions Firestore/core/src/model/mutable_document.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@
#ifndef FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_
#define FIRESTORE_CORE_SRC_MODEL_MUTABLE_DOCUMENT_H_

#include <ostream>
#include <iosfwd>
#include <memory>
#include <string>
#include <utility>

#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
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -169,7 +155,7 @@ class MutableDocument {
}

const ObjectValue& data() const {
return value_;
return *value_;
}

/**
Expand All @@ -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<FieldValue> field(const FieldPath& field_path) const {
return value_.Get(field_path);
absl::optional<google_firestore_v1_Value> field(
const FieldPath& field_path) const {
return value_->Get(field_path);
}

bool is_valid_document() const {
Expand All @@ -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,
Expand All @@ -211,27 +200,28 @@ class MutableDocument {
MutableDocument(DocumentKey key,
DocumentType document_type,
SnapshotVersion version,
ObjectValue value,
std::shared_ptr<const ObjectValue> 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} {
}

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<const ObjectValue> value_ =
std::make_shared<const ObjectValue>();
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);
Expand Down