aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/model
diff options
context:
space:
mode:
authorGravatar zxu <zxu@google.com>2018-04-23 10:51:52 -0400
committerGravatar GitHub <noreply@github.com>2018-04-23 10:51:52 -0400
commit12d9358c96d8de816254992b20d263e8ad9aac63 (patch)
tree4dde38730c95d6ec2582ccdbc1eba12a6f432619 /Firestore/core/src/firebase/firestore/model
parentb2cf8c6d3df3ebe792c4b3932f05ddfc7f477959 (diff)
Update `FieldValue` For Porting `Mutation`s to C++ (#1144)
* update FieldValue for Mutation implementation * address changes * address changes * address change
Diffstat (limited to 'Firestore/core/src/firebase/firestore/model')
-rw-r--r--Firestore/core/src/firebase/firestore/model/CMakeLists.txt1
-rw-r--r--Firestore/core/src/firebase/firestore/model/document.h6
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.cc91
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.h41
-rw-r--r--Firestore/core/src/firebase/firestore/model/maybe_document.h4
5 files changed, 137 insertions, 6 deletions
diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
index 02affdb..cf43d7a 100644
--- a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
@@ -41,6 +41,7 @@ cc_library(
transform_operations.h
types.h
DEPENDS
+ absl_optional
absl_strings
firebase_firestore_util
firebase_firestore_types
diff --git a/Firestore/core/src/firebase/firestore/model/document.h b/Firestore/core/src/firebase/firestore/model/document.h
index 50a7b90..1b7cc13 100644
--- a/Firestore/core/src/firebase/firestore/model/document.h
+++ b/Firestore/core/src/firebase/firestore/model/document.h
@@ -17,8 +17,10 @@
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_H_
+#include "Firestore/core/src/firebase/firestore/model/field_path.h"
#include "Firestore/core/src/firebase/firestore/model/field_value.h"
#include "Firestore/core/src/firebase/firestore/model/maybe_document.h"
+#include "absl/types/optional.h"
namespace firebase {
namespace firestore {
@@ -42,6 +44,10 @@ class Document : public MaybeDocument {
return data_;
}
+ absl::optional<FieldValue> field(const FieldPath& path) const {
+ return data_.Get(path);
+ }
+
bool has_local_mutations() const {
return has_local_mutations_;
}
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.cc b/Firestore/core/src/firebase/firestore/model/field_value.cc
index b0519f7..9b3acad 100644
--- a/Firestore/core/src/firebase/firestore/model/field_value.cc
+++ b/Firestore/core/src/firebase/firestore/model/field_value.cc
@@ -55,6 +55,19 @@ bool Comparable(Type lhs, Type rhs) {
}
}
+// Makes a copy excluding the specified child, which is expected to be assigned
+// different value afterwards.
+ObjectValue::Map CopyExcept(const ObjectValue::Map& object_map,
+ const std::string exclude) {
+ ObjectValue::Map copy;
+ for (const auto& kv : object_map) {
+ if (kv.first != exclude) {
+ copy[kv.first] = kv.second;
+ }
+ }
+ return copy;
+}
+
} // namespace
FieldValue::FieldValue(const FieldValue& value) {
@@ -153,6 +166,81 @@ FieldValue& FieldValue::operator=(FieldValue&& value) {
}
}
+FieldValue FieldValue::Set(const FieldPath& field_path,
+ FieldValue value) const {
+ FIREBASE_ASSERT_MESSAGE(type() == Type::Object,
+ "Cannot set field for non-object FieldValue");
+ FIREBASE_ASSERT_MESSAGE(!field_path.empty(),
+ "Cannot set field for empty path on FieldValue");
+ // Set the value by recursively calling on child object.
+ const std::string& child_name = field_path.first_segment();
+ const ObjectValue::Map& object_map = object_value_.internal_value;
+ if (field_path.size() == 1) {
+ // TODO(zxu): Once immutable type is available, rewrite these.
+ ObjectValue::Map copy = CopyExcept(object_map, child_name);
+ copy[child_name] = std::move(value);
+ return FieldValue::ObjectValueFromMap(std::move(copy));
+ } else {
+ ObjectValue::Map copy = CopyExcept(object_map, child_name);
+ const auto iter = object_map.find(child_name);
+ if (iter == copy.end() || iter->second.type() != Type::Object) {
+ copy[child_name] = FieldValue::ObjectValueFromMap({}).Set(
+ field_path.PopFirst(), std::move(value));
+ } else {
+ copy[child_name] = object_map.at(child_name)
+ .Set(field_path.PopFirst(), std::move(value));
+ }
+ return FieldValue::ObjectValueFromMap(std::move(copy));
+ }
+}
+
+FieldValue FieldValue::Delete(const FieldPath& field_path) const {
+ FIREBASE_ASSERT_MESSAGE(type() == Type::Object,
+ "Cannot delete field for non-object FieldValue");
+ FIREBASE_ASSERT_MESSAGE(!field_path.empty(),
+ "Cannot delete field for empty path on FieldValue");
+ // Delete the value by recursively calling on child object.
+ const std::string& child_name = field_path.first_segment();
+ const ObjectValue::Map& object_map = object_value_.internal_value;
+ if (field_path.size() == 1) {
+ // TODO(zxu): Once immutable type is available, rewrite these.
+ ObjectValue::Map copy = CopyExcept(object_map, child_name);
+ return FieldValue::ObjectValueFromMap(std::move(copy));
+ } else {
+ const auto iter = object_map.find(child_name);
+ if (iter == object_map.end() || iter->second.type() != Type::Object) {
+ // If the found value isn't an object, it cannot contain the remaining
+ // segments of the path. We don't actually change a primitive value to
+ // an object for a delete.
+ return *this;
+ } else {
+ ObjectValue::Map copy = CopyExcept(object_map, child_name);
+ copy[child_name] =
+ object_map.at(child_name).Delete(field_path.PopFirst());
+ return FieldValue::ObjectValueFromMap(std::move(copy));
+ }
+ }
+}
+
+absl::optional<FieldValue> FieldValue::Get(const FieldPath& field_path) const {
+ FIREBASE_ASSERT_MESSAGE(type() == Type::Object,
+ "Cannot get field for non-object FieldValue");
+ const FieldValue* current = this;
+ for (const auto& path : field_path) {
+ if (current->type() != Type::Object) {
+ return absl::nullopt;
+ }
+ const ObjectValue::Map& object_map = current->object_value_.internal_value;
+ const auto iter = object_map.find(path);
+ if (iter == object_map.end()) {
+ return absl::nullopt;
+ } else {
+ current = &iter->second;
+ }
+ }
+ return *current;
+}
+
const FieldValue& FieldValue::NullValue() {
static const FieldValue kNullInstance;
return kNullInstance;
@@ -204,7 +292,6 @@ FieldValue FieldValue::ServerTimestampValue(const Timestamp& local_write_time,
result.SwitchTo(Type::ServerTimestamp);
result.server_timestamp_value_.local_write_time = local_write_time;
result.server_timestamp_value_.previous_value = previous_value;
- result.server_timestamp_value_.has_previous_value_ = true;
return result;
}
@@ -212,7 +299,7 @@ FieldValue FieldValue::ServerTimestampValue(const Timestamp& local_write_time) {
FieldValue result;
result.SwitchTo(Type::ServerTimestamp);
result.server_timestamp_value_.local_write_time = local_write_time;
- result.server_timestamp_value_.has_previous_value_ = false;
+ result.server_timestamp_value_.previous_value = absl::nullopt;
return result;
}
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.h b/Firestore/core/src/firebase/firestore/model/field_value.h
index 3c5af9c..0f7dfc4 100644
--- a/Firestore/core/src/firebase/firestore/model/field_value.h
+++ b/Firestore/core/src/firebase/firestore/model/field_value.h
@@ -27,7 +27,9 @@
#include "Firestore/core/include/firebase/firestore/timestamp.h"
#include "Firestore/core/src/firebase/firestore/model/database_id.h"
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
+#include "Firestore/core/src/firebase/firestore/model/field_path.h"
#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "absl/types/optional.h"
namespace firebase {
namespace firestore {
@@ -35,9 +37,7 @@ namespace model {
struct ServerTimestamp {
Timestamp local_write_time;
- Timestamp previous_value;
- // TODO(zxu123): adopt absl::optional once abseil is ported.
- bool has_previous_value_;
+ absl::optional<Timestamp> previous_value;
};
struct ReferenceValue {
@@ -118,16 +118,49 @@ class FieldValue {
return integer_value_;
}
+ Timestamp timestamp_value() const {
+ FIREBASE_ASSERT(tag_ == Type::Timestamp);
+ return timestamp_value_;
+ }
+
const std::string& string_value() const {
FIREBASE_ASSERT(tag_ == Type::String);
return string_value_;
}
- const ObjectValue object_value() const {
+ ObjectValue object_value() const {
FIREBASE_ASSERT(tag_ == Type::Object);
return ObjectValue{object_value_};
}
+ /**
+ * Returns a FieldValue with the field at the named path set to value.
+ * Any absent parent of the field will also be created accordingly.
+ *
+ * @param field_path The field path to set. Cannot be empty.
+ * @param value The value to set.
+ * @return A new FieldValue with the field set.
+ */
+ FieldValue Set(const FieldPath& field_path, FieldValue value) const;
+
+ /**
+ * Returns a FieldValue with the field path deleted. If there is no field at
+ * the specified path, the returned value is an identical copy.
+ *
+ * @param field_path The field path to remove. Cannot be empty.
+ * @return A new FieldValue with the field path removed.
+ */
+ FieldValue Delete(const FieldPath& field_path) const;
+
+ /**
+ * Returns the value at the given path or absl::nullopt. If the path is empty,
+ * an identical copy of the FieldValue is returned.
+ *
+ * @param field_path the path to search.
+ * @return The value at the path or absl::nullopt if it doesn't exist.
+ */
+ absl::optional<FieldValue> Get(const FieldPath& field_path) const;
+
/** factory methods. */
static const FieldValue& NullValue();
static const FieldValue& TrueValue();
diff --git a/Firestore/core/src/firebase/firestore/model/maybe_document.h b/Firestore/core/src/firebase/firestore/model/maybe_document.h
index 71bd3ef..c2ffb86 100644
--- a/Firestore/core/src/firebase/firestore/model/maybe_document.h
+++ b/Firestore/core/src/firebase/firestore/model/maybe_document.h
@@ -18,6 +18,7 @@
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MAYBE_DOCUMENT_H_
#include <functional>
+#include <memory>
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
@@ -44,6 +45,9 @@ class MaybeDocument {
MaybeDocument(DocumentKey key, SnapshotVersion version);
+ virtual ~MaybeDocument() {
+ }
+
/** The runtime type of this document. */
Type type() const {
return type_;