FSTLevelDBKey.mm 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Local/FSTLevelDBKey.h"
  17. #include <string>
  18. #include <utility>
  19. #include <vector>
  20. #import "Firestore/Source/Model/FSTDocumentKey.h"
  21. #include "Firestore/core/src/firebase/firestore/model/resource_path.h"
  22. #include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
  23. #include "Firestore/core/src/firebase/firestore/util/string_apple.h"
  24. namespace util = firebase::firestore::util;
  25. namespace util = firebase::firestore::util;
  26. using firebase::firestore::model::ResourcePath;
  27. NS_ASSUME_NONNULL_BEGIN
  28. using firebase::firestore::model::ResourcePath;
  29. using firebase::firestore::util::OrderedCode;
  30. using Firestore::StringView;
  31. using leveldb::Slice;
  32. static const char *kVersionGlobalTable = "version";
  33. static const char *kMutationsTable = "mutation";
  34. static const char *kDocumentMutationsTable = "document_mutation";
  35. static const char *kMutationQueuesTable = "mutation_queue";
  36. static const char *kTargetGlobalTable = "target_global";
  37. static const char *kTargetsTable = "target";
  38. static const char *kQueryTargetsTable = "query_target";
  39. static const char *kTargetDocumentsTable = "target_document";
  40. static const char *kDocumentTargetsTable = "document_target";
  41. static const char *kRemoteDocumentsTable = "remote_document";
  42. /**
  43. * Labels for the components of keys. These serve to make keys self-describing.
  44. *
  45. * These are intended to sort similarly to keys in the server storage format.
  46. *
  47. * Note that the server writes component labels using the equivalent to
  48. * OrderedCode::WriteSignedNumDecreasing. This means that despite the higher numeric value, a
  49. * terminator sorts before a path segment. In order to avoid needing the WriteSignedNumDecreasing
  50. * code just for these values, this enum's values are in the reverse order to the server side.
  51. *
  52. * Most server-side values don't apply here. For example, the server embeds projects, databases,
  53. * namespaces and similar values in its entity keys where the clients just open a different
  54. * leveldb. Similarly, many of these values don't apply to the server since the server is backed
  55. * by spanner which natively has concepts of tables and indexes. Where there's overlap, a comment
  56. * denotes the server value from the storage_format_internal.proto.
  57. */
  58. typedef NS_ENUM(int64_t, FSTComponentLabel) {
  59. /**
  60. * A terminator is the final component of a key. All complete keys have a terminator and a key
  61. * is known to be a key prefix if it doesn't have a terminator.
  62. */
  63. FSTComponentLabelTerminator = 0, // TERMINATOR_COMPONENT = 63, server-side
  64. /** A table name component names the logical table to which the key belongs. */
  65. FSTComponentLabelTableName = 5,
  66. /** A component containing the batch ID of a mutation. */
  67. FSTComponentLabelBatchID = 10,
  68. /** A component containing the canonical ID of a query. */
  69. FSTComponentLabelCanonicalID = 11,
  70. /** A component containing the target ID of a query. */
  71. FSTComponentLabelTargetID = 12,
  72. /** A component containing a user ID. */
  73. FSTComponentLabelUserID = 13,
  74. /**
  75. * A path segment describes just a single segment in a resource path. Path segments that occur
  76. * sequentially in a key represent successive segments in a single path.
  77. *
  78. * This value must be greater than FSTComponentLabelTerminator to ensure that longer paths sort
  79. * after paths that are prefixes of them.
  80. *
  81. * This value must also be larger than other separators so that path suffixes sort after other
  82. * key components.
  83. */
  84. FSTComponentLabelPathSegment = 62, // PATH = 60, server-side
  85. /** The maximum value that can be encoded by WriteSignedNumIncreasing in a single byte. */
  86. FSTComponentLabelUnknown = 63,
  87. };
  88. namespace {
  89. /** Writes a component label to the given key destination. */
  90. void WriteComponentLabel(std::string *dest, FSTComponentLabel label) {
  91. OrderedCode::WriteSignedNumIncreasing(dest, label);
  92. }
  93. /**
  94. * Reads a component label from the given key contents.
  95. *
  96. * If the read is unsuccessful or if the read was successful but the label that was read did not
  97. * match the expectedLabel returns NO and changes none of its arguments.
  98. *
  99. * If the read is successful, returns YES and contents will be updated to the next unread byte.
  100. */
  101. BOOL ReadComponentLabelMatching(absl::string_view *contents, FSTComponentLabel expectedLabel) {
  102. int64_t rawResult = 0;
  103. absl::string_view tmp = *contents;
  104. if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
  105. if (rawResult == expectedLabel) {
  106. *contents = tmp;
  107. return YES;
  108. }
  109. }
  110. return NO;
  111. }
  112. /**
  113. * Reads a signed number from the given key contents and verifies that the value fits in a 32-bit
  114. * integer.
  115. *
  116. * If the read is unsuccessful or the number that was read was out of bounds for an int32_t,
  117. * returns NO, and changes none of its arguments.
  118. *
  119. * If the read is successful, returns YES, contents will be updated to the next unread byte, and
  120. * result will be set to the decoded integer value.
  121. */
  122. BOOL ReadInt32(Slice *contents, int32_t *result) {
  123. int64_t rawResult = 0;
  124. absl::string_view tmp(contents->data(), contents->size());
  125. if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
  126. if (rawResult >= INT32_MIN && rawResult <= INT32_MAX) {
  127. *contents = leveldb::Slice(tmp.data(), tmp.size());
  128. *result = static_cast<int32_t>(rawResult);
  129. return YES;
  130. }
  131. }
  132. return NO;
  133. }
  134. /** Writes a component label and a signed integer to the given key destination. */
  135. void WriteLabeledInt32(std::string *dest, FSTComponentLabel label, int32_t value) {
  136. WriteComponentLabel(dest, label);
  137. OrderedCode::WriteSignedNumIncreasing(dest, value);
  138. }
  139. /**
  140. * Reads a component label and signed number from the given key contents and verifies that the
  141. * label matches the expectedLabel and the value fits in a 32-bit integer.
  142. *
  143. * If the read is unsuccessful, the label didn't match, or the number that was read was out of
  144. * bounds for an int32_t, returns NO, and changes none of its arguments.
  145. *
  146. * If the read is successful, returns YES, contents will be updated to the next unread byte, and
  147. * value will be set to the decoded integer value.
  148. */
  149. BOOL ReadLabeledInt32(Slice *contents, FSTComponentLabel expectedLabel, int32_t *value) {
  150. absl::string_view tmp(contents->data(), contents->size());
  151. if (ReadComponentLabelMatching(&tmp, expectedLabel)) {
  152. Slice tmpSlice = leveldb::Slice(tmp.data(), tmp.size());
  153. if (ReadInt32(&tmpSlice, value)) {
  154. *contents = tmpSlice;
  155. return YES;
  156. }
  157. }
  158. return NO;
  159. }
  160. /** Writes a component label and an encoded string to the given key destination. */
  161. void WriteLabeledString(std::string *dest, FSTComponentLabel label, StringView value) {
  162. WriteComponentLabel(dest, label);
  163. OrderedCode::WriteString(dest, value);
  164. }
  165. /**
  166. * Reads a component label and a string from the given key contents and verifies that the label
  167. * matches the expectedLabel.
  168. *
  169. * If the read is unsuccessful or the label didn't match, returns NO, and changes none of its
  170. * arguments.
  171. *
  172. * If the read is successful, returns YES, contents will be updated to the next unread byte, and
  173. * value will be set to the decoded string value.
  174. */
  175. BOOL ReadLabeledString(Slice *contents, FSTComponentLabel expectedLabel, std::string *value) {
  176. absl::string_view tmp(contents->data(), contents->size());
  177. if (ReadComponentLabelMatching(&tmp, expectedLabel)) {
  178. if (OrderedCode::ReadString(&tmp, value)) {
  179. *contents = leveldb::Slice(tmp.data(), tmp.size());
  180. return YES;
  181. }
  182. }
  183. return NO;
  184. }
  185. /**
  186. * Reads a component label and a string from the given key contents and verifies that the label
  187. * matches the expectedLabel and the string matches the expectedValue.
  188. *
  189. * If the read is unsuccessful, the label or didn't match, or the string value didn't match,
  190. * returns NO, and changes none of its arguments.
  191. *
  192. * If the read is successful, returns YES, contents will be updated to the next unread byte.
  193. */
  194. BOOL ReadLabeledStringMatching(Slice *contents,
  195. FSTComponentLabel expectedLabel,
  196. const char *expectedValue) {
  197. std::string value;
  198. Slice tmp = *contents;
  199. if (ReadLabeledString(&tmp, expectedLabel, &value)) {
  200. if (value == expectedValue) {
  201. *contents = tmp;
  202. return YES;
  203. }
  204. }
  205. return NO;
  206. }
  207. /**
  208. * For each segment in the given resource path writes an FSTComponentLabelPathSegment component
  209. * label and a string containing the path segment.
  210. */
  211. void WriteResourcePath(std::string *dest, const ResourcePath &path) {
  212. for (const auto &segment : path) {
  213. WriteComponentLabel(dest, FSTComponentLabelPathSegment);
  214. OrderedCode::WriteString(dest, segment);
  215. }
  216. }
  217. /**
  218. * Reads component labels and strings from the given key contents until it finds a component label
  219. * other that FSTComponentLabelPathSegment. All matched path segments are assembled into a resource
  220. * path and wrapped in an FSTDocumentKey.
  221. *
  222. * If the read is unsuccessful or the document key is invalid, returns NO, and changes none of its
  223. * arguments.
  224. *
  225. * If the read is successful, returns YES, contents will be updated to the next unread byte, and
  226. * value will be set to the decoded document key.
  227. */
  228. BOOL ReadDocumentKey(Slice *contents, FSTDocumentKey *__strong *result) {
  229. Slice completeSegments = *contents;
  230. std::string segment;
  231. std::vector<std::string> path_segments;
  232. for (;;) {
  233. // Advance a temporary slice to avoid advancing contents into the next key component which may
  234. // not be a path segment.
  235. absl::string_view readPosition(completeSegments.data(), completeSegments.size());
  236. if (!ReadComponentLabelMatching(&readPosition, FSTComponentLabelPathSegment)) {
  237. break;
  238. }
  239. if (!OrderedCode::ReadString(&readPosition, &segment)) {
  240. return NO;
  241. }
  242. path_segments.push_back(std::move(segment));
  243. segment.clear();
  244. completeSegments = leveldb::Slice(readPosition.data(), readPosition.size());
  245. }
  246. ResourcePath path{std::move(path_segments)};
  247. if (path.size() > 0 && [FSTDocumentKey isDocumentKey:path]) {
  248. *contents = completeSegments;
  249. *result = [FSTDocumentKey keyWithPath:path];
  250. return YES;
  251. }
  252. return NO;
  253. }
  254. // Trivial shortcuts that make reading and writing components type-safe.
  255. inline void WriteTerminator(std::string *dest) {
  256. OrderedCode::WriteSignedNumIncreasing(dest, FSTComponentLabelTerminator);
  257. }
  258. inline BOOL ReadTerminator(Slice *contents) {
  259. absl::string_view tmp(contents->data(), contents->size());
  260. BOOL result = ReadComponentLabelMatching(&tmp, FSTComponentLabelTerminator);
  261. *contents = leveldb::Slice(tmp.data(), tmp.size());
  262. return result;
  263. }
  264. inline void WriteTableName(std::string *dest, const char *tableName) {
  265. WriteLabeledString(dest, FSTComponentLabelTableName, tableName);
  266. }
  267. inline BOOL ReadTableNameMatching(Slice *contents, const char *expectedTableName) {
  268. return ReadLabeledStringMatching(contents, FSTComponentLabelTableName, expectedTableName);
  269. }
  270. inline void WriteBatchID(std::string *dest, FSTBatchID batchID) {
  271. WriteLabeledInt32(dest, FSTComponentLabelBatchID, batchID);
  272. }
  273. inline BOOL ReadBatchID(Slice *contents, FSTBatchID *batchID) {
  274. return ReadLabeledInt32(contents, FSTComponentLabelBatchID, batchID);
  275. }
  276. inline void WriteCanonicalID(std::string *dest, StringView canonicalID) {
  277. WriteLabeledString(dest, FSTComponentLabelCanonicalID, canonicalID);
  278. }
  279. inline BOOL ReadCanonicalID(Slice *contents, std::string *canonicalID) {
  280. return ReadLabeledString(contents, FSTComponentLabelCanonicalID, canonicalID);
  281. }
  282. inline void WriteTargetID(std::string *dest, FSTTargetID targetID) {
  283. WriteLabeledInt32(dest, FSTComponentLabelTargetID, targetID);
  284. }
  285. inline BOOL ReadTargetID(Slice *contents, FSTTargetID *targetID) {
  286. return ReadLabeledInt32(contents, FSTComponentLabelTargetID, targetID);
  287. }
  288. inline void WriteUserID(std::string *dest, StringView userID) {
  289. WriteLabeledString(dest, FSTComponentLabelUserID, userID);
  290. }
  291. inline BOOL ReadUserID(Slice *contents, std::string *userID) {
  292. return ReadLabeledString(contents, FSTComponentLabelUserID, userID);
  293. }
  294. } // namespace
  295. @implementation FSTLevelDBVersionKey
  296. + (std::string)key {
  297. std::string result;
  298. WriteTableName(&result, kVersionGlobalTable);
  299. WriteTerminator(&result);
  300. return result;
  301. }
  302. @end
  303. @implementation FSTLevelDBMutationKey {
  304. std::string _userID;
  305. }
  306. + (std::string)keyPrefix {
  307. std::string result;
  308. WriteTableName(&result, kMutationsTable);
  309. return result;
  310. }
  311. + (std::string)keyPrefixWithUserID:(StringView)userID {
  312. std::string result;
  313. WriteTableName(&result, kMutationsTable);
  314. WriteUserID(&result, userID);
  315. return result;
  316. }
  317. + (std::string)keyWithUserID:(StringView)userID batchID:(FSTBatchID)batchID {
  318. std::string result;
  319. WriteTableName(&result, kMutationsTable);
  320. WriteUserID(&result, userID);
  321. WriteBatchID(&result, batchID);
  322. WriteTerminator(&result);
  323. return result;
  324. }
  325. - (const std::string &)userID {
  326. return _userID;
  327. }
  328. - (BOOL)decodeKey:(StringView)key {
  329. _userID.clear();
  330. Slice contents = key;
  331. return ReadTableNameMatching(&contents, kMutationsTable) && ReadUserID(&contents, &_userID) &&
  332. ReadBatchID(&contents, &_batchID) && ReadTerminator(&contents);
  333. }
  334. @end
  335. @implementation FSTLevelDBDocumentMutationKey {
  336. std::string _userID;
  337. }
  338. + (std::string)keyPrefix {
  339. std::string result;
  340. WriteTableName(&result, kDocumentMutationsTable);
  341. return result;
  342. }
  343. + (std::string)keyPrefixWithUserID:(StringView)userID {
  344. std::string result;
  345. WriteTableName(&result, kDocumentMutationsTable);
  346. WriteUserID(&result, userID);
  347. return result;
  348. }
  349. + (std::string)keyPrefixWithUserID:(StringView)userID
  350. resourcePath:(const ResourcePath &)resourcePath {
  351. std::string result;
  352. WriteTableName(&result, kDocumentMutationsTable);
  353. WriteUserID(&result, userID);
  354. WriteResourcePath(&result, resourcePath);
  355. return result;
  356. }
  357. + (std::string)keyWithUserID:(StringView)userID
  358. documentKey:(FSTDocumentKey *)documentKey
  359. batchID:(FSTBatchID)batchID {
  360. std::string result;
  361. WriteTableName(&result, kDocumentMutationsTable);
  362. WriteUserID(&result, userID);
  363. WriteResourcePath(&result, documentKey.path);
  364. WriteBatchID(&result, batchID);
  365. WriteTerminator(&result);
  366. return result;
  367. }
  368. - (const std::string &)userID {
  369. return _userID;
  370. }
  371. - (BOOL)decodeKey:(StringView)key {
  372. _userID.clear();
  373. _documentKey = nil;
  374. Slice contents = key;
  375. return ReadTableNameMatching(&contents, kDocumentMutationsTable) &&
  376. ReadUserID(&contents, &_userID) && ReadDocumentKey(&contents, &_documentKey) &&
  377. ReadBatchID(&contents, &_batchID) && ReadTerminator(&contents);
  378. }
  379. @end
  380. @implementation FSTLevelDBMutationQueueKey {
  381. std::string _userID;
  382. }
  383. + (std::string)keyPrefix {
  384. std::string result;
  385. WriteTableName(&result, kMutationQueuesTable);
  386. return result;
  387. }
  388. + (std::string)keyWithUserID:(StringView)userID {
  389. std::string result;
  390. WriteTableName(&result, kMutationQueuesTable);
  391. WriteUserID(&result, userID);
  392. WriteTerminator(&result);
  393. return result;
  394. }
  395. - (const std::string &)userID {
  396. return _userID;
  397. }
  398. - (BOOL)decodeKey:(StringView)key {
  399. _userID.clear();
  400. Slice contents = key;
  401. return ReadTableNameMatching(&contents, kMutationQueuesTable) &&
  402. ReadUserID(&contents, &_userID) && ReadTerminator(&contents);
  403. }
  404. @end
  405. @implementation FSTLevelDBTargetGlobalKey
  406. + (std::string)key {
  407. std::string result;
  408. WriteTableName(&result, kTargetGlobalTable);
  409. WriteTerminator(&result);
  410. return result;
  411. }
  412. - (BOOL)decodeKey:(StringView)key {
  413. Slice contents = key;
  414. return ReadTableNameMatching(&contents, kTargetGlobalTable) && ReadTerminator(&contents);
  415. }
  416. @end
  417. @implementation FSTLevelDBTargetKey
  418. + (std::string)keyPrefix {
  419. std::string result;
  420. WriteTableName(&result, kTargetsTable);
  421. return result;
  422. }
  423. + (std::string)keyWithTargetID:(FSTTargetID)targetID {
  424. std::string result;
  425. WriteTableName(&result, kTargetsTable);
  426. WriteTargetID(&result, targetID);
  427. WriteTerminator(&result);
  428. return result;
  429. }
  430. - (BOOL)decodeKey:(StringView)key {
  431. Slice contents = key;
  432. return ReadTableNameMatching(&contents, kTargetsTable) && ReadTargetID(&contents, &_targetID) &&
  433. ReadTerminator(&contents);
  434. }
  435. @end
  436. @implementation FSTLevelDBQueryTargetKey {
  437. std::string _canonicalID;
  438. }
  439. + (std::string)keyPrefix {
  440. std::string result;
  441. WriteTableName(&result, kQueryTargetsTable);
  442. return result;
  443. }
  444. + (std::string)keyPrefixWithCanonicalID:(StringView)canonicalID {
  445. std::string result;
  446. WriteTableName(&result, kQueryTargetsTable);
  447. WriteCanonicalID(&result, canonicalID);
  448. return result;
  449. }
  450. + (std::string)keyWithCanonicalID:(StringView)canonicalID targetID:(FSTTargetID)targetID {
  451. std::string result;
  452. WriteTableName(&result, kQueryTargetsTable);
  453. WriteCanonicalID(&result, canonicalID);
  454. WriteTargetID(&result, targetID);
  455. WriteTerminator(&result);
  456. return result;
  457. }
  458. - (const std::string &)canonicalID {
  459. return _canonicalID;
  460. }
  461. - (BOOL)decodeKey:(StringView)key {
  462. _canonicalID.clear();
  463. Slice contents = key;
  464. return ReadTableNameMatching(&contents, kQueryTargetsTable) &&
  465. ReadCanonicalID(&contents, &_canonicalID) && ReadTargetID(&contents, &_targetID) &&
  466. ReadTerminator(&contents);
  467. }
  468. @end
  469. @implementation FSTLevelDBTargetDocumentKey
  470. + (std::string)keyPrefix {
  471. std::string result;
  472. WriteTableName(&result, kTargetDocumentsTable);
  473. return result;
  474. }
  475. + (std::string)keyPrefixWithTargetID:(FSTTargetID)targetID {
  476. std::string result;
  477. WriteTableName(&result, kTargetDocumentsTable);
  478. WriteTargetID(&result, targetID);
  479. return result;
  480. }
  481. + (std::string)keyWithTargetID:(FSTTargetID)targetID documentKey:(FSTDocumentKey *)documentKey {
  482. std::string result;
  483. WriteTableName(&result, kTargetDocumentsTable);
  484. WriteTargetID(&result, targetID);
  485. WriteResourcePath(&result, documentKey.path);
  486. WriteTerminator(&result);
  487. return result;
  488. }
  489. - (BOOL)decodeKey:(Firestore::StringView)key {
  490. _documentKey = nil;
  491. leveldb::Slice contents = key;
  492. return ReadTableNameMatching(&contents, kTargetDocumentsTable) &&
  493. ReadTargetID(&contents, &_targetID) && ReadDocumentKey(&contents, &_documentKey) &&
  494. ReadTerminator(&contents);
  495. }
  496. @end
  497. // Used for sentinel row for a document in the document target index. No target has the ID 0,
  498. // and it will sort first in the list of targets for a document.
  499. static const FSTTargetID kInvalidTargetID = 0;
  500. @implementation FSTLevelDBDocumentTargetKey
  501. + (std::string)keyPrefix {
  502. std::string result;
  503. WriteTableName(&result, kDocumentTargetsTable);
  504. return result;
  505. }
  506. + (std::string)keyPrefixWithResourcePath:(const ResourcePath &)resourcePath {
  507. std::string result;
  508. WriteTableName(&result, kDocumentTargetsTable);
  509. WriteResourcePath(&result, resourcePath);
  510. return result;
  511. }
  512. + (std::string)keyWithDocumentKey:(FSTDocumentKey *)documentKey targetID:(FSTTargetID)targetID {
  513. std::string result;
  514. WriteTableName(&result, kDocumentTargetsTable);
  515. WriteResourcePath(&result, documentKey.path);
  516. WriteTargetID(&result, targetID);
  517. WriteTerminator(&result);
  518. return result;
  519. }
  520. + (std::string)sentinelKeyWithDocumentKey:(FSTDocumentKey *)documentKey {
  521. return [self keyWithDocumentKey:documentKey targetID:kInvalidTargetID];
  522. }
  523. - (BOOL)decodeKey:(Firestore::StringView)key {
  524. _documentKey = nil;
  525. leveldb::Slice contents = key;
  526. return ReadTableNameMatching(&contents, kDocumentTargetsTable) &&
  527. ReadDocumentKey(&contents, &_documentKey) && ReadTargetID(&contents, &_targetID) &&
  528. ReadTerminator(&contents);
  529. }
  530. @end
  531. BOOL FSTTargetIDIsSentinel(FSTTargetID targetId) {
  532. return targetId == 0;
  533. }
  534. @implementation FSTLevelDBRemoteDocumentKey
  535. + (std::string)keyPrefix {
  536. std::string result;
  537. WriteTableName(&result, kRemoteDocumentsTable);
  538. return result;
  539. }
  540. + (std::string)keyPrefixWithResourcePath:(const ResourcePath &)path {
  541. std::string result;
  542. WriteTableName(&result, kRemoteDocumentsTable);
  543. WriteResourcePath(&result, path);
  544. return result;
  545. }
  546. + (std::string)keyWithDocumentKey:(FSTDocumentKey *)key {
  547. std::string result;
  548. WriteTableName(&result, kRemoteDocumentsTable);
  549. WriteResourcePath(&result, key.path);
  550. WriteTerminator(&result);
  551. return result;
  552. }
  553. - (BOOL)decodeKey:(StringView)key {
  554. _documentKey = nil;
  555. Slice contents = key;
  556. return ReadTableNameMatching(&contents, kRemoteDocumentsTable) &&
  557. ReadDocumentKey(&contents, &_documentKey) && ReadTerminator(&contents);
  558. }
  559. @end
  560. NS_ASSUME_NONNULL_END