aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase
diff options
context:
space:
mode:
authorGravatar rsgowman <rgowman@google.com>2018-05-04 15:21:22 -0400
committerGravatar GitHub <noreply@github.com>2018-05-04 15:21:22 -0400
commite12b997c6147663c692233a7e29a7433f4aee6f6 (patch)
treec19fe24c70e057fac00de00ebe5c63214972d72d /Firestore/core/src/firebase
parentadc514a894b819c0a63e85c083b766907b68e6ea (diff)
[De]serialize DocumentKeys via the remote Serializer (#1212)
Diffstat (limited to 'Firestore/core/src/firebase')
-rw-r--r--Firestore/core/src/firebase/firestore/remote/serializer.cc75
-rw-r--r--Firestore/core/src/firebase/firestore/remote/serializer.h39
2 files changed, 99 insertions, 15 deletions
diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.cc b/Firestore/core/src/firebase/firestore/remote/serializer.cc
index 2a89515..e81ea2d 100644
--- a/Firestore/core/src/firebase/firestore/remote/serializer.cc
+++ b/Firestore/core/src/firebase/firestore/remote/serializer.cc
@@ -25,14 +25,18 @@
#include <utility>
#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h"
+#include "Firestore/core/src/firebase/firestore/model/resource_path.h"
#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
namespace firebase {
namespace firestore {
namespace remote {
+using firebase::firestore::model::DatabaseId;
+using firebase::firestore::model::DocumentKey;
using firebase::firestore::model::FieldValue;
using firebase::firestore::model::ObjectValue;
+using firebase::firestore::model::ResourcePath;
using firebase::firestore::util::Status;
using firebase::firestore::util::StatusOr;
@@ -719,6 +723,64 @@ ObjectValue::Map DecodeObject(Reader* reader) {
});
}
+/**
+ * Creates the prefix for a fully qualified resource path, without a local path
+ * on the end.
+ */
+ResourcePath EncodeDatabaseId(const DatabaseId& database_id) {
+ return ResourcePath{"projects", database_id.project_id(), "databases",
+ database_id.database_id()};
+}
+
+/**
+ * Encodes a databaseId and resource path into the following form:
+ * /projects/$projectId/database/$databaseId/documents/$path
+ */
+std::string EncodeResourceName(const DatabaseId& database_id,
+ const ResourcePath& path) {
+ return EncodeDatabaseId(database_id)
+ .Append("documents")
+ .Append(path)
+ .CanonicalString();
+}
+
+/**
+ * Validates that a path has a prefix that looks like a valid encoded
+ * databaseId.
+ */
+bool IsValidResourceName(const ResourcePath& path) {
+ // Resource names have at least 4 components (project ID, database ID)
+ // and commonly the (root) resource type, e.g. documents
+ return path.size() >= 4 && path[0] == "projects" && path[2] == "databases";
+}
+
+/**
+ * Decodes a fully qualified resource name into a resource path and validates
+ * that there is a project and database encoded in the path. There are no
+ * guarantees that a local path is also encoded in this resource name.
+ */
+ResourcePath DecodeResourceName(absl::string_view encoded) {
+ ResourcePath resource = ResourcePath::FromString(encoded);
+ FIREBASE_ASSERT_MESSAGE(IsValidResourceName(resource),
+ "Tried to deserialize invalid key %s",
+ resource.CanonicalString().c_str());
+ return resource;
+}
+
+/**
+ * Decodes a fully qualified resource name into a resource path and validates
+ * that there is a project and database encoded in the path along with a local
+ * path.
+ */
+ResourcePath ExtractLocalPathFromResourceName(
+ const ResourcePath& resource_name) {
+ FIREBASE_ASSERT_MESSAGE(
+ resource_name.size() > 4 && resource_name[4] == "documents",
+ "Tried to deserialize invalid key %s",
+ resource_name.CanonicalString().c_str());
+ return resource_name.PopFirst(5);
+}
+
} // namespace
Status Serializer::EncodeFieldValue(const FieldValue& field_value,
@@ -739,6 +801,19 @@ StatusOr<FieldValue> Serializer::DecodeFieldValue(const uint8_t* bytes,
}
}
+std::string Serializer::EncodeKey(const DocumentKey& key) const {
+ return EncodeResourceName(database_id_, key.path());
+}
+
+DocumentKey Serializer::DecodeKey(absl::string_view name) const {
+ ResourcePath resource = DecodeResourceName(name);
+ FIREBASE_ASSERT_MESSAGE(resource[1] == database_id_.project_id(),
+ "Tried to deserialize key from different project.");
+ FIREBASE_ASSERT_MESSAGE(resource[3] == database_id_.database_id(),
+ "Tried to deserialize key from different database.");
+ return DocumentKey{ExtractLocalPathFromResourceName(resource)};
+}
+
} // namespace remote
} // namespace firestore
} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.h b/Firestore/core/src/firebase/firestore/remote/serializer.h
index 7d13583..86aa6e2 100644
--- a/Firestore/core/src/firebase/firestore/remote/serializer.h
+++ b/Firestore/core/src/firebase/firestore/remote/serializer.h
@@ -19,13 +19,17 @@
#include <cstdint>
#include <cstdlib>
+#include <string>
#include <vector>
+#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_value.h"
#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
#include "Firestore/core/src/firebase/firestore/util/status.h"
#include "Firestore/core/src/firebase/firestore/util/statusor.h"
#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
namespace firebase {
namespace firestore {
@@ -46,20 +50,13 @@ namespace remote {
// interpret." Adjust for C++.
class Serializer {
public:
- Serializer() {
+ /**
+ * @param database_id Must remain valid for the lifetime of this Serializer
+ * object.
+ */
+ explicit Serializer(const firebase::firestore::model::DatabaseId& database_id)
+ : database_id_(database_id) {
}
- // TODO(rsgowman): We eventually need the DatabaseId, but can't add it just
- // yet since it's not used yet (which travis complains about). So for now,
- // we'll create a parameterless ctor (above) that likely won't exist in the
- // final version of this class.
- ///**
- // * @param database_id Must remain valid for the lifetime of this Serializer
- // * object.
- // */
- // explicit Serializer(const firebase::firestore::model::DatabaseId&
- // database_id)
- // : database_id_(database_id) {
- //}
/**
* Converts the FieldValue model passed into bytes.
@@ -101,9 +98,21 @@ class Serializer {
return DecodeFieldValue(bytes.data(), bytes.size());
}
+ /**
+ * Encodes the given document key as a fully qualified name. This includes the
+ * databaseId associated with this Serializer and the key path.
+ */
+ std::string EncodeKey(
+ const firebase::firestore::model::DocumentKey& key) const;
+
+ /**
+ * Decodes the given document key from a fully qualified name.
+ */
+ firebase::firestore::model::DocumentKey DecodeKey(
+ absl::string_view name) const;
+
private:
- // TODO(rsgowman): We don't need the database_id_ yet (but will eventually).
- // model::DatabaseId* database_id_;
+ const firebase::firestore::model::DatabaseId& database_id_;
};
} // namespace remote