@firebase/firestore 3.4.4-canary.2dd99ae2d → 3.4.4-canary.3e9f3e253

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/firestore/src/api/credentials.d.ts +1 -0
  2. package/dist/firestore/src/api/snapshot.d.ts +1 -2
  3. package/dist/firestore/src/core/target.d.ts +8 -4
  4. package/dist/firestore/src/lite-api/query.d.ts +2 -2
  5. package/dist/firestore/src/local/document_overlay_cache.d.ts +72 -0
  6. package/dist/firestore/src/local/index_manager.d.ts +52 -0
  7. package/dist/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
  8. package/dist/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  9. package/dist/firestore/src/local/indexeddb_persistence.d.ts +6 -4
  10. package/dist/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  11. package/dist/firestore/src/local/indexeddb_schema.d.ts +193 -7
  12. package/dist/firestore/src/local/local_documents_view.d.ts +0 -1
  13. package/dist/firestore/src/local/local_serializer.d.ts +18 -2
  14. package/dist/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
  15. package/dist/firestore/src/local/memory_index_manager.d.ts +11 -0
  16. package/dist/firestore/src/local/memory_persistence.d.ts +6 -2
  17. package/dist/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  18. package/dist/firestore/src/local/persistence.d.ts +8 -2
  19. package/dist/firestore/src/local/remote_document_cache.d.ts +7 -9
  20. package/dist/firestore/src/local/simple_db.d.ts +1 -0
  21. package/dist/firestore/src/model/document_key.d.ts +4 -0
  22. package/dist/firestore/src/model/field_index.d.ts +2 -2
  23. package/dist/firestore/src/model/overlay.d.ts +32 -0
  24. package/dist/firestore/src/model/target_index_matcher.d.ts +70 -0
  25. package/dist/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  26. package/dist/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
  27. package/dist/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  28. package/dist/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
  29. package/dist/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  30. package/dist/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  31. package/dist/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  32. package/dist/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  33. package/dist/firestore/test/util/helpers.d.ts +1 -1
  34. package/dist/index.d.ts +1 -2
  35. package/dist/index.esm2017.js +3864 -3349
  36. package/dist/index.esm2017.js.map +1 -1
  37. package/dist/index.esm5.js +3879 -3455
  38. package/dist/index.esm5.js.map +1 -1
  39. package/dist/index.node.cjs.js +878 -221
  40. package/dist/index.node.cjs.js.map +1 -1
  41. package/dist/index.node.mjs +878 -221
  42. package/dist/index.node.mjs.map +1 -1
  43. package/dist/index.rn.js +3973 -3458
  44. package/dist/index.rn.js.map +1 -1
  45. package/dist/internal.d.ts +252 -14
  46. package/dist/lite/firestore/src/api/credentials.d.ts +1 -0
  47. package/dist/lite/firestore/src/api/snapshot.d.ts +1 -2
  48. package/dist/lite/firestore/src/core/target.d.ts +8 -4
  49. package/dist/lite/firestore/src/lite-api/query.d.ts +2 -2
  50. package/dist/lite/firestore/src/local/document_overlay_cache.d.ts +72 -0
  51. package/dist/lite/firestore/src/local/index_manager.d.ts +52 -0
  52. package/dist/lite/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
  53. package/dist/lite/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  54. package/dist/lite/firestore/src/local/indexeddb_persistence.d.ts +6 -4
  55. package/dist/lite/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  56. package/dist/lite/firestore/src/local/indexeddb_schema.d.ts +193 -7
  57. package/dist/lite/firestore/src/local/local_documents_view.d.ts +0 -1
  58. package/dist/lite/firestore/src/local/local_serializer.d.ts +18 -2
  59. package/dist/lite/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
  60. package/dist/lite/firestore/src/local/memory_index_manager.d.ts +11 -0
  61. package/dist/lite/firestore/src/local/memory_persistence.d.ts +6 -2
  62. package/dist/lite/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  63. package/dist/lite/firestore/src/local/persistence.d.ts +8 -2
  64. package/dist/lite/firestore/src/local/remote_document_cache.d.ts +7 -9
  65. package/dist/lite/firestore/src/local/simple_db.d.ts +1 -0
  66. package/dist/lite/firestore/src/model/document_key.d.ts +4 -0
  67. package/dist/lite/firestore/src/model/field_index.d.ts +2 -2
  68. package/dist/lite/firestore/src/model/overlay.d.ts +32 -0
  69. package/dist/lite/firestore/src/model/target_index_matcher.d.ts +70 -0
  70. package/dist/lite/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  71. package/dist/lite/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
  72. package/dist/lite/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  73. package/dist/lite/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
  74. package/dist/lite/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  75. package/dist/lite/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  76. package/dist/lite/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  77. package/dist/lite/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  78. package/dist/lite/firestore/test/util/helpers.d.ts +1 -1
  79. package/dist/lite/index.browser.esm2017.js +1152 -1143
  80. package/dist/lite/index.browser.esm2017.js.map +1 -1
  81. package/dist/lite/index.browser.esm5.js +348 -341
  82. package/dist/lite/index.browser.esm5.js.map +1 -1
  83. package/dist/lite/index.node.cjs.js +44 -29
  84. package/dist/lite/index.node.cjs.js.map +1 -1
  85. package/dist/lite/index.node.mjs +44 -29
  86. package/dist/lite/index.node.mjs.map +1 -1
  87. package/dist/lite/index.rn.esm2017.js +1180 -1171
  88. package/dist/lite/index.rn.esm2017.js.map +1 -1
  89. package/dist/lite/internal.d.ts +6 -2
  90. package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +121 -121
  91. package/dist/lite/packages/firestore/src/api/credentials.d.ts +1 -0
  92. package/dist/lite/packages/firestore/src/api/snapshot.d.ts +1 -2
  93. package/dist/lite/packages/firestore/src/core/target.d.ts +8 -4
  94. package/dist/lite/packages/firestore/src/lite-api/query.d.ts +2 -2
  95. package/dist/lite/packages/firestore/src/local/document_overlay_cache.d.ts +72 -0
  96. package/dist/lite/packages/firestore/src/local/index_manager.d.ts +52 -0
  97. package/dist/lite/packages/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
  98. package/dist/lite/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  99. package/dist/lite/packages/firestore/src/local/indexeddb_persistence.d.ts +6 -4
  100. package/dist/lite/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  101. package/dist/lite/packages/firestore/src/local/indexeddb_schema.d.ts +193 -7
  102. package/dist/lite/packages/firestore/src/local/local_documents_view.d.ts +0 -1
  103. package/dist/lite/packages/firestore/src/local/local_serializer.d.ts +18 -2
  104. package/dist/lite/packages/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
  105. package/dist/lite/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
  106. package/dist/lite/packages/firestore/src/local/memory_persistence.d.ts +6 -2
  107. package/dist/lite/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  108. package/dist/lite/packages/firestore/src/local/persistence.d.ts +8 -2
  109. package/dist/lite/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
  110. package/dist/lite/packages/firestore/src/local/simple_db.d.ts +1 -0
  111. package/dist/lite/packages/firestore/src/model/document_key.d.ts +4 -0
  112. package/dist/lite/packages/firestore/src/model/field_index.d.ts +2 -2
  113. package/dist/lite/packages/firestore/src/model/overlay.d.ts +32 -0
  114. package/dist/lite/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
  115. package/dist/lite/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  116. package/dist/lite/packages/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
  117. package/dist/lite/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  118. package/dist/lite/packages/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
  119. package/dist/lite/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  120. package/dist/lite/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  121. package/dist/lite/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  122. package/dist/lite/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  123. package/dist/lite/packages/firestore/test/util/helpers.d.ts +1 -1
  124. package/dist/lite/private.d.ts +2 -2
  125. package/dist/packages/firestore/dist/index.esm2017.d.ts +181 -179
  126. package/dist/packages/firestore/src/api/credentials.d.ts +1 -0
  127. package/dist/packages/firestore/src/api/snapshot.d.ts +1 -2
  128. package/dist/packages/firestore/src/core/target.d.ts +8 -4
  129. package/dist/packages/firestore/src/lite-api/query.d.ts +2 -2
  130. package/dist/packages/firestore/src/local/document_overlay_cache.d.ts +72 -0
  131. package/dist/packages/firestore/src/local/index_manager.d.ts +52 -0
  132. package/dist/packages/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
  133. package/dist/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  134. package/dist/packages/firestore/src/local/indexeddb_persistence.d.ts +6 -4
  135. package/dist/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  136. package/dist/packages/firestore/src/local/indexeddb_schema.d.ts +193 -7
  137. package/dist/packages/firestore/src/local/local_documents_view.d.ts +0 -1
  138. package/dist/packages/firestore/src/local/local_serializer.d.ts +18 -2
  139. package/dist/packages/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
  140. package/dist/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
  141. package/dist/packages/firestore/src/local/memory_persistence.d.ts +6 -2
  142. package/dist/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  143. package/dist/packages/firestore/src/local/persistence.d.ts +8 -2
  144. package/dist/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
  145. package/dist/packages/firestore/src/local/simple_db.d.ts +1 -0
  146. package/dist/packages/firestore/src/model/document_key.d.ts +4 -0
  147. package/dist/packages/firestore/src/model/field_index.d.ts +2 -2
  148. package/dist/packages/firestore/src/model/overlay.d.ts +32 -0
  149. package/dist/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
  150. package/dist/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  151. package/dist/packages/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
  152. package/dist/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  153. package/dist/packages/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
  154. package/dist/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  155. package/dist/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  156. package/dist/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  157. package/dist/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  158. package/dist/packages/firestore/test/util/helpers.d.ts +1 -1
  159. package/dist/private.d.ts +248 -14
  160. package/package.json +9 -9
@@ -12,7 +12,7 @@ var grpcJs = require('@grpc/grpc-js');
12
12
  var protoLoader = require('@grpc/proto-loader');
13
13
 
14
14
  const name = "@firebase/firestore";
15
- const version$1 = "3.4.4-canary.2dd99ae2d";
15
+ const version$1 = "3.4.4-canary.3e9f3e253";
16
16
 
17
17
  /**
18
18
  * @license
@@ -65,7 +65,7 @@ User.GOOGLE_CREDENTIALS = new User('google-credentials-uid');
65
65
  User.FIRST_PARTY = new User('first-party-uid');
66
66
  User.MOCK_USER = new User('mock-user');
67
67
 
68
- const version = "9.6.5-canary.2dd99ae2d";
68
+ const version = "9.6.6-canary.3e9f3e253";
69
69
 
70
70
  /**
71
71
  * @license
@@ -670,13 +670,19 @@ class FirebaseAppCheckTokenProvider {
670
670
  this.appCheckProvider = appCheckProvider;
671
671
  this.forceRefresh = false;
672
672
  this.appCheck = null;
673
+ this.latestAppCheckToken = null;
673
674
  }
674
675
  start(asyncQueue, changeListener) {
675
676
  const onTokenChanged = tokenResult => {
676
677
  if (tokenResult.error != null) {
677
678
  logDebug('FirebaseAppCheckTokenProvider', `Error getting App Check token; using placeholder token instead. Error: ${tokenResult.error.message}`);
678
679
  }
679
- return changeListener(tokenResult.token);
680
+ const tokenUpdated = tokenResult.token !== this.latestAppCheckToken;
681
+ this.latestAppCheckToken = tokenResult.token;
682
+ logDebug('FirebaseAppCheckTokenProvider', `Received ${tokenUpdated ? 'new' : 'existing'} token.`);
683
+ return tokenUpdated
684
+ ? changeListener(tokenResult.token)
685
+ : Promise.resolve();
680
686
  };
681
687
  this.tokenListener = (tokenResult) => {
682
688
  asyncQueue.enqueueRetryable(() => onTokenChanged(tokenResult));
@@ -711,6 +717,7 @@ class FirebaseAppCheckTokenProvider {
711
717
  return this.appCheck.getToken(forceRefresh).then(tokenResult => {
712
718
  if (tokenResult) {
713
719
  hardAssert(typeof tokenResult.token === 'string');
720
+ this.latestAppCheckToken = tokenResult.token;
714
721
  return new AppCheckToken(tokenResult.token);
715
722
  }
716
723
  else {
@@ -1196,23 +1203,6 @@ function decodeResourcePath(path) {
1196
1203
  }
1197
1204
  return new ResourcePath(segments);
1198
1205
  }
1199
-
1200
- /**
1201
- * @license
1202
- * Copyright 2017 Google LLC
1203
- *
1204
- * Licensed under the Apache License, Version 2.0 (the "License");
1205
- * you may not use this file except in compliance with the License.
1206
- * You may obtain a copy of the License at
1207
- *
1208
- * http://www.apache.org/licenses/LICENSE-2.0
1209
- *
1210
- * Unless required by applicable law or agreed to in writing, software
1211
- * distributed under the License is distributed on an "AS IS" BASIS,
1212
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1213
- * See the License for the specific language governing permissions and
1214
- * limitations under the License.
1215
- */
1216
1206
  /**
1217
1207
  * Schema Version for the Web client:
1218
1208
  * 1. Initial version including Mutation Queue, Query Cache, and Remote
@@ -1231,8 +1221,10 @@ function decodeResourcePath(path) {
1231
1221
  * an auto-incrementing ID. This is required for Index-Free queries.
1232
1222
  * 10. Rewrite the canonical IDs to the explicit Protobuf-based format.
1233
1223
  * 11. Add bundles and named_queries for bundle support.
1224
+ * 12. Add document overlays.
1225
+ * 13. Add indexing support.
1234
1226
  */
1235
- const SCHEMA_VERSION = 11;
1227
+ const SCHEMA_VERSION = 12;
1236
1228
  /**
1237
1229
  * Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects.
1238
1230
  */
@@ -1757,9 +1749,7 @@ class DbClientMetadata {
1757
1749
  DbClientMetadata.store = 'clientMetadata';
1758
1750
  /** Keys are automatically assigned via the clientId properties. */
1759
1751
  DbClientMetadata.keyPath = 'clientId';
1760
- /**
1761
- * A object representing a bundle loaded by the SDK.
1762
- */
1752
+ /** An object representing a bundle loaded by the SDK. */
1763
1753
  class DbBundle {
1764
1754
  constructor(
1765
1755
  /** The ID of the loaded bundle. */
@@ -1776,9 +1766,7 @@ class DbBundle {
1776
1766
  /** Name of the IndexedDb object store. */
1777
1767
  DbBundle.store = 'bundles';
1778
1768
  DbBundle.keyPath = 'bundleId';
1779
- /**
1780
- * A object representing a named query loaded by the SDK via a bundle.
1781
- */
1769
+ /** An object representing a named query loaded by the SDK via a bundle. */
1782
1770
  class DbNamedQuery {
1783
1771
  constructor(
1784
1772
  /** The name of the query. */
@@ -1795,6 +1783,156 @@ class DbNamedQuery {
1795
1783
  /** Name of the IndexedDb object store. */
1796
1784
  DbNamedQuery.store = 'namedQueries';
1797
1785
  DbNamedQuery.keyPath = 'name';
1786
+ /** An object representing the global configuration for a field index. */
1787
+ class DbIndexConfiguration {
1788
+ constructor(
1789
+ /**
1790
+ * The index id for this entry. Undefined for indexes that are not yet
1791
+ * persisted.
1792
+ */
1793
+ indexId,
1794
+ /** The collection group this index belongs to. */
1795
+ collectionGroup,
1796
+ /** The fields to index for this index. */
1797
+ fields) {
1798
+ this.indexId = indexId;
1799
+ this.collectionGroup = collectionGroup;
1800
+ this.fields = fields;
1801
+ }
1802
+ }
1803
+ /** Name of the IndexedDb object store. */
1804
+ DbIndexConfiguration.store = 'indexConfiguration';
1805
+ DbIndexConfiguration.keyPath = 'indexId';
1806
+ /**
1807
+ * An index that provides access to the index configurations by collection
1808
+ * group.
1809
+ *
1810
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1811
+ * not possible here as the Web client supports concurrent access to
1812
+ * persistence via multi-tab.
1813
+ */
1814
+ DbIndexConfiguration.collectionGroupIndex = 'collectionGroupIndex';
1815
+ DbIndexConfiguration.collectionGroupIndexPath = 'collectionGroup';
1816
+ /**
1817
+ * An object describing how up-to-date the index backfill is for each user and
1818
+ * index.
1819
+ */
1820
+ class DbIndexState {
1821
+ constructor(
1822
+ /** The index id for this entry. */
1823
+ indexId,
1824
+ /** The user id for this entry. */
1825
+ uid,
1826
+ /**
1827
+ * A number that indicates when the index was last updated (relative to
1828
+ * other indexes).
1829
+ */
1830
+ sequenceNumber,
1831
+ /**
1832
+ * The latest read time that has been indexed by Firestore for this field
1833
+ * index. Set to `{seconds: 0, nanos: 0}` if no documents have been indexed.
1834
+ */
1835
+ readTime,
1836
+ /**
1837
+ * The last document that has been indexed for this field index. Empty if
1838
+ * no documents have been indexed.
1839
+ */
1840
+ documentKey,
1841
+ /**
1842
+ * The largest mutation batch id that has been processed for this index. -1
1843
+ * if no mutations have been indexed.
1844
+ */
1845
+ largestBatchId) {
1846
+ this.indexId = indexId;
1847
+ this.uid = uid;
1848
+ this.sequenceNumber = sequenceNumber;
1849
+ this.readTime = readTime;
1850
+ this.documentKey = documentKey;
1851
+ this.largestBatchId = largestBatchId;
1852
+ }
1853
+ }
1854
+ /** Name of the IndexedDb object store. */
1855
+ DbIndexState.store = 'indexState';
1856
+ DbIndexState.keyPath = ['indexId', 'uid'];
1857
+ /**
1858
+ * An index that provides access to documents in a collection sorted by last
1859
+ * update time. Used by the backfiller.
1860
+ *
1861
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1862
+ * not possible here as the Web client supports concurrent access to
1863
+ * persistence via multi-tab.
1864
+ */
1865
+ DbIndexState.sequenceNumberIndex = 'sequenceNumberIndex';
1866
+ DbIndexState.sequenceNumberIndexPath = ['uid', 'sequenceNumber'];
1867
+ /** An object that stores the encoded entries for all documents and fields. */
1868
+ class DbIndexEntry {
1869
+ constructor(
1870
+ /** The index id for this entry. */
1871
+ indexId,
1872
+ /** The user id for this entry. */
1873
+ uid,
1874
+ /** The encoded array index value for this entry. */
1875
+ arrayValue,
1876
+ /** The encoded directional value for equality and inequality filters. */
1877
+ directionalValue,
1878
+ /** The document key this entry points to. */
1879
+ documentKey) {
1880
+ this.indexId = indexId;
1881
+ this.uid = uid;
1882
+ this.arrayValue = arrayValue;
1883
+ this.directionalValue = directionalValue;
1884
+ this.documentKey = documentKey;
1885
+ }
1886
+ }
1887
+ /** Name of the IndexedDb object store. */
1888
+ DbIndexEntry.store = 'indexEntries';
1889
+ DbIndexEntry.keyPath = [
1890
+ 'indexId',
1891
+ 'uid',
1892
+ 'arrayValue',
1893
+ 'directionalValue',
1894
+ 'documentKey'
1895
+ ];
1896
+ /**
1897
+ * An object representing a document overlay.
1898
+ */
1899
+ class DbDocumentOverlay {
1900
+ constructor(
1901
+ /** The user ID to whom this overlay belongs. */
1902
+ userId,
1903
+ /** The path to the collection that contains the document. */
1904
+ collectionPath,
1905
+ /** The ID (key) of the document within the collection. */
1906
+ documentId,
1907
+ /** The collection group to which the document belongs. */
1908
+ collectionGroup,
1909
+ /** The largest batch ID that's been applied for this overlay. */
1910
+ largestBatchId,
1911
+ /** The overlay mutation. */
1912
+ overlayMutation) {
1913
+ this.userId = userId;
1914
+ this.collectionPath = collectionPath;
1915
+ this.documentId = documentId;
1916
+ this.collectionGroup = collectionGroup;
1917
+ this.largestBatchId = largestBatchId;
1918
+ this.overlayMutation = overlayMutation;
1919
+ }
1920
+ }
1921
+ /** Name of the IndexedDb object store. */
1922
+ DbDocumentOverlay.store = 'documentOverlays';
1923
+ DbDocumentOverlay.keyPath = ['userId', 'collectionPath', 'documentId'];
1924
+ DbDocumentOverlay.collectionPathOverlayIndex = 'collectionPathOverlayIndex';
1925
+ DbDocumentOverlay.collectionPathOverlayIndexPath = [
1926
+ 'userId',
1927
+ 'collectionPath',
1928
+ 'largestBatchId'
1929
+ ];
1930
+ DbDocumentOverlay.collectionGroupOverlayIndex = 'collectionGroupOverlayIndex';
1931
+ DbDocumentOverlay.collectionGroupOverlayIndexPath = [
1932
+ 'userId',
1933
+ 'collectionGroup',
1934
+ 'largestBatchId'
1935
+ ];
1798
1936
  // Visible for testing
1799
1937
  const V1_STORES = [
1800
1938
  DbMutationQueue.store,
@@ -1809,7 +1947,6 @@ const V1_STORES = [
1809
1947
  // V2 is no longer usable (see comment at top of file)
1810
1948
  // Visible for testing
1811
1949
  const V3_STORES = V1_STORES;
1812
- // Visible for testing
1813
1950
  // Note: DbRemoteDocumentChanges is no longer used and dropped with v9.
1814
1951
  const V4_STORES = [...V3_STORES, DbClientMetadata.store];
1815
1952
  // V5 does not change the set of stores.
@@ -1819,12 +1956,28 @@ const V8_STORES = [...V6_STORES, DbCollectionParent.store];
1819
1956
  // V9 does not change the set of stores.
1820
1957
  // V10 does not change the set of stores.
1821
1958
  const V11_STORES = [...V8_STORES, DbBundle.store, DbNamedQuery.store];
1822
- /**
1823
- * The list of all default IndexedDB stores used throughout the SDK. This is
1824
- * used when creating transactions so that access across all stores is done
1825
- * atomically.
1826
- */
1827
- const ALL_STORES = V11_STORES;
1959
+ const V12_STORES = [...V11_STORES, DbDocumentOverlay.store];
1960
+ const V13_STORES = [
1961
+ ...V12_STORES,
1962
+ DbIndexConfiguration.store,
1963
+ DbIndexState.store,
1964
+ DbIndexEntry.store
1965
+ ];
1966
+ /** Returns the object stores for the provided schema. */
1967
+ function getObjectStores(schemaVersion) {
1968
+ if (schemaVersion === 13) {
1969
+ return V13_STORES;
1970
+ }
1971
+ else if (schemaVersion === 12) {
1972
+ return V12_STORES;
1973
+ }
1974
+ else if (schemaVersion === 11) {
1975
+ return V11_STORES;
1976
+ }
1977
+ else {
1978
+ fail();
1979
+ }
1980
+ }
1828
1981
 
1829
1982
  /**
1830
1983
  * @license
@@ -2121,6 +2274,15 @@ class SimpleDbTransaction {
2121
2274
  this.transaction.abort();
2122
2275
  }
2123
2276
  }
2277
+ maybeCommit() {
2278
+ // If the browser supports V3 IndexedDB, we invoke commit() explicitly to
2279
+ // speed up index DB processing if the event loop remains blocks.
2280
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2281
+ const maybeV3IndexedDb = this.transaction;
2282
+ if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {
2283
+ maybeV3IndexedDb.commit();
2284
+ }
2285
+ }
2124
2286
  /**
2125
2287
  * Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
2126
2288
  * operations performed on the SimpleDbStore happen within the context of this
@@ -2317,6 +2479,10 @@ class SimpleDb {
2317
2479
  this.db = await this.ensureDb(action);
2318
2480
  const transaction = SimpleDbTransaction.open(this.db, action, readonly ? 'readonly' : 'readwrite', objectStores);
2319
2481
  const transactionFnResult = transactionFn(transaction)
2482
+ .next(result => {
2483
+ transaction.maybeCommit();
2484
+ return result;
2485
+ })
2320
2486
  .catch(error => {
2321
2487
  // Abort the transaction if there was an error.
2322
2488
  transaction.abort(error);
@@ -2489,13 +2655,29 @@ class SimpleDbStore {
2489
2655
  return wrapRequest(request);
2490
2656
  }
2491
2657
  loadAll(indexOrRange, range) {
2492
- const cursor = this.cursor(this.options(indexOrRange, range));
2493
- const results = [];
2494
- return this.iterateCursor(cursor, (key, value) => {
2495
- results.push(value);
2496
- }).next(() => {
2497
- return results;
2498
- });
2658
+ const iterateOptions = this.options(indexOrRange, range);
2659
+ // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly
2660
+ // 20% faster. Unfortunately, getAll() does not support custom indices.
2661
+ if (!iterateOptions.index && typeof this.store.getAll === 'function') {
2662
+ const request = this.store.getAll(iterateOptions.range);
2663
+ return new PersistencePromise((resolve, reject) => {
2664
+ request.onerror = (event) => {
2665
+ reject(event.target.error);
2666
+ };
2667
+ request.onsuccess = (event) => {
2668
+ resolve(event.target.result);
2669
+ };
2670
+ });
2671
+ }
2672
+ else {
2673
+ const cursor = this.cursor(iterateOptions);
2674
+ const results = [];
2675
+ return this.iterateCursor(cursor, (key, value) => {
2676
+ results.push(value);
2677
+ }).next(() => {
2678
+ return results;
2679
+ });
2680
+ }
2499
2681
  }
2500
2682
  deleteAll(indexOrRange, range) {
2501
2683
  logDebug(LOG_TAG$g, 'DELETE ALL', this.store.name);
@@ -3526,6 +3708,14 @@ class DocumentKey {
3526
3708
  return (this.path.length >= 2 &&
3527
3709
  this.path.get(this.path.length - 2) === collectionId);
3528
3710
  }
3711
+ /** Returns the collection group (i.e. the name of the parent collection) for this key. */
3712
+ getCollectionGroup() {
3713
+ return this.path.get(this.path.length - 2);
3714
+ }
3715
+ /** Returns the fully qualified path to the parent collection. */
3716
+ getCollectionPath() {
3717
+ return this.path.popLast();
3718
+ }
3529
3719
  isEqual(other) {
3530
3720
  return (other !== null && ResourcePath.comparator(this.path, other.path) === 0);
3531
3721
  }
@@ -4349,12 +4539,12 @@ class FieldIndex {
4349
4539
  /** The collection ID this index applies to. */
4350
4540
  collectionGroup,
4351
4541
  /** The field segments for this index. */
4352
- segments,
4542
+ fields,
4353
4543
  /** Shows how up-to-date the index is for the current user. */
4354
4544
  indexState) {
4355
4545
  this.indexId = indexId;
4356
4546
  this.collectionGroup = collectionGroup;
4357
- this.segments = segments;
4547
+ this.fields = fields;
4358
4548
  this.indexState = indexState;
4359
4549
  }
4360
4550
  }
@@ -4464,27 +4654,29 @@ function newTarget(path, collectionGroup = null, orderBy = [], filters = [], lim
4464
4654
  function canonifyTarget(target) {
4465
4655
  const targetImpl = debugCast(target);
4466
4656
  if (targetImpl.memoizedCanonicalId === null) {
4467
- let canonicalId = targetImpl.path.canonicalString();
4657
+ let str = targetImpl.path.canonicalString();
4468
4658
  if (targetImpl.collectionGroup !== null) {
4469
- canonicalId += '|cg:' + targetImpl.collectionGroup;
4659
+ str += '|cg:' + targetImpl.collectionGroup;
4470
4660
  }
4471
- canonicalId += '|f:';
4472
- canonicalId += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4473
- canonicalId += '|ob:';
4474
- canonicalId += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4661
+ str += '|f:';
4662
+ str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4663
+ str += '|ob:';
4664
+ str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4475
4665
  if (!isNullOrUndefined(targetImpl.limit)) {
4476
- canonicalId += '|l:';
4477
- canonicalId += targetImpl.limit;
4666
+ str += '|l:';
4667
+ str += targetImpl.limit;
4478
4668
  }
4479
4669
  if (targetImpl.startAt) {
4480
- canonicalId += '|lb:';
4481
- canonicalId += canonifyBound(targetImpl.startAt);
4670
+ str += '|lb:';
4671
+ str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
4672
+ str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
4482
4673
  }
4483
4674
  if (targetImpl.endAt) {
4484
- canonicalId += '|ub:';
4485
- canonicalId += canonifyBound(targetImpl.endAt);
4675
+ str += '|ub:';
4676
+ str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
4677
+ str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
4486
4678
  }
4487
- targetImpl.memoizedCanonicalId = canonicalId;
4679
+ targetImpl.memoizedCanonicalId = str;
4488
4680
  }
4489
4681
  return targetImpl.memoizedCanonicalId;
4490
4682
  }
@@ -4507,10 +4699,14 @@ function stringifyTarget(target) {
4507
4699
  .join(', ')}]`;
4508
4700
  }
4509
4701
  if (target.startAt) {
4510
- str += ', startAt: ' + canonifyBound(target.startAt);
4702
+ str += ', startAt: ';
4703
+ str += target.startAt.inclusive ? 'b:' : 'a:';
4704
+ str += target.startAt.position.map(p => canonicalId(p)).join(',');
4511
4705
  }
4512
4706
  if (target.endAt) {
4513
- str += ', endAt: ' + canonifyBound(target.endAt);
4707
+ str += ', endAt: ';
4708
+ str += target.endAt.inclusive ? 'a:' : 'b:';
4709
+ str += target.endAt.position.map(p => canonicalId(p)).join(',');
4514
4710
  }
4515
4711
  return `Target(${str})`;
4516
4712
  }
@@ -4733,7 +4929,6 @@ class ArrayContainsAnyFilter extends FieldFilter {
4733
4929
  return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
4734
4930
  }
4735
4931
  }
4736
- // TODO(indexing): Change Bound.before to "inclusive"
4737
4932
  /**
4738
4933
  * Represents a bound of a query.
4739
4934
  *
@@ -4749,17 +4944,11 @@ class ArrayContainsAnyFilter extends FieldFilter {
4749
4944
  * just after the provided values.
4750
4945
  */
4751
4946
  class Bound {
4752
- constructor(position, before) {
4947
+ constructor(position, inclusive) {
4753
4948
  this.position = position;
4754
- this.before = before;
4949
+ this.inclusive = inclusive;
4755
4950
  }
4756
4951
  }
4757
- function canonifyBound(bound) {
4758
- // TODO(b/29183165): Make this collision robust.
4759
- return `${bound.before ? 'b' : 'a'}:${bound.position
4760
- .map(p => canonicalId(p))
4761
- .join(',')}`;
4762
- }
4763
4952
  /**
4764
4953
  * An ordering on a field, in some Direction. Direction defaults to ASCENDING.
4765
4954
  */
@@ -4779,11 +4968,7 @@ function stringifyOrderBy(orderBy) {
4779
4968
  function orderByEquals(left, right) {
4780
4969
  return left.dir === right.dir && left.field.isEqual(right.field);
4781
4970
  }
4782
- /**
4783
- * Returns true if a document sorts before a bound using the provided sort
4784
- * order.
4785
- */
4786
- function sortsBeforeDocument(bound, orderBy, doc) {
4971
+ function boundCompareToDocument(bound, orderBy, doc) {
4787
4972
  let comparison = 0;
4788
4973
  for (let i = 0; i < bound.position.length; i++) {
4789
4974
  const orderByComponent = orderBy[i];
@@ -4802,7 +4987,23 @@ function sortsBeforeDocument(bound, orderBy, doc) {
4802
4987
  break;
4803
4988
  }
4804
4989
  }
4805
- return bound.before ? comparison <= 0 : comparison < 0;
4990
+ return comparison;
4991
+ }
4992
+ /**
4993
+ * Returns true if a document sorts after a bound using the provided sort
4994
+ * order.
4995
+ */
4996
+ function boundSortsAfterDocument(bound, orderBy, doc) {
4997
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4998
+ return bound.inclusive ? comparison >= 0 : comparison > 0;
4999
+ }
5000
+ /**
5001
+ * Returns true if a document sorts before a bound using the provided sort
5002
+ * order.
5003
+ */
5004
+ function boundSortsBeforeDocument(bound, orderBy, doc) {
5005
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
5006
+ return bound.inclusive ? comparison <= 0 : comparison < 0;
4806
5007
  }
4807
5008
  function boundEquals(left, right) {
4808
5009
  if (left === null) {
@@ -4811,7 +5012,7 @@ function boundEquals(left, right) {
4811
5012
  else if (right === null) {
4812
5013
  return false;
4813
5014
  }
4814
- if (left.before !== right.before ||
5015
+ if (left.inclusive !== right.inclusive ||
4815
5016
  left.position.length !== right.position.length) {
4816
5017
  return false;
4817
5018
  }
@@ -5015,10 +5216,10 @@ function queryToTarget(query) {
5015
5216
  }
5016
5217
  // We need to swap the cursors to match the now-flipped query ordering.
5017
5218
  const startAt = queryImpl.endAt
5018
- ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.before)
5219
+ ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
5019
5220
  : null;
5020
5221
  const endAt = queryImpl.startAt
5021
- ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.before)
5222
+ ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
5022
5223
  : null;
5023
5224
  // Now return as a LimitType.First query.
5024
5225
  queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
@@ -5106,11 +5307,11 @@ function queryMatchesFilters(query, doc) {
5106
5307
  /** Makes sure a document is within the bounds, if provided. */
5107
5308
  function queryMatchesBounds(query, doc) {
5108
5309
  if (query.startAt &&
5109
- !sortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5310
+ !boundSortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5110
5311
  return false;
5111
5312
  }
5112
5313
  if (query.endAt &&
5113
- sortsBeforeDocument(query.endAt, queryOrderBy(query), doc)) {
5314
+ !boundSortsAfterDocument(query.endAt, queryOrderBy(query), doc)) {
5114
5315
  return false;
5115
5316
  }
5116
5317
  return true;
@@ -6603,6 +6804,47 @@ class MutationBatchResult {
6603
6804
  }
6604
6805
  }
6605
6806
 
6807
+ /**
6808
+ * @license
6809
+ * Copyright 2022 Google LLC
6810
+ *
6811
+ * Licensed under the Apache License, Version 2.0 (the "License");
6812
+ * you may not use this file except in compliance with the License.
6813
+ * You may obtain a copy of the License at
6814
+ *
6815
+ * http://www.apache.org/licenses/LICENSE-2.0
6816
+ *
6817
+ * Unless required by applicable law or agreed to in writing, software
6818
+ * distributed under the License is distributed on an "AS IS" BASIS,
6819
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6820
+ * See the License for the specific language governing permissions and
6821
+ * limitations under the License.
6822
+ */
6823
+ /**
6824
+ * Representation of an overlay computed by Firestore.
6825
+ *
6826
+ * Holds information about a mutation and the largest batch id in Firestore when
6827
+ * the mutation was created.
6828
+ */
6829
+ class Overlay {
6830
+ constructor(largestBatchId, mutation) {
6831
+ this.largestBatchId = largestBatchId;
6832
+ this.mutation = mutation;
6833
+ }
6834
+ getKey() {
6835
+ return this.mutation.key;
6836
+ }
6837
+ isEqual(other) {
6838
+ return other !== null && this.mutation === other.mutation;
6839
+ }
6840
+ toString() {
6841
+ return `Overlay{
6842
+ largestBatchId: ${this.largestBatchId},
6843
+ mutation: ${this.mutation.toString()}
6844
+ }`;
6845
+ }
6846
+ }
6847
+
6606
6848
  /**
6607
6849
  * @license
6608
6850
  * Copyright 2017 Google LLC
@@ -7989,10 +8231,10 @@ function toQueryTarget(serializer, target) {
7989
8231
  result.structuredQuery.limit = limit;
7990
8232
  }
7991
8233
  if (target.startAt) {
7992
- result.structuredQuery.startAt = toCursor(target.startAt);
8234
+ result.structuredQuery.startAt = toStartAtCursor(target.startAt);
7993
8235
  }
7994
8236
  if (target.endAt) {
7995
- result.structuredQuery.endAt = toCursor(target.endAt);
8237
+ result.structuredQuery.endAt = toEndAtCursor(target.endAt);
7996
8238
  }
7997
8239
  return result;
7998
8240
  }
@@ -8025,11 +8267,11 @@ function convertQueryTargetToQuery(target) {
8025
8267
  }
8026
8268
  let startAt = null;
8027
8269
  if (query.startAt) {
8028
- startAt = fromCursor(query.startAt);
8270
+ startAt = fromStartAtCursor(query.startAt);
8029
8271
  }
8030
8272
  let endAt = null;
8031
8273
  if (query.endAt) {
8032
- endAt = fromCursor(query.endAt);
8274
+ endAt = fromEndAtCursor(query.endAt);
8033
8275
  }
8034
8276
  return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
8035
8277
  }
@@ -8120,16 +8362,27 @@ function toOrder(orderBys) {
8120
8362
  function fromOrder(orderBys) {
8121
8363
  return orderBys.map(order => fromPropertyOrder(order));
8122
8364
  }
8123
- function toCursor(cursor) {
8365
+ function toStartAtCursor(cursor) {
8366
+ return {
8367
+ before: cursor.inclusive,
8368
+ values: cursor.position
8369
+ };
8370
+ }
8371
+ function toEndAtCursor(cursor) {
8124
8372
  return {
8125
- before: cursor.before,
8373
+ before: !cursor.inclusive,
8126
8374
  values: cursor.position
8127
8375
  };
8128
8376
  }
8129
- function fromCursor(cursor) {
8130
- const before = !!cursor.before;
8377
+ function fromStartAtCursor(cursor) {
8378
+ const inclusive = !!cursor.before;
8131
8379
  const position = cursor.values || [];
8132
- return new Bound(position, before);
8380
+ return new Bound(position, inclusive);
8381
+ }
8382
+ function fromEndAtCursor(cursor) {
8383
+ const inclusive = !cursor.before;
8384
+ const position = cursor.values || [];
8385
+ return new Bound(position, inclusive);
8133
8386
  }
8134
8387
  // visible for testing
8135
8388
  function toDirection(dir) {
@@ -8593,6 +8846,37 @@ function fromBundleMetadata(metadata) {
8593
8846
  version: metadata.version,
8594
8847
  createTime: fromVersion(metadata.createTime)
8595
8848
  };
8849
+ }
8850
+ /** Encodes a DbDocumentOverlay object to an Overlay model object. */
8851
+ function fromDbDocumentOverlay(localSerializer, dbDocumentOverlay) {
8852
+ return new Overlay(dbDocumentOverlay.largestBatchId, fromMutation(localSerializer.remoteSerializer, dbDocumentOverlay.overlayMutation));
8853
+ }
8854
+ /** Decodes an Overlay model object into a DbDocumentOverlay object. */
8855
+ function toDbDocumentOverlay(localSerializer, userId, overlay) {
8856
+ const [_, collectionPath, documentId] = toDbDocumentOverlayKey(userId, overlay.mutation.key);
8857
+ return new DbDocumentOverlay(userId, collectionPath, documentId, overlay.mutation.key.getCollectionGroup(), overlay.largestBatchId, toMutation(localSerializer.remoteSerializer, overlay.mutation));
8858
+ }
8859
+ /**
8860
+ * Returns the DbDocumentOverlayKey corresponding to the given user and
8861
+ * document key.
8862
+ */
8863
+ function toDbDocumentOverlayKey(userId, docKey) {
8864
+ const docId = docKey.path.lastSegment();
8865
+ const collectionPath = encodeResourcePath(docKey.path.popLast());
8866
+ return [userId, collectionPath, docId];
8867
+ }
8868
+ function toDbIndexConfiguration(index) {
8869
+ return new DbIndexConfiguration(index.indexId, index.collectionGroup, index.fields.map(s => [s.fieldPath.canonicalString(), s.kind]));
8870
+ }
8871
+ function fromDbIndexConfiguration(index, state) {
8872
+ const decodedState = state
8873
+ ? new IndexState(state.sequenceNumber, new IndexOffset(fromDbTimestamp(state.readTime), new DocumentKey(decodeResourcePath(state.documentKey)), state.largestBatchId))
8874
+ : IndexState.empty();
8875
+ const decodedSegments = index.fields.map(([fieldPath, kind]) => new IndexSegment(FieldPath$1.fromServerFormat(fieldPath), kind));
8876
+ return new FieldIndex(index.indexId, index.collectionGroup, decodedSegments, decodedState);
8877
+ }
8878
+ function toDbIndexState(indexId, user, sequenceNumber, offset) {
8879
+ return new DbIndexState(indexId, user.uid || '', sequenceNumber, toDbTimestamp(offset.readTime), encodeResourcePath(offset.documentKey.path), offset.largestBatchId);
8596
8880
  }
8597
8881
 
8598
8882
  /**
@@ -8652,6 +8936,125 @@ function namedQueriesStore(txn) {
8652
8936
  return getStore(txn, DbNamedQuery.store);
8653
8937
  }
8654
8938
 
8939
+ /**
8940
+ * @license
8941
+ * Copyright 2022 Google LLC
8942
+ *
8943
+ * Licensed under the Apache License, Version 2.0 (the "License");
8944
+ * you may not use this file except in compliance with the License.
8945
+ * You may obtain a copy of the License at
8946
+ *
8947
+ * http://www.apache.org/licenses/LICENSE-2.0
8948
+ *
8949
+ * Unless required by applicable law or agreed to in writing, software
8950
+ * distributed under the License is distributed on an "AS IS" BASIS,
8951
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8952
+ * See the License for the specific language governing permissions and
8953
+ * limitations under the License.
8954
+ */
8955
+ /**
8956
+ * Implementation of DocumentOverlayCache using IndexedDb.
8957
+ */
8958
+ class IndexedDbDocumentOverlayCache {
8959
+ /**
8960
+ * @param serializer - The document serializer.
8961
+ * @param userId - The userId for which we are accessing overlays.
8962
+ */
8963
+ constructor(serializer, userId) {
8964
+ this.serializer = serializer;
8965
+ this.userId = userId;
8966
+ }
8967
+ static forUser(serializer, user) {
8968
+ const userId = user.uid || '';
8969
+ return new IndexedDbDocumentOverlayCache(serializer, userId);
8970
+ }
8971
+ getOverlay(transaction, key) {
8972
+ return documentOverlayStore(transaction)
8973
+ .get(toDbDocumentOverlayKey(this.userId, key))
8974
+ .next(dbOverlay => {
8975
+ if (dbOverlay) {
8976
+ return fromDbDocumentOverlay(this.serializer, dbOverlay);
8977
+ }
8978
+ return null;
8979
+ });
8980
+ }
8981
+ saveOverlays(transaction, largestBatchId, overlays) {
8982
+ const promises = [];
8983
+ overlays.forEach(mutation => {
8984
+ const overlay = new Overlay(largestBatchId, mutation);
8985
+ promises.push(this.saveOverlay(transaction, overlay));
8986
+ });
8987
+ return PersistencePromise.waitFor(promises);
8988
+ }
8989
+ removeOverlaysForBatchId(transaction, documentKeys, batchId) {
8990
+ const collectionPaths = new Set();
8991
+ // Get the set of unique collection paths.
8992
+ documentKeys.forEach(key => collectionPaths.add(encodeResourcePath(key.getCollectionPath())));
8993
+ const promises = [];
8994
+ collectionPaths.forEach(collectionPath => {
8995
+ const range = IDBKeyRange.bound([this.userId, collectionPath, batchId], [this.userId, collectionPath, batchId + 1],
8996
+ /*lowerOpen=*/ false,
8997
+ /*upperOpen=*/ true);
8998
+ promises.push(documentOverlayStore(transaction).deleteAll(DbDocumentOverlay.collectionPathOverlayIndex, range));
8999
+ });
9000
+ return PersistencePromise.waitFor(promises);
9001
+ }
9002
+ getOverlaysForCollection(transaction, collection, sinceBatchId) {
9003
+ const result = new Map();
9004
+ const collectionPath = encodeResourcePath(collection);
9005
+ // We want batch IDs larger than `sinceBatchId`, and so the lower bound
9006
+ // is not inclusive.
9007
+ const range = IDBKeyRange.bound([this.userId, collectionPath, sinceBatchId], [this.userId, collectionPath, Number.POSITIVE_INFINITY],
9008
+ /*lowerOpen=*/ true);
9009
+ return documentOverlayStore(transaction)
9010
+ .loadAll(DbDocumentOverlay.collectionPathOverlayIndex, range)
9011
+ .next(dbOverlays => {
9012
+ for (const dbOverlay of dbOverlays) {
9013
+ const overlay = fromDbDocumentOverlay(this.serializer, dbOverlay);
9014
+ result.set(overlay.getKey(), overlay);
9015
+ }
9016
+ return result;
9017
+ });
9018
+ }
9019
+ getOverlaysForCollectionGroup(transaction, collectionGroup, sinceBatchId, count) {
9020
+ const result = new Map();
9021
+ let currentBatchId = undefined;
9022
+ // We want batch IDs larger than `sinceBatchId`, and so the lower bound
9023
+ // is not inclusive.
9024
+ const range = IDBKeyRange.bound([this.userId, collectionGroup, sinceBatchId], [this.userId, collectionGroup, Number.POSITIVE_INFINITY],
9025
+ /*lowerOpen=*/ true);
9026
+ return documentOverlayStore(transaction)
9027
+ .iterate({
9028
+ index: DbDocumentOverlay.collectionGroupOverlayIndex,
9029
+ range
9030
+ }, (_, dbOverlay, control) => {
9031
+ // We do not want to return partial batch overlays, even if the size
9032
+ // of the result set exceeds the given `count` argument. Therefore, we
9033
+ // continue to aggregate results even after the result size exceeds
9034
+ // `count` if there are more overlays from the `currentBatchId`.
9035
+ const overlay = fromDbDocumentOverlay(this.serializer, dbOverlay);
9036
+ if (result.size < count ||
9037
+ overlay.largestBatchId === currentBatchId) {
9038
+ result.set(overlay.getKey(), overlay);
9039
+ currentBatchId = overlay.largestBatchId;
9040
+ }
9041
+ else {
9042
+ control.done();
9043
+ }
9044
+ })
9045
+ .next(() => result);
9046
+ }
9047
+ saveOverlay(transaction, overlay) {
9048
+ return documentOverlayStore(transaction).put(toDbDocumentOverlay(this.serializer, this.userId, overlay));
9049
+ }
9050
+ }
9051
+ /**
9052
+ * Helper to get a typed SimpleDbStore for the document overlay object store.
9053
+ */
9054
+ function documentOverlayStore(txn) {
9055
+ return getStore(txn, DbDocumentOverlay.store);
9056
+ }
9057
+
8655
9058
  /**
8656
9059
  * @license
8657
9060
  * Copyright 2019 Google LLC
@@ -8682,6 +9085,38 @@ class MemoryIndexManager {
8682
9085
  getCollectionParents(transaction, collectionId) {
8683
9086
  return PersistencePromise.resolve(this.collectionParentIndex.getEntries(collectionId));
8684
9087
  }
9088
+ addFieldIndex(transaction, index) {
9089
+ // Field indices are not supported with memory persistence.
9090
+ return PersistencePromise.resolve();
9091
+ }
9092
+ deleteFieldIndex(transaction, index) {
9093
+ // Field indices are not supported with memory persistence.
9094
+ return PersistencePromise.resolve();
9095
+ }
9096
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9097
+ // Field indices are not supported with memory persistence.
9098
+ return PersistencePromise.resolve(documentKeySet());
9099
+ }
9100
+ getFieldIndex(transaction, target) {
9101
+ // Field indices are not supported with memory persistence.
9102
+ return PersistencePromise.resolve(null);
9103
+ }
9104
+ getFieldIndexes(transaction, collectionGroup) {
9105
+ // Field indices are not supported with memory persistence.
9106
+ return PersistencePromise.resolve([]);
9107
+ }
9108
+ getNextCollectionGroupToUpdate(transaction) {
9109
+ // Field indices are not supported with memory persistence.
9110
+ return PersistencePromise.resolve(null);
9111
+ }
9112
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9113
+ // Field indices are not supported with memory persistence.
9114
+ return PersistencePromise.resolve();
9115
+ }
9116
+ updateIndexEntries(transaction, documents) {
9117
+ // Field indices are not supported with memory persistence.
9118
+ return PersistencePromise.resolve();
9119
+ }
8685
9120
  }
8686
9121
  /**
8687
9122
  * Internal implementation of the collection-parent index exposed by MemoryIndexManager.
@@ -8733,17 +9168,22 @@ class MemoryCollectionParentIndex {
8733
9168
  */
8734
9169
  /**
8735
9170
  * A persisted implementation of IndexManager.
9171
+ *
9172
+ * PORTING NOTE: Unlike iOS and Android, the Web SDK does not memoize index
9173
+ * data as it supports multi-tab access.
8736
9174
  */
8737
9175
  class IndexedDbIndexManager {
8738
- constructor() {
9176
+ constructor(user) {
9177
+ this.user = user;
8739
9178
  /**
8740
9179
  * An in-memory copy of the index entries we've already written since the SDK
8741
9180
  * launched. Used to avoid re-writing the same entry repeatedly.
8742
9181
  *
8743
- * This is *NOT* a complete cache of what's in persistence and so can never be used to
8744
- * satisfy reads.
9182
+ * This is *NOT* a complete cache of what's in persistence and so can never be
9183
+ * used to satisfy reads.
8745
9184
  */
8746
9185
  this.collectionParentsCache = new MemoryCollectionParentIndex();
9186
+ this.uid = user.uid || '';
8747
9187
  }
8748
9188
  /**
8749
9189
  * Adds a new entry to the collection parent index.
@@ -8790,6 +9230,85 @@ class IndexedDbIndexManager {
8790
9230
  return parentPaths;
8791
9231
  });
8792
9232
  }
9233
+ addFieldIndex(transaction, index) {
9234
+ // TODO(indexing): Verify that the auto-incrementing index ID works in
9235
+ // Safari & Firefox.
9236
+ const indexes = indexConfigurationStore(transaction);
9237
+ const dbIndex = toDbIndexConfiguration(index);
9238
+ delete dbIndex.indexId; // `indexId` is auto-populated by IndexedDb
9239
+ return indexes.add(dbIndex).next();
9240
+ }
9241
+ deleteFieldIndex(transaction, index) {
9242
+ const indexes = indexConfigurationStore(transaction);
9243
+ const states = indexStateStore(transaction);
9244
+ const entries = indexEntriesStore(transaction);
9245
+ return indexes
9246
+ .delete(index.indexId)
9247
+ .next(() => states.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9248
+ /*lowerOpen=*/ false,
9249
+ /*upperOpen=*/ true)))
9250
+ .next(() => entries.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9251
+ /*lowerOpen=*/ false,
9252
+ /*upperOpen=*/ true)));
9253
+ }
9254
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9255
+ // TODO(indexing): Implement
9256
+ return PersistencePromise.resolve(documentKeySet());
9257
+ }
9258
+ getFieldIndex(transaction, target) {
9259
+ // TODO(indexing): Implement
9260
+ return PersistencePromise.resolve(null);
9261
+ }
9262
+ getFieldIndexes(transaction, collectionGroup) {
9263
+ const indexes = indexConfigurationStore(transaction);
9264
+ const states = indexStateStore(transaction);
9265
+ return (collectionGroup
9266
+ ? indexes.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9267
+ : indexes.loadAll()).next(indexConfigs => {
9268
+ const result = [];
9269
+ return PersistencePromise.forEach(indexConfigs, (indexConfig) => {
9270
+ return states
9271
+ .get([indexConfig.indexId, this.uid])
9272
+ .next(indexState => {
9273
+ result.push(fromDbIndexConfiguration(indexConfig, indexState));
9274
+ });
9275
+ }).next(() => result);
9276
+ });
9277
+ }
9278
+ getNextCollectionGroupToUpdate(transaction) {
9279
+ return this.getFieldIndexes(transaction).next(indexes => {
9280
+ if (indexes.length === 0) {
9281
+ return null;
9282
+ }
9283
+ indexes.sort((l, r) => l.indexState.sequenceNumber - r.indexState.sequenceNumber);
9284
+ return indexes[0].collectionGroup;
9285
+ });
9286
+ }
9287
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9288
+ const indexes = indexConfigurationStore(transaction);
9289
+ const states = indexStateStore(transaction);
9290
+ return this.getNextSequenceNumber(transaction).next(nextSequenceNumber => indexes
9291
+ .loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9292
+ .next(configs => PersistencePromise.forEach(configs, (config) => states.put(toDbIndexState(config.indexId, this.user, nextSequenceNumber, offset)))));
9293
+ }
9294
+ updateIndexEntries(transaction, documents) {
9295
+ // TODO(indexing): Implement
9296
+ return PersistencePromise.resolve();
9297
+ }
9298
+ getNextSequenceNumber(transaction) {
9299
+ let nextSequenceNumber = 1;
9300
+ const states = indexStateStore(transaction);
9301
+ return states
9302
+ .iterate({
9303
+ index: DbIndexState.sequenceNumberIndex,
9304
+ reverse: true,
9305
+ range: IDBKeyRange.upperBound([this.uid, Number.MAX_SAFE_INTEGER])
9306
+ }, (_, state, controller) => {
9307
+ controller.done();
9308
+ nextSequenceNumber = state.sequenceNumber + 1;
9309
+ })
9310
+ .next(() => nextSequenceNumber);
9311
+ }
8793
9312
  }
8794
9313
  /**
8795
9314
  * Helper to get a typed SimpleDbStore for the collectionParents
@@ -8797,6 +9316,24 @@ class IndexedDbIndexManager {
8797
9316
  */
8798
9317
  function collectionParentsStore(txn) {
8799
9318
  return getStore(txn, DbCollectionParent.store);
9319
+ }
9320
+ /**
9321
+ * Helper to get a typed SimpleDbStore for the index entry object store.
9322
+ */
9323
+ function indexEntriesStore(txn) {
9324
+ return getStore(txn, DbIndexEntry.store);
9325
+ }
9326
+ /**
9327
+ * Helper to get a typed SimpleDbStore for the index configuration object store.
9328
+ */
9329
+ function indexConfigurationStore(txn) {
9330
+ return getStore(txn, DbIndexConfiguration.store);
9331
+ }
9332
+ /**
9333
+ * Helper to get a typed SimpleDbStore for the index state object store.
9334
+ */
9335
+ function indexStateStore(txn) {
9336
+ return getStore(txn, DbIndexState.store);
8800
9337
  }
8801
9338
 
8802
9339
  /**
@@ -10266,12 +10803,10 @@ class RemoteDocumentChangeBuffer {
10266
10803
  * `newIndexedDbRemoteDocumentCache()`.
10267
10804
  */
10268
10805
  class IndexedDbRemoteDocumentCacheImpl {
10269
- /**
10270
- * @param serializer - The document serializer.
10271
- * @param indexManager - The query indexes that need to be maintained.
10272
- */
10273
- constructor(serializer, indexManager) {
10806
+ constructor(serializer) {
10274
10807
  this.serializer = serializer;
10808
+ }
10809
+ setIndexManager(indexManager) {
10275
10810
  this.indexManager = indexManager;
10276
10811
  }
10277
10812
  /**
@@ -10393,21 +10928,21 @@ class IndexedDbRemoteDocumentCacheImpl {
10393
10928
  }
10394
10929
  });
10395
10930
  }
10396
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
10931
+ getAll(transaction, collection, sinceReadTime) {
10397
10932
  let results = mutableDocumentMap();
10398
- const immediateChildrenPathLength = query.path.length + 1;
10933
+ const immediateChildrenPathLength = collection.length + 1;
10399
10934
  const iterationOptions = {};
10400
10935
  if (sinceReadTime.isEqual(SnapshotVersion.min())) {
10401
10936
  // Documents are ordered by key, so we can use a prefix scan to narrow
10402
10937
  // down the documents we need to match the query against.
10403
- const startKey = query.path.toArray();
10938
+ const startKey = collection.toArray();
10404
10939
  iterationOptions.range = IDBKeyRange.lowerBound(startKey);
10405
10940
  }
10406
10941
  else {
10407
10942
  // Execute an index-free query and filter by read time. This is safe
10408
10943
  // since all document changes to queries that have a
10409
10944
  // lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read time set.
10410
- const collectionKey = query.path.toArray();
10945
+ const collectionKey = collection.toArray();
10411
10946
  const readTimeKey = toDbTimestampKey(sinceReadTime);
10412
10947
  iterationOptions.range = IDBKeyRange.lowerBound([collectionKey, readTimeKey],
10413
10948
  /* open= */ true);
@@ -10424,12 +10959,12 @@ class IndexedDbRemoteDocumentCacheImpl {
10424
10959
  return;
10425
10960
  }
10426
10961
  const document = this.maybeDecodeDocument(DocumentKey.fromSegments(key), dbRemoteDoc);
10427
- if (!query.path.isPrefixOf(document.key.path)) {
10428
- control.done();
10429
- }
10430
- else if (queryMatches(query, document)) {
10962
+ if (collection.isPrefixOf(document.key.path)) {
10431
10963
  results = results.insert(document.key, document);
10432
10964
  }
10965
+ else {
10966
+ control.done();
10967
+ }
10433
10968
  })
10434
10969
  .next(() => results);
10435
10970
  }
@@ -10467,14 +11002,9 @@ class IndexedDbRemoteDocumentCacheImpl {
10467
11002
  return MutableDocument.newInvalidDocument(documentKey);
10468
11003
  }
10469
11004
  }
10470
- /**
10471
- * Creates a new IndexedDbRemoteDocumentCache.
10472
- *
10473
- * @param serializer - The document serializer.
10474
- * @param indexManager - The query indexes that need to be maintained.
10475
- */
10476
- function newIndexedDbRemoteDocumentCache(serializer, indexManager) {
10477
- return new IndexedDbRemoteDocumentCacheImpl(serializer, indexManager);
11005
+ /** Creates a new IndexedDbRemoteDocumentCache. */
11006
+ function newIndexedDbRemoteDocumentCache(serializer) {
11007
+ return new IndexedDbRemoteDocumentCacheImpl(serializer);
10478
11008
  }
10479
11009
  /**
10480
11010
  * Returns the set of documents that have changed since the specified read
@@ -10641,9 +11171,6 @@ class SchemaConverter {
10641
11171
  * and local feature development.
10642
11172
  */
10643
11173
  createOrUpgrade(db, txn, fromVersion, toVersion) {
10644
- hardAssert(fromVersion < toVersion &&
10645
- fromVersion >= 0 &&
10646
- toVersion <= SCHEMA_VERSION);
10647
11174
  const simpleDbTransaction = new SimpleDbTransaction('createOrUpgrade', txn);
10648
11175
  if (fromVersion < 1 && toVersion >= 1) {
10649
11176
  createPrimaryClientStore(db);
@@ -10710,6 +11237,16 @@ class SchemaConverter {
10710
11237
  createNamedQueriesStore(db);
10711
11238
  });
10712
11239
  }
11240
+ if (fromVersion < 12 && toVersion >= 12) {
11241
+ p = p.next(() => {
11242
+ createDocumentOverlayStore(db);
11243
+ });
11244
+ }
11245
+ if (fromVersion < 13 && toVersion >= 13) {
11246
+ p = p.next(() => {
11247
+ createFieldIndex(db);
11248
+ });
11249
+ }
10713
11250
  return p;
10714
11251
  }
10715
11252
  addDocumentGlobal(txn) {
@@ -10916,6 +11453,27 @@ function createNamedQueriesStore(db) {
10916
11453
  db.createObjectStore(DbNamedQuery.store, {
10917
11454
  keyPath: DbNamedQuery.keyPath
10918
11455
  });
11456
+ }
11457
+ function createFieldIndex(db) {
11458
+ const indexConfiguratioStore = db.createObjectStore(DbIndexConfiguration.store, {
11459
+ keyPath: DbIndexConfiguration.keyPath,
11460
+ autoIncrement: true
11461
+ });
11462
+ indexConfiguratioStore.createIndex(DbIndexConfiguration.collectionGroupIndex, DbIndexConfiguration.collectionGroupIndexPath, { unique: false });
11463
+ const indexStateStore = db.createObjectStore(DbIndexState.store, {
11464
+ keyPath: DbIndexState.keyPath
11465
+ });
11466
+ indexStateStore.createIndex(DbIndexState.sequenceNumberIndex, DbIndexState.sequenceNumberIndexPath, { unique: false });
11467
+ db.createObjectStore(DbIndexEntry.store, {
11468
+ keyPath: DbIndexEntry.keyPath
11469
+ });
11470
+ }
11471
+ function createDocumentOverlayStore(db) {
11472
+ const documentOverlayStore = db.createObjectStore(DbDocumentOverlay.store, {
11473
+ keyPath: DbDocumentOverlay.keyPath
11474
+ });
11475
+ documentOverlayStore.createIndex(DbDocumentOverlay.collectionPathOverlayIndex, DbDocumentOverlay.collectionPathOverlayIndexPath, { unique: false });
11476
+ documentOverlayStore.createIndex(DbDocumentOverlay.collectionGroupOverlayIndex, DbDocumentOverlay.collectionGroupOverlayIndexPath, { unique: false });
10919
11477
  }
10920
11478
 
10921
11479
  /**
@@ -11027,7 +11585,7 @@ class IndexedDbPersistence {
11027
11585
  * If set to true, forcefully obtains database access. Existing tabs will
11028
11586
  * no longer be able to access IndexedDB.
11029
11587
  */
11030
- forceOwningTab) {
11588
+ forceOwningTab, schemaVersion = SCHEMA_VERSION) {
11031
11589
  this.allowTabSynchronization = allowTabSynchronization;
11032
11590
  this.persistenceKey = persistenceKey;
11033
11591
  this.clientId = clientId;
@@ -11036,6 +11594,7 @@ class IndexedDbPersistence {
11036
11594
  this.document = document;
11037
11595
  this.sequenceNumberSyncer = sequenceNumberSyncer;
11038
11596
  this.forceOwningTab = forceOwningTab;
11597
+ this.schemaVersion = schemaVersion;
11039
11598
  this.listenSequence = null;
11040
11599
  this._started = false;
11041
11600
  this.isPrimary = false;
@@ -11057,10 +11616,9 @@ class IndexedDbPersistence {
11057
11616
  this.referenceDelegate = new IndexedDbLruDelegateImpl(this, lruParams);
11058
11617
  this.dbName = persistenceKey + MAIN_DATABASE;
11059
11618
  this.serializer = new LocalSerializer(serializer);
11060
- this.simpleDb = new SimpleDb(this.dbName, SCHEMA_VERSION, new SchemaConverter(this.serializer));
11619
+ this.simpleDb = new SimpleDb(this.dbName, this.schemaVersion, new SchemaConverter(this.serializer));
11061
11620
  this.targetCache = new IndexedDbTargetCache(this.referenceDelegate, this.serializer);
11062
- this.indexManager = new IndexedDbIndexManager();
11063
- this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer, this.indexManager);
11621
+ this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer);
11064
11622
  this.bundleCache = new IndexedDbBundleCache();
11065
11623
  if (this.window && this.window.localStorage) {
11066
11624
  this.webStorage = this.window.localStorage;
@@ -11396,8 +11954,8 @@ class IndexedDbPersistence {
11396
11954
  get started() {
11397
11955
  return this._started;
11398
11956
  }
11399
- getMutationQueue(user) {
11400
- return IndexedDbMutationQueue.forUser(user, this.serializer, this.indexManager, this.referenceDelegate);
11957
+ getMutationQueue(user, indexManager) {
11958
+ return IndexedDbMutationQueue.forUser(user, this.serializer, indexManager, this.referenceDelegate);
11401
11959
  }
11402
11960
  getTargetCache() {
11403
11961
  return this.targetCache;
@@ -11405,8 +11963,11 @@ class IndexedDbPersistence {
11405
11963
  getRemoteDocumentCache() {
11406
11964
  return this.remoteDocumentCache;
11407
11965
  }
11408
- getIndexManager() {
11409
- return this.indexManager;
11966
+ getIndexManager(user) {
11967
+ return new IndexedDbIndexManager(user);
11968
+ }
11969
+ getDocumentOverlayCache(user) {
11970
+ return IndexedDbDocumentOverlayCache.forUser(this.serializer, user);
11410
11971
  }
11411
11972
  getBundleCache() {
11412
11973
  return this.bundleCache;
@@ -11414,11 +11975,12 @@ class IndexedDbPersistence {
11414
11975
  runTransaction(action, mode, transactionOperation) {
11415
11976
  logDebug(LOG_TAG$d, 'Starting transaction:', action);
11416
11977
  const simpleDbMode = mode === 'readonly' ? 'readonly' : 'readwrite';
11978
+ const objectStores = getObjectStores(this.schemaVersion);
11417
11979
  let persistenceTransaction;
11418
11980
  // Do all transactions as readwrite against all object stores, since we
11419
11981
  // are the only reader/writer.
11420
11982
  return this.simpleDb
11421
- .runTransaction(action, simpleDbMode, ALL_STORES, simpleDbTxn => {
11983
+ .runTransaction(action, simpleDbMode, objectStores, simpleDbTxn => {
11422
11984
  persistenceTransaction = new IndexedDbTransaction(simpleDbTxn, this.listenSequence
11423
11985
  ? this.listenSequence.next()
11424
11986
  : ListenSequence.INVALID);
@@ -11790,39 +12352,28 @@ class LocalDocumentsView {
11790
12352
  getDocumentsMatchingCollectionQuery(transaction, query, sinceReadTime) {
11791
12353
  // Query the remote documents and overlay mutations.
11792
12354
  let results;
11793
- let mutationBatches;
11794
12355
  return this.remoteDocumentCache
11795
- .getDocumentsMatchingQuery(transaction, query, sinceReadTime)
12356
+ .getAll(transaction, query.path, sinceReadTime)
11796
12357
  .next(queryResults => {
11797
12358
  results = queryResults;
11798
12359
  return this.mutationQueue.getAllMutationBatchesAffectingQuery(transaction, query);
11799
12360
  })
11800
- .next(matchingMutationBatches => {
11801
- mutationBatches = matchingMutationBatches;
11802
- // It is possible that a PatchMutation can make a document match a query, even if
11803
- // the version in the RemoteDocumentCache is not a match yet (waiting for server
11804
- // to ack). To handle this, we find all document keys affected by the PatchMutations
11805
- // that are not in `result` yet, and back fill them via `remoteDocumentCache.getEntries`,
11806
- // otherwise those `PatchMutations` will be ignored because no base document can be found,
11807
- // and lead to missing result for the query.
11808
- return this.addMissingBaseDocuments(transaction, mutationBatches, results).next(mergedDocuments => {
11809
- results = mergedDocuments;
11810
- for (const batch of mutationBatches) {
11811
- for (const mutation of batch.mutations) {
11812
- const key = mutation.key;
11813
- let document = results.get(key);
11814
- if (document == null) {
11815
- // Create invalid document to apply mutations on top of
11816
- document = MutableDocument.newInvalidDocument(key);
11817
- results = results.insert(key, document);
11818
- }
11819
- mutationApplyToLocalView(mutation, document, batch.localWriteTime);
11820
- if (!document.isFoundDocument()) {
11821
- results = results.remove(key);
11822
- }
12361
+ .next(mutationBatches => {
12362
+ for (const batch of mutationBatches) {
12363
+ for (const mutation of batch.mutations) {
12364
+ const key = mutation.key;
12365
+ let document = results.get(key);
12366
+ if (document == null) {
12367
+ // Create invalid document to apply mutations on top of
12368
+ document = MutableDocument.newInvalidDocument(key);
12369
+ results = results.insert(key, document);
12370
+ }
12371
+ mutationApplyToLocalView(mutation, document, batch.localWriteTime);
12372
+ if (!document.isFoundDocument()) {
12373
+ results = results.remove(key);
11823
12374
  }
11824
12375
  }
11825
- });
12376
+ }
11826
12377
  })
11827
12378
  .next(() => {
11828
12379
  // Finally, filter out any documents that don't actually match
@@ -11835,29 +12386,6 @@ class LocalDocumentsView {
11835
12386
  return results;
11836
12387
  });
11837
12388
  }
11838
- addMissingBaseDocuments(transaction, matchingMutationBatches, existingDocuments) {
11839
- let missingBaseDocEntriesForPatching = documentKeySet();
11840
- for (const batch of matchingMutationBatches) {
11841
- for (const mutation of batch.mutations) {
11842
- if (mutation instanceof PatchMutation &&
11843
- existingDocuments.get(mutation.key) === null) {
11844
- missingBaseDocEntriesForPatching =
11845
- missingBaseDocEntriesForPatching.add(mutation.key);
11846
- }
11847
- }
11848
- }
11849
- let mergedDocuments = existingDocuments;
11850
- return this.remoteDocumentCache
11851
- .getEntries(transaction, missingBaseDocEntriesForPatching)
11852
- .next(missingBaseDocs => {
11853
- missingBaseDocs.forEach((key, doc) => {
11854
- if (doc.isFoundDocument()) {
11855
- mergedDocuments = mergedDocuments.insert(key, doc);
11856
- }
11857
- });
11858
- return mergedDocuments;
11859
- });
11860
- }
11861
12389
  }
11862
12390
 
11863
12391
  /**
@@ -11916,11 +12444,18 @@ class LocalStoreImpl {
11916
12444
  * PORTING NOTE: This is only used for multi-tab synchronization.
11917
12445
  */
11918
12446
  this.lastDocumentChangeReadTime = SnapshotVersion.min();
11919
- this.mutationQueue = persistence.getMutationQueue(initialUser);
11920
12447
  this.remoteDocuments = persistence.getRemoteDocumentCache();
11921
12448
  this.targetCache = persistence.getTargetCache();
11922
- this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.persistence.getIndexManager());
11923
12449
  this.bundleCache = persistence.getBundleCache();
12450
+ this.initializeUserComponents(initialUser);
12451
+ }
12452
+ initializeUserComponents(user) {
12453
+ // TODO(indexing): Add spec tests that test these components change after a
12454
+ // user change
12455
+ this.indexManager = this.persistence.getIndexManager(user);
12456
+ this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
12457
+ this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
12458
+ this.remoteDocuments.setIndexManager(this.indexManager);
11924
12459
  this.queryEngine.setLocalDocumentsView(this.localDocuments);
11925
12460
  }
11926
12461
  collectGarbage(garbageCollector) {
@@ -11942,8 +12477,6 @@ persistence, queryEngine, initialUser, serializer) {
11942
12477
  // change.
11943
12478
  async function localStoreHandleUserChange(localStore, user) {
11944
12479
  const localStoreImpl = debugCast(localStore);
11945
- let newMutationQueue = localStoreImpl.mutationQueue;
11946
- let newLocalDocuments = localStoreImpl.localDocuments;
11947
12480
  const result = await localStoreImpl.persistence.runTransaction('Handle user change', 'readonly', txn => {
11948
12481
  // Swap out the mutation queue, grabbing the pending mutation batches
11949
12482
  // before and after.
@@ -11952,11 +12485,8 @@ async function localStoreHandleUserChange(localStore, user) {
11952
12485
  .getAllMutationBatches(txn)
11953
12486
  .next(promisedOldBatches => {
11954
12487
  oldBatches = promisedOldBatches;
11955
- newMutationQueue = localStoreImpl.persistence.getMutationQueue(user);
11956
- // Recreate our LocalDocumentsView using the new
11957
- // MutationQueue.
11958
- newLocalDocuments = new LocalDocumentsView(localStoreImpl.remoteDocuments, newMutationQueue, localStoreImpl.persistence.getIndexManager());
11959
- return newMutationQueue.getAllMutationBatches(txn);
12488
+ localStoreImpl.initializeUserComponents(user);
12489
+ return localStoreImpl.mutationQueue.getAllMutationBatches(txn);
11960
12490
  })
11961
12491
  .next(newBatches => {
11962
12492
  const removedBatchIds = [];
@@ -11977,7 +12507,7 @@ async function localStoreHandleUserChange(localStore, user) {
11977
12507
  }
11978
12508
  // Return the set of all (potentially) changed documents and the list
11979
12509
  // of mutation batch IDs that were affected by change.
11980
- return newLocalDocuments
12510
+ return localStoreImpl.localDocuments
11981
12511
  .getDocuments(txn, changedKeys)
11982
12512
  .next(affectedDocuments => {
11983
12513
  return {
@@ -11988,9 +12518,6 @@ async function localStoreHandleUserChange(localStore, user) {
11988
12518
  });
11989
12519
  });
11990
12520
  });
11991
- localStoreImpl.mutationQueue = newMutationQueue;
11992
- localStoreImpl.localDocuments = newLocalDocuments;
11993
- localStoreImpl.queryEngine.setLocalDocumentsView(localStoreImpl.localDocuments);
11994
12521
  return result;
11995
12522
  }
11996
12523
  /* Accepts locally generated Mutations and commit them to storage. */
@@ -12703,6 +13230,122 @@ class MemoryBundleCache {
12703
13230
  }
12704
13231
  }
12705
13232
 
13233
+ /**
13234
+ * @license
13235
+ * Copyright 2022 Google LLC
13236
+ *
13237
+ * Licensed under the Apache License, Version 2.0 (the "License");
13238
+ * you may not use this file except in compliance with the License.
13239
+ * You may obtain a copy of the License at
13240
+ *
13241
+ * http://www.apache.org/licenses/LICENSE-2.0
13242
+ *
13243
+ * Unless required by applicable law or agreed to in writing, software
13244
+ * distributed under the License is distributed on an "AS IS" BASIS,
13245
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13246
+ * See the License for the specific language governing permissions and
13247
+ * limitations under the License.
13248
+ */
13249
+ /**
13250
+ * An in-memory implementation of DocumentOverlayCache.
13251
+ */
13252
+ class MemoryDocumentOverlayCache {
13253
+ constructor() {
13254
+ // A map sorted by DocumentKey, whose value is a pair of the largest batch id
13255
+ // for the overlay and the overlay itself.
13256
+ this.overlays = new SortedMap(DocumentKey.comparator);
13257
+ this.overlayByBatchId = new Map();
13258
+ }
13259
+ getOverlay(transaction, key) {
13260
+ return PersistencePromise.resolve(this.overlays.get(key));
13261
+ }
13262
+ saveOverlays(transaction, largestBatchId, overlays) {
13263
+ overlays.forEach(mutation => {
13264
+ this.saveOverlay(transaction, largestBatchId, mutation);
13265
+ });
13266
+ return PersistencePromise.resolve();
13267
+ }
13268
+ removeOverlaysForBatchId(transaction, documentKeys, batchId) {
13269
+ const keys = this.overlayByBatchId.get(batchId);
13270
+ if (keys !== undefined) {
13271
+ keys.forEach(key => (this.overlays = this.overlays.remove(key)));
13272
+ this.overlayByBatchId.delete(batchId);
13273
+ }
13274
+ return PersistencePromise.resolve();
13275
+ }
13276
+ getOverlaysForCollection(transaction, collection, sinceBatchId) {
13277
+ const result = new Map();
13278
+ const immediateChildrenPathLength = collection.length + 1;
13279
+ const prefix = new DocumentKey(collection.child(''));
13280
+ const iter = this.overlays.getIteratorFrom(prefix);
13281
+ while (iter.hasNext()) {
13282
+ const entry = iter.getNext();
13283
+ const overlay = entry.value;
13284
+ const key = overlay.getKey();
13285
+ if (!collection.isPrefixOf(key.path)) {
13286
+ break;
13287
+ }
13288
+ // Documents from sub-collections
13289
+ if (key.path.length !== immediateChildrenPathLength) {
13290
+ continue;
13291
+ }
13292
+ if (overlay.largestBatchId > sinceBatchId) {
13293
+ result.set(overlay.getKey(), overlay);
13294
+ }
13295
+ }
13296
+ return PersistencePromise.resolve(result);
13297
+ }
13298
+ getOverlaysForCollectionGroup(transaction, collectionGroup, sinceBatchId, count) {
13299
+ let batchIdToOverlays = new SortedMap((key1, key2) => key1 - key2);
13300
+ const iter = this.overlays.getIterator();
13301
+ while (iter.hasNext()) {
13302
+ const entry = iter.getNext();
13303
+ const overlay = entry.value;
13304
+ const key = overlay.getKey();
13305
+ if (key.getCollectionGroup() !== collectionGroup) {
13306
+ continue;
13307
+ }
13308
+ if (overlay.largestBatchId > sinceBatchId) {
13309
+ let overlaysForBatchId = batchIdToOverlays.get(overlay.largestBatchId);
13310
+ if (overlaysForBatchId === null) {
13311
+ overlaysForBatchId = new Map();
13312
+ batchIdToOverlays = batchIdToOverlays.insert(overlay.largestBatchId, overlaysForBatchId);
13313
+ }
13314
+ overlaysForBatchId.set(overlay.getKey(), overlay);
13315
+ }
13316
+ }
13317
+ const result = new Map();
13318
+ const batchIter = batchIdToOverlays.getIterator();
13319
+ while (batchIter.hasNext()) {
13320
+ const entry = batchIter.getNext();
13321
+ const overlays = entry.value;
13322
+ overlays.forEach((overlay, key) => result.set(key, overlay));
13323
+ if (result.size >= count) {
13324
+ break;
13325
+ }
13326
+ }
13327
+ return PersistencePromise.resolve(result);
13328
+ }
13329
+ saveOverlay(transaction, largestBatchId, mutation) {
13330
+ if (mutation === null) {
13331
+ return;
13332
+ }
13333
+ // Remove the association of the overlay to its batch id.
13334
+ const existing = this.overlays.get(mutation.key);
13335
+ if (existing !== null) {
13336
+ this.overlayByBatchId.get(existing.largestBatchId).delete(mutation.key);
13337
+ }
13338
+ this.overlays = this.overlays.insert(mutation.key, new Overlay(largestBatchId, mutation));
13339
+ // Create the association of this overlay to the given largestBatchId.
13340
+ let batch = this.overlayByBatchId.get(largestBatchId);
13341
+ if (batch === undefined) {
13342
+ batch = new Set();
13343
+ this.overlayByBatchId.set(largestBatchId, batch);
13344
+ }
13345
+ batch.add(mutation.key);
13346
+ }
13347
+ }
13348
+
12706
13349
  /**
12707
13350
  * @license
12708
13351
  * Copyright 2017 Google LLC
@@ -13056,14 +13699,16 @@ class MemoryRemoteDocumentCacheImpl {
13056
13699
  * expected to just return 0 to avoid unnecessarily doing the work of
13057
13700
  * calculating the size.
13058
13701
  */
13059
- constructor(indexManager, sizer) {
13060
- this.indexManager = indexManager;
13702
+ constructor(sizer) {
13061
13703
  this.sizer = sizer;
13062
13704
  /** Underlying cache of documents and their read times. */
13063
13705
  this.docs = documentEntryMap();
13064
13706
  /** Size of all cached documents. */
13065
13707
  this.size = 0;
13066
13708
  }
13709
+ setIndexManager(indexManager) {
13710
+ this.indexManager = indexManager;
13711
+ }
13067
13712
  /**
13068
13713
  * Adds the supplied entry to the cache and updates the cache size as appropriate.
13069
13714
  *
@@ -13111,21 +13756,22 @@ class MemoryRemoteDocumentCacheImpl {
13111
13756
  });
13112
13757
  return PersistencePromise.resolve(results);
13113
13758
  }
13114
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
13759
+ getAll(transaction, collectionPath, sinceReadTime) {
13115
13760
  let results = mutableDocumentMap();
13116
13761
  // Documents are ordered by key, so we can use a prefix scan to narrow down
13117
13762
  // the documents we need to match the query against.
13118
- const prefix = new DocumentKey(query.path.child(''));
13763
+ const prefix = new DocumentKey(collectionPath.child(''));
13119
13764
  const iterator = this.docs.getIteratorFrom(prefix);
13120
13765
  while (iterator.hasNext()) {
13121
13766
  const { key, value: { document } } = iterator.getNext();
13122
- if (!query.path.isPrefixOf(key.path)) {
13767
+ if (!collectionPath.isPrefixOf(key.path)) {
13123
13768
  break;
13124
13769
  }
13125
- if (document.readTime.compareTo(sinceReadTime) <= 0) {
13770
+ if (key.path.length > collectionPath.length + 1) {
13771
+ // Exclude entries from subcollections.
13126
13772
  continue;
13127
13773
  }
13128
- if (!queryMatches(query, document)) {
13774
+ if (document.readTime.compareTo(sinceReadTime) <= 0) {
13129
13775
  continue;
13130
13776
  }
13131
13777
  results = results.insert(document.key, document.mutableCopy());
@@ -13147,13 +13793,12 @@ class MemoryRemoteDocumentCacheImpl {
13147
13793
  /**
13148
13794
  * Creates a new memory-only RemoteDocumentCache.
13149
13795
  *
13150
- * @param indexManager - A class that manages collection group indices.
13151
13796
  * @param sizer - Used to assess the size of a document. For eager GC, this is
13152
13797
  * expected to just return 0 to avoid unnecessarily doing the work of
13153
13798
  * calculating the size.
13154
13799
  */
13155
- function newMemoryRemoteDocumentCache(indexManager, sizer) {
13156
- return new MemoryRemoteDocumentCacheImpl(indexManager, sizer);
13800
+ function newMemoryRemoteDocumentCache(sizer) {
13801
+ return new MemoryRemoteDocumentCacheImpl(sizer);
13157
13802
  }
13158
13803
  /**
13159
13804
  * Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
@@ -13347,6 +13992,7 @@ class MemoryPersistence {
13347
13992
  */
13348
13993
  constructor(referenceDelegateFactory, serializer) {
13349
13994
  this.mutationQueues = {};
13995
+ this.overlays = {};
13350
13996
  this.listenSequence = new ListenSequence(0);
13351
13997
  this._started = false;
13352
13998
  this._started = true;
@@ -13354,7 +14000,7 @@ class MemoryPersistence {
13354
14000
  this.targetCache = new MemoryTargetCache(this);
13355
14001
  const sizer = (doc) => this.referenceDelegate.documentSize(doc);
13356
14002
  this.indexManager = new MemoryIndexManager();
13357
- this.remoteDocumentCache = newMemoryRemoteDocumentCache(this.indexManager, sizer);
14003
+ this.remoteDocumentCache = newMemoryRemoteDocumentCache(sizer);
13358
14004
  this.serializer = new LocalSerializer(serializer);
13359
14005
  this.bundleCache = new MemoryBundleCache(this.serializer);
13360
14006
  }
@@ -13375,13 +14021,23 @@ class MemoryPersistence {
13375
14021
  setNetworkEnabled() {
13376
14022
  // No op.
13377
14023
  }
13378
- getIndexManager() {
14024
+ getIndexManager(user) {
14025
+ // We do not currently support indices for memory persistence, so we can
14026
+ // return the same shared instance of the memory index manager.
13379
14027
  return this.indexManager;
13380
14028
  }
13381
- getMutationQueue(user) {
14029
+ getDocumentOverlayCache(user) {
14030
+ let overlay = this.overlays[user.toKey()];
14031
+ if (!overlay) {
14032
+ overlay = new MemoryDocumentOverlayCache();
14033
+ this.overlays[user.toKey()] = overlay;
14034
+ }
14035
+ return overlay;
14036
+ }
14037
+ getMutationQueue(user, indexManager) {
13382
14038
  let queue = this.mutationQueues[user.toKey()];
13383
14039
  if (!queue) {
13384
- queue = new MemoryMutationQueue(this.indexManager, this.referenceDelegate);
14040
+ queue = new MemoryMutationQueue(indexManager, this.referenceDelegate);
13385
14041
  this.mutationQueues[user.toKey()] = queue;
13386
14042
  }
13387
14043
  return queue;
@@ -20344,12 +21000,12 @@ async function syncEngineListen(syncEngine, query) {
20344
21000
  }
20345
21001
  else {
20346
21002
  const targetData = await localStoreAllocateTarget(syncEngineImpl.localStore, queryToTarget(query));
20347
- const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
20348
- targetId = targetData.targetId;
20349
- viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20350
21003
  if (syncEngineImpl.isPrimaryClient) {
20351
21004
  remoteStoreListen(syncEngineImpl.remoteStore, targetData);
20352
21005
  }
21006
+ const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
21007
+ targetId = targetData.targetId;
21008
+ viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20353
21009
  }
20354
21010
  return viewSnapshot;
20355
21011
  }
@@ -24857,8 +25513,7 @@ class DocumentSnapshot extends DocumentSnapshot$1 {
24857
25513
  this.metadata = metadata;
24858
25514
  }
24859
25515
  /**
24860
- * Property of the `DocumentSnapshot` that signals whether or not the data
24861
- * exists. True if the document exists.
25516
+ * Returns whether or not the data exists. True if the document exists.
24862
25517
  */
24863
25518
  exists() {
24864
25519
  return super.exists();
@@ -25232,51 +25887,53 @@ function limitToLast(limit) {
25232
25887
  return new QueryLimitConstraint('limitToLast', limit, "L" /* Last */);
25233
25888
  }
25234
25889
  class QueryStartAtConstraint extends QueryConstraint {
25235
- constructor(type, _docOrFields, _before) {
25890
+ constructor(type, _docOrFields, _inclusive) {
25236
25891
  super();
25237
25892
  this.type = type;
25238
25893
  this._docOrFields = _docOrFields;
25239
- this._before = _before;
25894
+ this._inclusive = _inclusive;
25240
25895
  }
25241
25896
  _apply(query) {
25242
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25897
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25243
25898
  return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
25244
25899
  }
25245
25900
  }
25246
25901
  function startAt(...docOrFields) {
25247
- return new QueryStartAtConstraint('startAt', docOrFields, /*before=*/ true);
25902
+ return new QueryStartAtConstraint('startAt', docOrFields,
25903
+ /*inclusive=*/ true);
25248
25904
  }
25249
25905
  function startAfter(...docOrFields) {
25250
25906
  return new QueryStartAtConstraint('startAfter', docOrFields,
25251
- /*before=*/ false);
25907
+ /*inclusive=*/ false);
25252
25908
  }
25253
25909
  class QueryEndAtConstraint extends QueryConstraint {
25254
- constructor(type, _docOrFields, _before) {
25910
+ constructor(type, _docOrFields, _inclusive) {
25255
25911
  super();
25256
25912
  this.type = type;
25257
25913
  this._docOrFields = _docOrFields;
25258
- this._before = _before;
25914
+ this._inclusive = _inclusive;
25259
25915
  }
25260
25916
  _apply(query) {
25261
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25917
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25262
25918
  return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
25263
25919
  }
25264
25920
  }
25265
25921
  function endBefore(...docOrFields) {
25266
- return new QueryEndAtConstraint('endBefore', docOrFields, /*before=*/ true);
25922
+ return new QueryEndAtConstraint('endBefore', docOrFields,
25923
+ /*inclusive=*/ false);
25267
25924
  }
25268
25925
  function endAt(...docOrFields) {
25269
- return new QueryEndAtConstraint('endAt', docOrFields, /*before=*/ false);
25926
+ return new QueryEndAtConstraint('endAt', docOrFields, /*inclusive=*/ true);
25270
25927
  }
25271
25928
  /** Helper function to create a bound from a document or fields */
25272
- function newQueryBoundFromDocOrFields(query, methodName, docOrFields, before) {
25929
+ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
25273
25930
  docOrFields[0] = util$1.getModularInstance(docOrFields[0]);
25274
25931
  if (docOrFields[0] instanceof DocumentSnapshot$1) {
25275
- return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, before);
25932
+ return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive);
25276
25933
  }
25277
25934
  else {
25278
25935
  const reader = newUserDataReader(query.firestore);
25279
- return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, before);
25936
+ return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive);
25280
25937
  }
25281
25938
  }
25282
25939
  function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
@@ -25334,7 +25991,7 @@ function newQueryOrderBy(query, fieldPath, direction) {
25334
25991
  * of the query or if any of the fields in the order by are an uncommitted
25335
25992
  * server timestamp.
25336
25993
  */
25337
- function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25994
+ function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) {
25338
25995
  if (!doc) {
25339
25996
  throw new FirestoreError(Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` +
25340
25997
  `${methodName}().`);
@@ -25371,12 +26028,12 @@ function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25371
26028
  }
25372
26029
  }
25373
26030
  }
25374
- return new Bound(components, before);
26031
+ return new Bound(components, inclusive);
25375
26032
  }
25376
26033
  /**
25377
26034
  * Converts a list of field values to a `Bound` for the given query.
25378
26035
  */
25379
- function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, before) {
26036
+ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) {
25380
26037
  // Use explicit order by's because it has to match the query the user made
25381
26038
  const orderBy = query.explicitOrderBy;
25382
26039
  if (values.length > orderBy.length) {
@@ -25413,7 +26070,7 @@ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, valu
25413
26070
  components.push(wrapped);
25414
26071
  }
25415
26072
  }
25416
- return new Bound(components, before);
26073
+ return new Bound(components, inclusive);
25417
26074
  }
25418
26075
  /**
25419
26076
  * Parses the given `documentIdValue` into a `ReferenceValue`, throwing