| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781 |
- /*
- * Copyright 2017 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.
- */
- #import "Firestore/Source/Local/FSTLevelDBKey.h"
- #include <string>
- #include <utility>
- #include <vector>
- #import "Firestore/Source/Model/FSTDocumentKey.h"
- #include "Firestore/core/src/firebase/firestore/model/resource_path.h"
- #include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
- #include "Firestore/core/src/firebase/firestore/util/string_apple.h"
- namespace util = firebase::firestore::util;
- namespace util = firebase::firestore::util;
- using firebase::firestore::model::ResourcePath;
- NS_ASSUME_NONNULL_BEGIN
- using firebase::firestore::model::ResourcePath;
- using firebase::firestore::util::OrderedCode;
- using Firestore::StringView;
- using leveldb::Slice;
- static const char *kVersionGlobalTable = "version";
- static const char *kMutationsTable = "mutation";
- static const char *kDocumentMutationsTable = "document_mutation";
- static const char *kMutationQueuesTable = "mutation_queue";
- static const char *kTargetGlobalTable = "target_global";
- static const char *kTargetsTable = "target";
- static const char *kQueryTargetsTable = "query_target";
- static const char *kTargetDocumentsTable = "target_document";
- static const char *kDocumentTargetsTable = "document_target";
- static const char *kRemoteDocumentsTable = "remote_document";
- /**
- * Labels for the components of keys. These serve to make keys self-describing.
- *
- * These are intended to sort similarly to keys in the server storage format.
- *
- * Note that the server writes component labels using the equivalent to
- * OrderedCode::WriteSignedNumDecreasing. This means that despite the higher numeric value, a
- * terminator sorts before a path segment. In order to avoid needing the WriteSignedNumDecreasing
- * code just for these values, this enum's values are in the reverse order to the server side.
- *
- * Most server-side values don't apply here. For example, the server embeds projects, databases,
- * namespaces and similar values in its entity keys where the clients just open a different
- * leveldb. Similarly, many of these values don't apply to the server since the server is backed
- * by spanner which natively has concepts of tables and indexes. Where there's overlap, a comment
- * denotes the server value from the storage_format_internal.proto.
- */
- typedef NS_ENUM(int64_t, FSTComponentLabel) {
- /**
- * A terminator is the final component of a key. All complete keys have a terminator and a key
- * is known to be a key prefix if it doesn't have a terminator.
- */
- FSTComponentLabelTerminator = 0, // TERMINATOR_COMPONENT = 63, server-side
- /** A table name component names the logical table to which the key belongs. */
- FSTComponentLabelTableName = 5,
- /** A component containing the batch ID of a mutation. */
- FSTComponentLabelBatchID = 10,
- /** A component containing the canonical ID of a query. */
- FSTComponentLabelCanonicalID = 11,
- /** A component containing the target ID of a query. */
- FSTComponentLabelTargetID = 12,
- /** A component containing a user ID. */
- FSTComponentLabelUserID = 13,
- /**
- * A path segment describes just a single segment in a resource path. Path segments that occur
- * sequentially in a key represent successive segments in a single path.
- *
- * This value must be greater than FSTComponentLabelTerminator to ensure that longer paths sort
- * after paths that are prefixes of them.
- *
- * This value must also be larger than other separators so that path suffixes sort after other
- * key components.
- */
- FSTComponentLabelPathSegment = 62, // PATH = 60, server-side
- /** The maximum value that can be encoded by WriteSignedNumIncreasing in a single byte. */
- FSTComponentLabelUnknown = 63,
- };
- namespace {
- /** Writes a component label to the given key destination. */
- void WriteComponentLabel(std::string *dest, FSTComponentLabel label) {
- OrderedCode::WriteSignedNumIncreasing(dest, label);
- }
- /**
- * Reads a component label from the given key contents.
- *
- * If the read is unsuccessful, returns NO, and changes none of its arguments.
- *
- * If the read is successful, returns YES, contents will be updated to the next unread byte, and
- * label will be set to the decoded label value.
- */
- BOOL ReadComponentLabel(leveldb::Slice *contents, FSTComponentLabel *label) {
- int64_t rawResult = 0;
- absl::string_view tmp(contents->data(), contents->size());
- if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
- if (rawResult >= FSTComponentLabelTerminator && rawResult <= FSTComponentLabelUnknown) {
- *label = static_cast<FSTComponentLabel>(rawResult);
- *contents = leveldb::Slice(tmp.data(), tmp.size());
- return YES;
- }
- }
- return NO;
- }
- /**
- * Reads a component label from the given key contents.
- *
- * If the read is unsuccessful or if the read was successful but the label that was read did not
- * match the expectedLabel returns NO and changes none of its arguments.
- *
- * If the read is successful, returns YES and contents will be updated to the next unread byte.
- */
- BOOL ReadComponentLabelMatching(absl::string_view *contents, FSTComponentLabel expectedLabel) {
- int64_t rawResult = 0;
- absl::string_view tmp = *contents;
- if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
- if (rawResult == expectedLabel) {
- *contents = tmp;
- return YES;
- }
- }
- return NO;
- }
- /**
- * Reads a signed number from the given key contents and verifies that the value fits in a 32-bit
- * integer.
- *
- * If the read is unsuccessful or the number that was read was out of bounds for an int32_t,
- * returns NO, and changes none of its arguments.
- *
- * If the read is successful, returns YES, contents will be updated to the next unread byte, and
- * result will be set to the decoded integer value.
- */
- BOOL ReadInt32(Slice *contents, int32_t *result) {
- int64_t rawResult = 0;
- absl::string_view tmp(contents->data(), contents->size());
- if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
- if (rawResult >= INT32_MIN && rawResult <= INT32_MAX) {
- *contents = leveldb::Slice(tmp.data(), tmp.size());
- *result = static_cast<int32_t>(rawResult);
- return YES;
- }
- }
- return NO;
- }
- /** Writes a component label and a signed integer to the given key destination. */
- void WriteLabeledInt32(std::string *dest, FSTComponentLabel label, int32_t value) {
- WriteComponentLabel(dest, label);
- OrderedCode::WriteSignedNumIncreasing(dest, value);
- }
- /**
- * Reads a component label and signed number from the given key contents and verifies that the
- * label matches the expectedLabel and the value fits in a 32-bit integer.
- *
- * If the read is unsuccessful, the label didn't match, or the number that was read was out of
- * bounds for an int32_t, returns NO, and changes none of its arguments.
- *
- * If the read is successful, returns YES, contents will be updated to the next unread byte, and
- * value will be set to the decoded integer value.
- */
- BOOL ReadLabeledInt32(Slice *contents, FSTComponentLabel expectedLabel, int32_t *value) {
- absl::string_view tmp(contents->data(), contents->size());
- if (ReadComponentLabelMatching(&tmp, expectedLabel)) {
- Slice tmpSlice = leveldb::Slice(tmp.data(), tmp.size());
- if (ReadInt32(&tmpSlice, value)) {
- *contents = tmpSlice;
- return YES;
- }
- }
- return NO;
- }
- /** Writes a component label and an encoded string to the given key destination. */
- void WriteLabeledString(std::string *dest, FSTComponentLabel label, StringView value) {
- WriteComponentLabel(dest, label);
- OrderedCode::WriteString(dest, value);
- }
- /**
- * Reads a component label and a string from the given key contents and verifies that the label
- * matches the expectedLabel.
- *
- * If the read is unsuccessful or the label didn't match, returns NO, and changes none of its
- * arguments.
- *
- * If the read is successful, returns YES, contents will be updated to the next unread byte, and
- * value will be set to the decoded string value.
- */
- BOOL ReadLabeledString(Slice *contents, FSTComponentLabel expectedLabel, std::string *value) {
- absl::string_view tmp(contents->data(), contents->size());
- if (ReadComponentLabelMatching(&tmp, expectedLabel)) {
- if (OrderedCode::ReadString(&tmp, value)) {
- *contents = leveldb::Slice(tmp.data(), tmp.size());
- return YES;
- }
- }
- return NO;
- }
- /**
- * Reads a component label and a string from the given key contents and verifies that the label
- * matches the expectedLabel and the string matches the expectedValue.
- *
- * If the read is unsuccessful, the label or didn't match, or the string value didn't match,
- * returns NO, and changes none of its arguments.
- *
- * If the read is successful, returns YES, contents will be updated to the next unread byte.
- */
- BOOL ReadLabeledStringMatching(Slice *contents,
- FSTComponentLabel expectedLabel,
- const char *expectedValue) {
- std::string value;
- Slice tmp = *contents;
- if (ReadLabeledString(&tmp, expectedLabel, &value)) {
- if (value == expectedValue) {
- *contents = tmp;
- return YES;
- }
- }
- return NO;
- }
- /**
- * For each segment in the given resource path writes an FSTComponentLabelPathSegment component
- * label and a string containing the path segment.
- */
- void WriteResourcePath(std::string *dest, const ResourcePath &path) {
- for (const auto &segment : path) {
- WriteComponentLabel(dest, FSTComponentLabelPathSegment);
- OrderedCode::WriteString(dest, segment);
- }
- }
- /**
- * Reads component labels and strings from the given key contents until it finds a component label
- * other that FSTComponentLabelPathSegment. All matched path segments are assembled into a resource
- * path and wrapped in an FSTDocumentKey.
- *
- * If the read is unsuccessful or the document key is invalid, returns NO, and changes none of its
- * arguments.
- *
- * If the read is successful, returns YES, contents will be updated to the next unread byte, and
- * value will be set to the decoded document key.
- */
- BOOL ReadDocumentKey(Slice *contents, FSTDocumentKey *__strong *result) {
- Slice completeSegments = *contents;
- std::string segment;
- std::vector<std::string> path_segments;
- for (;;) {
- // Advance a temporary slice to avoid advancing contents into the next key component which may
- // not be a path segment.
- absl::string_view readPosition(completeSegments.data(), completeSegments.size());
- if (!ReadComponentLabelMatching(&readPosition, FSTComponentLabelPathSegment)) {
- break;
- }
- if (!OrderedCode::ReadString(&readPosition, &segment)) {
- return NO;
- }
- path_segments.push_back(std::move(segment));
- segment.clear();
- completeSegments = leveldb::Slice(readPosition.data(), readPosition.size());
- }
- ResourcePath path{std::move(path_segments)};
- if (path.size() > 0 && [FSTDocumentKey isDocumentKey:path]) {
- *contents = completeSegments;
- *result = [FSTDocumentKey keyWithPath:path];
- return YES;
- }
- return NO;
- }
- // Trivial shortcuts that make reading and writing components type-safe.
- inline void WriteTerminator(std::string *dest) {
- OrderedCode::WriteSignedNumIncreasing(dest, FSTComponentLabelTerminator);
- }
- inline BOOL ReadTerminator(Slice *contents) {
- absl::string_view tmp(contents->data(), contents->size());
- BOOL result = ReadComponentLabelMatching(&tmp, FSTComponentLabelTerminator);
- *contents = leveldb::Slice(tmp.data(), tmp.size());
- return result;
- }
- inline void WriteTableName(std::string *dest, const char *tableName) {
- WriteLabeledString(dest, FSTComponentLabelTableName, tableName);
- }
- inline BOOL ReadTableNameMatching(Slice *contents, const char *expectedTableName) {
- return ReadLabeledStringMatching(contents, FSTComponentLabelTableName, expectedTableName);
- }
- inline void WriteBatchID(std::string *dest, FSTBatchID batchID) {
- WriteLabeledInt32(dest, FSTComponentLabelBatchID, batchID);
- }
- inline BOOL ReadBatchID(Slice *contents, FSTBatchID *batchID) {
- return ReadLabeledInt32(contents, FSTComponentLabelBatchID, batchID);
- }
- inline void WriteCanonicalID(std::string *dest, StringView canonicalID) {
- WriteLabeledString(dest, FSTComponentLabelCanonicalID, canonicalID);
- }
- inline BOOL ReadCanonicalID(Slice *contents, std::string *canonicalID) {
- return ReadLabeledString(contents, FSTComponentLabelCanonicalID, canonicalID);
- }
- inline void WriteTargetID(std::string *dest, FSTTargetID targetID) {
- WriteLabeledInt32(dest, FSTComponentLabelTargetID, targetID);
- }
- inline BOOL ReadTargetID(Slice *contents, FSTTargetID *targetID) {
- return ReadLabeledInt32(contents, FSTComponentLabelTargetID, targetID);
- }
- inline void WriteUserID(std::string *dest, StringView userID) {
- WriteLabeledString(dest, FSTComponentLabelUserID, userID);
- }
- inline BOOL ReadUserID(Slice *contents, std::string *userID) {
- return ReadLabeledString(contents, FSTComponentLabelUserID, userID);
- }
- /** Returns a base64-encoded string for an invalid key, used for debug-friendly description text. */
- NSString *InvalidKey(const Slice &key) {
- NSData *keyData =
- [[NSData alloc] initWithBytesNoCopy:(void *)key.data() length:key.size() freeWhenDone:NO];
- return [keyData base64EncodedStringWithOptions:0];
- }
- } // namespace
- @implementation FSTLevelDBKey
- + (NSString *)descriptionForKey:(StringView)key {
- Slice contents = key;
- BOOL isTerminated = NO;
- NSMutableString *description = [NSMutableString string];
- [description appendString:@"["];
- while (contents.size() > 0) {
- Slice tmp = contents;
- FSTComponentLabel label = FSTComponentLabelUnknown;
- if (!ReadComponentLabel(&tmp, &label)) {
- break;
- }
- if (label == FSTComponentLabelTerminator) {
- isTerminated = YES;
- contents = tmp;
- break;
- }
- // Reset tmp since all the different read routines expect to see the separator first
- tmp = contents;
- if (label == FSTComponentLabelPathSegment) {
- FSTDocumentKey *documentKey = nil;
- if (!ReadDocumentKey(&tmp, &documentKey)) {
- break;
- }
- [description appendFormat:@" key=%s", documentKey.path.CanonicalString().c_str()];
- } else if (label == FSTComponentLabelTableName) {
- std::string table;
- if (!ReadLabeledString(&tmp, FSTComponentLabelTableName, &table)) {
- break;
- }
- [description appendFormat:@"%s:", table.c_str()];
- } else if (label == FSTComponentLabelBatchID) {
- FSTBatchID batchID;
- if (!ReadBatchID(&tmp, &batchID)) {
- break;
- }
- [description appendFormat:@" batchID=%d", batchID];
- } else if (label == FSTComponentLabelCanonicalID) {
- std::string canonicalID;
- if (!ReadCanonicalID(&tmp, &canonicalID)) {
- break;
- }
- [description appendFormat:@" canonicalID=%s", canonicalID.c_str()];
- } else if (label == FSTComponentLabelTargetID) {
- FSTTargetID targetID;
- if (!ReadTargetID(&tmp, &targetID)) {
- break;
- }
- [description appendFormat:@" targetID=%d", targetID];
- } else if (label == FSTComponentLabelUserID) {
- std::string userID;
- if (!ReadUserID(&tmp, &userID)) {
- break;
- }
- [description appendFormat:@" userID=%s", userID.c_str()];
- } else {
- [description appendFormat:@" unknown label=%d", (int)label];
- break;
- }
- contents = tmp;
- }
- if (contents.size() > 0) {
- [description appendFormat:@" invalid key=<%@>", InvalidKey(key)];
- } else if (!isTerminated) {
- [description appendFormat:@" incomplete key"];
- }
- [description appendString:@"]"];
- return description;
- }
- @end
- @implementation FSTLevelDBVersionKey
- + (std::string)key {
- std::string result;
- WriteTableName(&result, kVersionGlobalTable);
- WriteTerminator(&result);
- return result;
- }
- @end
- @implementation FSTLevelDBMutationKey {
- std::string _userID;
- }
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kMutationsTable);
- return result;
- }
- + (std::string)keyPrefixWithUserID:(StringView)userID {
- std::string result;
- WriteTableName(&result, kMutationsTable);
- WriteUserID(&result, userID);
- return result;
- }
- + (std::string)keyWithUserID:(StringView)userID batchID:(FSTBatchID)batchID {
- std::string result;
- WriteTableName(&result, kMutationsTable);
- WriteUserID(&result, userID);
- WriteBatchID(&result, batchID);
- WriteTerminator(&result);
- return result;
- }
- - (const std::string &)userID {
- return _userID;
- }
- - (BOOL)decodeKey:(StringView)key {
- _userID.clear();
- Slice contents = key;
- return ReadTableNameMatching(&contents, kMutationsTable) && ReadUserID(&contents, &_userID) &&
- ReadBatchID(&contents, &_batchID) && ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBDocumentMutationKey {
- std::string _userID;
- }
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kDocumentMutationsTable);
- return result;
- }
- + (std::string)keyPrefixWithUserID:(StringView)userID {
- std::string result;
- WriteTableName(&result, kDocumentMutationsTable);
- WriteUserID(&result, userID);
- return result;
- }
- + (std::string)keyPrefixWithUserID:(StringView)userID
- resourcePath:(const ResourcePath &)resourcePath {
- std::string result;
- WriteTableName(&result, kDocumentMutationsTable);
- WriteUserID(&result, userID);
- WriteResourcePath(&result, resourcePath);
- return result;
- }
- + (std::string)keyWithUserID:(StringView)userID
- documentKey:(FSTDocumentKey *)documentKey
- batchID:(FSTBatchID)batchID {
- std::string result;
- WriteTableName(&result, kDocumentMutationsTable);
- WriteUserID(&result, userID);
- WriteResourcePath(&result, documentKey.path);
- WriteBatchID(&result, batchID);
- WriteTerminator(&result);
- return result;
- }
- - (const std::string &)userID {
- return _userID;
- }
- - (BOOL)decodeKey:(StringView)key {
- _userID.clear();
- _documentKey = nil;
- Slice contents = key;
- return ReadTableNameMatching(&contents, kDocumentMutationsTable) &&
- ReadUserID(&contents, &_userID) && ReadDocumentKey(&contents, &_documentKey) &&
- ReadBatchID(&contents, &_batchID) && ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBMutationQueueKey {
- std::string _userID;
- }
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kMutationQueuesTable);
- return result;
- }
- + (std::string)keyWithUserID:(StringView)userID {
- std::string result;
- WriteTableName(&result, kMutationQueuesTable);
- WriteUserID(&result, userID);
- WriteTerminator(&result);
- return result;
- }
- - (const std::string &)userID {
- return _userID;
- }
- - (BOOL)decodeKey:(StringView)key {
- _userID.clear();
- Slice contents = key;
- return ReadTableNameMatching(&contents, kMutationQueuesTable) &&
- ReadUserID(&contents, &_userID) && ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBTargetGlobalKey
- + (std::string)key {
- std::string result;
- WriteTableName(&result, kTargetGlobalTable);
- WriteTerminator(&result);
- return result;
- }
- - (BOOL)decodeKey:(StringView)key {
- Slice contents = key;
- return ReadTableNameMatching(&contents, kTargetGlobalTable) && ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBTargetKey
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kTargetsTable);
- return result;
- }
- + (std::string)keyWithTargetID:(FSTTargetID)targetID {
- std::string result;
- WriteTableName(&result, kTargetsTable);
- WriteTargetID(&result, targetID);
- WriteTerminator(&result);
- return result;
- }
- - (BOOL)decodeKey:(StringView)key {
- Slice contents = key;
- return ReadTableNameMatching(&contents, kTargetsTable) && ReadTargetID(&contents, &_targetID) &&
- ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBQueryTargetKey {
- std::string _canonicalID;
- }
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kQueryTargetsTable);
- return result;
- }
- + (std::string)keyPrefixWithCanonicalID:(StringView)canonicalID {
- std::string result;
- WriteTableName(&result, kQueryTargetsTable);
- WriteCanonicalID(&result, canonicalID);
- return result;
- }
- + (std::string)keyWithCanonicalID:(StringView)canonicalID targetID:(FSTTargetID)targetID {
- std::string result;
- WriteTableName(&result, kQueryTargetsTable);
- WriteCanonicalID(&result, canonicalID);
- WriteTargetID(&result, targetID);
- WriteTerminator(&result);
- return result;
- }
- - (const std::string &)canonicalID {
- return _canonicalID;
- }
- - (BOOL)decodeKey:(StringView)key {
- _canonicalID.clear();
- Slice contents = key;
- return ReadTableNameMatching(&contents, kQueryTargetsTable) &&
- ReadCanonicalID(&contents, &_canonicalID) && ReadTargetID(&contents, &_targetID) &&
- ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBTargetDocumentKey
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kTargetDocumentsTable);
- return result;
- }
- + (std::string)keyPrefixWithTargetID:(FSTTargetID)targetID {
- std::string result;
- WriteTableName(&result, kTargetDocumentsTable);
- WriteTargetID(&result, targetID);
- return result;
- }
- + (std::string)keyWithTargetID:(FSTTargetID)targetID documentKey:(FSTDocumentKey *)documentKey {
- std::string result;
- WriteTableName(&result, kTargetDocumentsTable);
- WriteTargetID(&result, targetID);
- WriteResourcePath(&result, documentKey.path);
- WriteTerminator(&result);
- return result;
- }
- - (BOOL)decodeKey:(Firestore::StringView)key {
- _documentKey = nil;
- leveldb::Slice contents = key;
- return ReadTableNameMatching(&contents, kTargetDocumentsTable) &&
- ReadTargetID(&contents, &_targetID) && ReadDocumentKey(&contents, &_documentKey) &&
- ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBDocumentTargetKey
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kDocumentTargetsTable);
- return result;
- }
- + (std::string)keyPrefixWithResourcePath:(const ResourcePath &)resourcePath {
- std::string result;
- WriteTableName(&result, kDocumentTargetsTable);
- WriteResourcePath(&result, resourcePath);
- return result;
- }
- + (std::string)keyWithDocumentKey:(FSTDocumentKey *)documentKey targetID:(FSTTargetID)targetID {
- std::string result;
- WriteTableName(&result, kDocumentTargetsTable);
- WriteResourcePath(&result, documentKey.path);
- WriteTargetID(&result, targetID);
- WriteTerminator(&result);
- return result;
- }
- - (BOOL)decodeKey:(Firestore::StringView)key {
- _documentKey = nil;
- leveldb::Slice contents = key;
- return ReadTableNameMatching(&contents, kDocumentTargetsTable) &&
- ReadDocumentKey(&contents, &_documentKey) && ReadTargetID(&contents, &_targetID) &&
- ReadTerminator(&contents);
- }
- @end
- @implementation FSTLevelDBRemoteDocumentKey
- + (std::string)keyPrefix {
- std::string result;
- WriteTableName(&result, kRemoteDocumentsTable);
- return result;
- }
- + (std::string)keyPrefixWithResourcePath:(const ResourcePath &)path {
- std::string result;
- WriteTableName(&result, kRemoteDocumentsTable);
- WriteResourcePath(&result, path);
- return result;
- }
- + (std::string)keyWithDocumentKey:(FSTDocumentKey *)key {
- std::string result;
- WriteTableName(&result, kRemoteDocumentsTable);
- WriteResourcePath(&result, key.path);
- WriteTerminator(&result);
- return result;
- }
- - (BOOL)decodeKey:(StringView)key {
- _documentKey = nil;
- Slice contents = key;
- return ReadTableNameMatching(&contents, kRemoteDocumentsTable) &&
- ReadDocumentKey(&contents, &_documentKey) && ReadTerminator(&contents);
- }
- @end
- NS_ASSUME_NONNULL_END
|