@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
@@ -8,7 +8,7 @@ import { credentials, loadPackageDefinition, Metadata } from '@grpc/grpc-js';
8
8
  import { fromJSON } from '@grpc/proto-loader';
9
9
 
10
10
  const name = "@firebase/firestore";
11
- const version$1 = "3.4.4-canary.2dd99ae2d";
11
+ const version$1 = "3.4.4-canary.3e9f3e253";
12
12
 
13
13
  /**
14
14
  * @license
@@ -61,7 +61,7 @@ User.GOOGLE_CREDENTIALS = new User('google-credentials-uid');
61
61
  User.FIRST_PARTY = new User('first-party-uid');
62
62
  User.MOCK_USER = new User('mock-user');
63
63
 
64
- const version = "9.6.5-canary.2dd99ae2d";
64
+ const version = "9.6.6-canary.3e9f3e253";
65
65
 
66
66
  /**
67
67
  * @license
@@ -666,13 +666,19 @@ class FirebaseAppCheckTokenProvider {
666
666
  this.appCheckProvider = appCheckProvider;
667
667
  this.forceRefresh = false;
668
668
  this.appCheck = null;
669
+ this.latestAppCheckToken = null;
669
670
  }
670
671
  start(asyncQueue, changeListener) {
671
672
  const onTokenChanged = tokenResult => {
672
673
  if (tokenResult.error != null) {
673
674
  logDebug('FirebaseAppCheckTokenProvider', `Error getting App Check token; using placeholder token instead. Error: ${tokenResult.error.message}`);
674
675
  }
675
- return changeListener(tokenResult.token);
676
+ const tokenUpdated = tokenResult.token !== this.latestAppCheckToken;
677
+ this.latestAppCheckToken = tokenResult.token;
678
+ logDebug('FirebaseAppCheckTokenProvider', `Received ${tokenUpdated ? 'new' : 'existing'} token.`);
679
+ return tokenUpdated
680
+ ? changeListener(tokenResult.token)
681
+ : Promise.resolve();
676
682
  };
677
683
  this.tokenListener = (tokenResult) => {
678
684
  asyncQueue.enqueueRetryable(() => onTokenChanged(tokenResult));
@@ -707,6 +713,7 @@ class FirebaseAppCheckTokenProvider {
707
713
  return this.appCheck.getToken(forceRefresh).then(tokenResult => {
708
714
  if (tokenResult) {
709
715
  hardAssert(typeof tokenResult.token === 'string');
716
+ this.latestAppCheckToken = tokenResult.token;
710
717
  return new AppCheckToken(tokenResult.token);
711
718
  }
712
719
  else {
@@ -1192,23 +1199,6 @@ function decodeResourcePath(path) {
1192
1199
  }
1193
1200
  return new ResourcePath(segments);
1194
1201
  }
1195
-
1196
- /**
1197
- * @license
1198
- * Copyright 2017 Google LLC
1199
- *
1200
- * Licensed under the Apache License, Version 2.0 (the "License");
1201
- * you may not use this file except in compliance with the License.
1202
- * You may obtain a copy of the License at
1203
- *
1204
- * http://www.apache.org/licenses/LICENSE-2.0
1205
- *
1206
- * Unless required by applicable law or agreed to in writing, software
1207
- * distributed under the License is distributed on an "AS IS" BASIS,
1208
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1209
- * See the License for the specific language governing permissions and
1210
- * limitations under the License.
1211
- */
1212
1202
  /**
1213
1203
  * Schema Version for the Web client:
1214
1204
  * 1. Initial version including Mutation Queue, Query Cache, and Remote
@@ -1227,8 +1217,10 @@ function decodeResourcePath(path) {
1227
1217
  * an auto-incrementing ID. This is required for Index-Free queries.
1228
1218
  * 10. Rewrite the canonical IDs to the explicit Protobuf-based format.
1229
1219
  * 11. Add bundles and named_queries for bundle support.
1220
+ * 12. Add document overlays.
1221
+ * 13. Add indexing support.
1230
1222
  */
1231
- const SCHEMA_VERSION = 11;
1223
+ const SCHEMA_VERSION = 12;
1232
1224
  /**
1233
1225
  * Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects.
1234
1226
  */
@@ -1753,9 +1745,7 @@ class DbClientMetadata {
1753
1745
  DbClientMetadata.store = 'clientMetadata';
1754
1746
  /** Keys are automatically assigned via the clientId properties. */
1755
1747
  DbClientMetadata.keyPath = 'clientId';
1756
- /**
1757
- * A object representing a bundle loaded by the SDK.
1758
- */
1748
+ /** An object representing a bundle loaded by the SDK. */
1759
1749
  class DbBundle {
1760
1750
  constructor(
1761
1751
  /** The ID of the loaded bundle. */
@@ -1772,9 +1762,7 @@ class DbBundle {
1772
1762
  /** Name of the IndexedDb object store. */
1773
1763
  DbBundle.store = 'bundles';
1774
1764
  DbBundle.keyPath = 'bundleId';
1775
- /**
1776
- * A object representing a named query loaded by the SDK via a bundle.
1777
- */
1765
+ /** An object representing a named query loaded by the SDK via a bundle. */
1778
1766
  class DbNamedQuery {
1779
1767
  constructor(
1780
1768
  /** The name of the query. */
@@ -1791,6 +1779,156 @@ class DbNamedQuery {
1791
1779
  /** Name of the IndexedDb object store. */
1792
1780
  DbNamedQuery.store = 'namedQueries';
1793
1781
  DbNamedQuery.keyPath = 'name';
1782
+ /** An object representing the global configuration for a field index. */
1783
+ class DbIndexConfiguration {
1784
+ constructor(
1785
+ /**
1786
+ * The index id for this entry. Undefined for indexes that are not yet
1787
+ * persisted.
1788
+ */
1789
+ indexId,
1790
+ /** The collection group this index belongs to. */
1791
+ collectionGroup,
1792
+ /** The fields to index for this index. */
1793
+ fields) {
1794
+ this.indexId = indexId;
1795
+ this.collectionGroup = collectionGroup;
1796
+ this.fields = fields;
1797
+ }
1798
+ }
1799
+ /** Name of the IndexedDb object store. */
1800
+ DbIndexConfiguration.store = 'indexConfiguration';
1801
+ DbIndexConfiguration.keyPath = 'indexId';
1802
+ /**
1803
+ * An index that provides access to the index configurations by collection
1804
+ * group.
1805
+ *
1806
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1807
+ * not possible here as the Web client supports concurrent access to
1808
+ * persistence via multi-tab.
1809
+ */
1810
+ DbIndexConfiguration.collectionGroupIndex = 'collectionGroupIndex';
1811
+ DbIndexConfiguration.collectionGroupIndexPath = 'collectionGroup';
1812
+ /**
1813
+ * An object describing how up-to-date the index backfill is for each user and
1814
+ * index.
1815
+ */
1816
+ class DbIndexState {
1817
+ constructor(
1818
+ /** The index id for this entry. */
1819
+ indexId,
1820
+ /** The user id for this entry. */
1821
+ uid,
1822
+ /**
1823
+ * A number that indicates when the index was last updated (relative to
1824
+ * other indexes).
1825
+ */
1826
+ sequenceNumber,
1827
+ /**
1828
+ * The latest read time that has been indexed by Firestore for this field
1829
+ * index. Set to `{seconds: 0, nanos: 0}` if no documents have been indexed.
1830
+ */
1831
+ readTime,
1832
+ /**
1833
+ * The last document that has been indexed for this field index. Empty if
1834
+ * no documents have been indexed.
1835
+ */
1836
+ documentKey,
1837
+ /**
1838
+ * The largest mutation batch id that has been processed for this index. -1
1839
+ * if no mutations have been indexed.
1840
+ */
1841
+ largestBatchId) {
1842
+ this.indexId = indexId;
1843
+ this.uid = uid;
1844
+ this.sequenceNumber = sequenceNumber;
1845
+ this.readTime = readTime;
1846
+ this.documentKey = documentKey;
1847
+ this.largestBatchId = largestBatchId;
1848
+ }
1849
+ }
1850
+ /** Name of the IndexedDb object store. */
1851
+ DbIndexState.store = 'indexState';
1852
+ DbIndexState.keyPath = ['indexId', 'uid'];
1853
+ /**
1854
+ * An index that provides access to documents in a collection sorted by last
1855
+ * update time. Used by the backfiller.
1856
+ *
1857
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1858
+ * not possible here as the Web client supports concurrent access to
1859
+ * persistence via multi-tab.
1860
+ */
1861
+ DbIndexState.sequenceNumberIndex = 'sequenceNumberIndex';
1862
+ DbIndexState.sequenceNumberIndexPath = ['uid', 'sequenceNumber'];
1863
+ /** An object that stores the encoded entries for all documents and fields. */
1864
+ class DbIndexEntry {
1865
+ constructor(
1866
+ /** The index id for this entry. */
1867
+ indexId,
1868
+ /** The user id for this entry. */
1869
+ uid,
1870
+ /** The encoded array index value for this entry. */
1871
+ arrayValue,
1872
+ /** The encoded directional value for equality and inequality filters. */
1873
+ directionalValue,
1874
+ /** The document key this entry points to. */
1875
+ documentKey) {
1876
+ this.indexId = indexId;
1877
+ this.uid = uid;
1878
+ this.arrayValue = arrayValue;
1879
+ this.directionalValue = directionalValue;
1880
+ this.documentKey = documentKey;
1881
+ }
1882
+ }
1883
+ /** Name of the IndexedDb object store. */
1884
+ DbIndexEntry.store = 'indexEntries';
1885
+ DbIndexEntry.keyPath = [
1886
+ 'indexId',
1887
+ 'uid',
1888
+ 'arrayValue',
1889
+ 'directionalValue',
1890
+ 'documentKey'
1891
+ ];
1892
+ /**
1893
+ * An object representing a document overlay.
1894
+ */
1895
+ class DbDocumentOverlay {
1896
+ constructor(
1897
+ /** The user ID to whom this overlay belongs. */
1898
+ userId,
1899
+ /** The path to the collection that contains the document. */
1900
+ collectionPath,
1901
+ /** The ID (key) of the document within the collection. */
1902
+ documentId,
1903
+ /** The collection group to which the document belongs. */
1904
+ collectionGroup,
1905
+ /** The largest batch ID that's been applied for this overlay. */
1906
+ largestBatchId,
1907
+ /** The overlay mutation. */
1908
+ overlayMutation) {
1909
+ this.userId = userId;
1910
+ this.collectionPath = collectionPath;
1911
+ this.documentId = documentId;
1912
+ this.collectionGroup = collectionGroup;
1913
+ this.largestBatchId = largestBatchId;
1914
+ this.overlayMutation = overlayMutation;
1915
+ }
1916
+ }
1917
+ /** Name of the IndexedDb object store. */
1918
+ DbDocumentOverlay.store = 'documentOverlays';
1919
+ DbDocumentOverlay.keyPath = ['userId', 'collectionPath', 'documentId'];
1920
+ DbDocumentOverlay.collectionPathOverlayIndex = 'collectionPathOverlayIndex';
1921
+ DbDocumentOverlay.collectionPathOverlayIndexPath = [
1922
+ 'userId',
1923
+ 'collectionPath',
1924
+ 'largestBatchId'
1925
+ ];
1926
+ DbDocumentOverlay.collectionGroupOverlayIndex = 'collectionGroupOverlayIndex';
1927
+ DbDocumentOverlay.collectionGroupOverlayIndexPath = [
1928
+ 'userId',
1929
+ 'collectionGroup',
1930
+ 'largestBatchId'
1931
+ ];
1794
1932
  // Visible for testing
1795
1933
  const V1_STORES = [
1796
1934
  DbMutationQueue.store,
@@ -1805,7 +1943,6 @@ const V1_STORES = [
1805
1943
  // V2 is no longer usable (see comment at top of file)
1806
1944
  // Visible for testing
1807
1945
  const V3_STORES = V1_STORES;
1808
- // Visible for testing
1809
1946
  // Note: DbRemoteDocumentChanges is no longer used and dropped with v9.
1810
1947
  const V4_STORES = [...V3_STORES, DbClientMetadata.store];
1811
1948
  // V5 does not change the set of stores.
@@ -1815,12 +1952,28 @@ const V8_STORES = [...V6_STORES, DbCollectionParent.store];
1815
1952
  // V9 does not change the set of stores.
1816
1953
  // V10 does not change the set of stores.
1817
1954
  const V11_STORES = [...V8_STORES, DbBundle.store, DbNamedQuery.store];
1818
- /**
1819
- * The list of all default IndexedDB stores used throughout the SDK. This is
1820
- * used when creating transactions so that access across all stores is done
1821
- * atomically.
1822
- */
1823
- const ALL_STORES = V11_STORES;
1955
+ const V12_STORES = [...V11_STORES, DbDocumentOverlay.store];
1956
+ const V13_STORES = [
1957
+ ...V12_STORES,
1958
+ DbIndexConfiguration.store,
1959
+ DbIndexState.store,
1960
+ DbIndexEntry.store
1961
+ ];
1962
+ /** Returns the object stores for the provided schema. */
1963
+ function getObjectStores(schemaVersion) {
1964
+ if (schemaVersion === 13) {
1965
+ return V13_STORES;
1966
+ }
1967
+ else if (schemaVersion === 12) {
1968
+ return V12_STORES;
1969
+ }
1970
+ else if (schemaVersion === 11) {
1971
+ return V11_STORES;
1972
+ }
1973
+ else {
1974
+ fail();
1975
+ }
1976
+ }
1824
1977
 
1825
1978
  /**
1826
1979
  * @license
@@ -2117,6 +2270,15 @@ class SimpleDbTransaction {
2117
2270
  this.transaction.abort();
2118
2271
  }
2119
2272
  }
2273
+ maybeCommit() {
2274
+ // If the browser supports V3 IndexedDB, we invoke commit() explicitly to
2275
+ // speed up index DB processing if the event loop remains blocks.
2276
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2277
+ const maybeV3IndexedDb = this.transaction;
2278
+ if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {
2279
+ maybeV3IndexedDb.commit();
2280
+ }
2281
+ }
2120
2282
  /**
2121
2283
  * Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
2122
2284
  * operations performed on the SimpleDbStore happen within the context of this
@@ -2313,6 +2475,10 @@ class SimpleDb {
2313
2475
  this.db = await this.ensureDb(action);
2314
2476
  const transaction = SimpleDbTransaction.open(this.db, action, readonly ? 'readonly' : 'readwrite', objectStores);
2315
2477
  const transactionFnResult = transactionFn(transaction)
2478
+ .next(result => {
2479
+ transaction.maybeCommit();
2480
+ return result;
2481
+ })
2316
2482
  .catch(error => {
2317
2483
  // Abort the transaction if there was an error.
2318
2484
  transaction.abort(error);
@@ -2485,13 +2651,29 @@ class SimpleDbStore {
2485
2651
  return wrapRequest(request);
2486
2652
  }
2487
2653
  loadAll(indexOrRange, range) {
2488
- const cursor = this.cursor(this.options(indexOrRange, range));
2489
- const results = [];
2490
- return this.iterateCursor(cursor, (key, value) => {
2491
- results.push(value);
2492
- }).next(() => {
2493
- return results;
2494
- });
2654
+ const iterateOptions = this.options(indexOrRange, range);
2655
+ // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly
2656
+ // 20% faster. Unfortunately, getAll() does not support custom indices.
2657
+ if (!iterateOptions.index && typeof this.store.getAll === 'function') {
2658
+ const request = this.store.getAll(iterateOptions.range);
2659
+ return new PersistencePromise((resolve, reject) => {
2660
+ request.onerror = (event) => {
2661
+ reject(event.target.error);
2662
+ };
2663
+ request.onsuccess = (event) => {
2664
+ resolve(event.target.result);
2665
+ };
2666
+ });
2667
+ }
2668
+ else {
2669
+ const cursor = this.cursor(iterateOptions);
2670
+ const results = [];
2671
+ return this.iterateCursor(cursor, (key, value) => {
2672
+ results.push(value);
2673
+ }).next(() => {
2674
+ return results;
2675
+ });
2676
+ }
2495
2677
  }
2496
2678
  deleteAll(indexOrRange, range) {
2497
2679
  logDebug(LOG_TAG$g, 'DELETE ALL', this.store.name);
@@ -3522,6 +3704,14 @@ class DocumentKey {
3522
3704
  return (this.path.length >= 2 &&
3523
3705
  this.path.get(this.path.length - 2) === collectionId);
3524
3706
  }
3707
+ /** Returns the collection group (i.e. the name of the parent collection) for this key. */
3708
+ getCollectionGroup() {
3709
+ return this.path.get(this.path.length - 2);
3710
+ }
3711
+ /** Returns the fully qualified path to the parent collection. */
3712
+ getCollectionPath() {
3713
+ return this.path.popLast();
3714
+ }
3525
3715
  isEqual(other) {
3526
3716
  return (other !== null && ResourcePath.comparator(this.path, other.path) === 0);
3527
3717
  }
@@ -4345,12 +4535,12 @@ class FieldIndex {
4345
4535
  /** The collection ID this index applies to. */
4346
4536
  collectionGroup,
4347
4537
  /** The field segments for this index. */
4348
- segments,
4538
+ fields,
4349
4539
  /** Shows how up-to-date the index is for the current user. */
4350
4540
  indexState) {
4351
4541
  this.indexId = indexId;
4352
4542
  this.collectionGroup = collectionGroup;
4353
- this.segments = segments;
4543
+ this.fields = fields;
4354
4544
  this.indexState = indexState;
4355
4545
  }
4356
4546
  }
@@ -4460,27 +4650,29 @@ function newTarget(path, collectionGroup = null, orderBy = [], filters = [], lim
4460
4650
  function canonifyTarget(target) {
4461
4651
  const targetImpl = debugCast(target);
4462
4652
  if (targetImpl.memoizedCanonicalId === null) {
4463
- let canonicalId = targetImpl.path.canonicalString();
4653
+ let str = targetImpl.path.canonicalString();
4464
4654
  if (targetImpl.collectionGroup !== null) {
4465
- canonicalId += '|cg:' + targetImpl.collectionGroup;
4655
+ str += '|cg:' + targetImpl.collectionGroup;
4466
4656
  }
4467
- canonicalId += '|f:';
4468
- canonicalId += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4469
- canonicalId += '|ob:';
4470
- canonicalId += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4657
+ str += '|f:';
4658
+ str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4659
+ str += '|ob:';
4660
+ str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4471
4661
  if (!isNullOrUndefined(targetImpl.limit)) {
4472
- canonicalId += '|l:';
4473
- canonicalId += targetImpl.limit;
4662
+ str += '|l:';
4663
+ str += targetImpl.limit;
4474
4664
  }
4475
4665
  if (targetImpl.startAt) {
4476
- canonicalId += '|lb:';
4477
- canonicalId += canonifyBound(targetImpl.startAt);
4666
+ str += '|lb:';
4667
+ str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
4668
+ str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
4478
4669
  }
4479
4670
  if (targetImpl.endAt) {
4480
- canonicalId += '|ub:';
4481
- canonicalId += canonifyBound(targetImpl.endAt);
4671
+ str += '|ub:';
4672
+ str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
4673
+ str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
4482
4674
  }
4483
- targetImpl.memoizedCanonicalId = canonicalId;
4675
+ targetImpl.memoizedCanonicalId = str;
4484
4676
  }
4485
4677
  return targetImpl.memoizedCanonicalId;
4486
4678
  }
@@ -4503,10 +4695,14 @@ function stringifyTarget(target) {
4503
4695
  .join(', ')}]`;
4504
4696
  }
4505
4697
  if (target.startAt) {
4506
- str += ', startAt: ' + canonifyBound(target.startAt);
4698
+ str += ', startAt: ';
4699
+ str += target.startAt.inclusive ? 'b:' : 'a:';
4700
+ str += target.startAt.position.map(p => canonicalId(p)).join(',');
4507
4701
  }
4508
4702
  if (target.endAt) {
4509
- str += ', endAt: ' + canonifyBound(target.endAt);
4703
+ str += ', endAt: ';
4704
+ str += target.endAt.inclusive ? 'a:' : 'b:';
4705
+ str += target.endAt.position.map(p => canonicalId(p)).join(',');
4510
4706
  }
4511
4707
  return `Target(${str})`;
4512
4708
  }
@@ -4729,7 +4925,6 @@ class ArrayContainsAnyFilter extends FieldFilter {
4729
4925
  return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
4730
4926
  }
4731
4927
  }
4732
- // TODO(indexing): Change Bound.before to "inclusive"
4733
4928
  /**
4734
4929
  * Represents a bound of a query.
4735
4930
  *
@@ -4745,17 +4940,11 @@ class ArrayContainsAnyFilter extends FieldFilter {
4745
4940
  * just after the provided values.
4746
4941
  */
4747
4942
  class Bound {
4748
- constructor(position, before) {
4943
+ constructor(position, inclusive) {
4749
4944
  this.position = position;
4750
- this.before = before;
4945
+ this.inclusive = inclusive;
4751
4946
  }
4752
4947
  }
4753
- function canonifyBound(bound) {
4754
- // TODO(b/29183165): Make this collision robust.
4755
- return `${bound.before ? 'b' : 'a'}:${bound.position
4756
- .map(p => canonicalId(p))
4757
- .join(',')}`;
4758
- }
4759
4948
  /**
4760
4949
  * An ordering on a field, in some Direction. Direction defaults to ASCENDING.
4761
4950
  */
@@ -4775,11 +4964,7 @@ function stringifyOrderBy(orderBy) {
4775
4964
  function orderByEquals(left, right) {
4776
4965
  return left.dir === right.dir && left.field.isEqual(right.field);
4777
4966
  }
4778
- /**
4779
- * Returns true if a document sorts before a bound using the provided sort
4780
- * order.
4781
- */
4782
- function sortsBeforeDocument(bound, orderBy, doc) {
4967
+ function boundCompareToDocument(bound, orderBy, doc) {
4783
4968
  let comparison = 0;
4784
4969
  for (let i = 0; i < bound.position.length; i++) {
4785
4970
  const orderByComponent = orderBy[i];
@@ -4798,7 +4983,23 @@ function sortsBeforeDocument(bound, orderBy, doc) {
4798
4983
  break;
4799
4984
  }
4800
4985
  }
4801
- return bound.before ? comparison <= 0 : comparison < 0;
4986
+ return comparison;
4987
+ }
4988
+ /**
4989
+ * Returns true if a document sorts after a bound using the provided sort
4990
+ * order.
4991
+ */
4992
+ function boundSortsAfterDocument(bound, orderBy, doc) {
4993
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4994
+ return bound.inclusive ? comparison >= 0 : comparison > 0;
4995
+ }
4996
+ /**
4997
+ * Returns true if a document sorts before a bound using the provided sort
4998
+ * order.
4999
+ */
5000
+ function boundSortsBeforeDocument(bound, orderBy, doc) {
5001
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
5002
+ return bound.inclusive ? comparison <= 0 : comparison < 0;
4802
5003
  }
4803
5004
  function boundEquals(left, right) {
4804
5005
  if (left === null) {
@@ -4807,7 +5008,7 @@ function boundEquals(left, right) {
4807
5008
  else if (right === null) {
4808
5009
  return false;
4809
5010
  }
4810
- if (left.before !== right.before ||
5011
+ if (left.inclusive !== right.inclusive ||
4811
5012
  left.position.length !== right.position.length) {
4812
5013
  return false;
4813
5014
  }
@@ -5011,10 +5212,10 @@ function queryToTarget(query) {
5011
5212
  }
5012
5213
  // We need to swap the cursors to match the now-flipped query ordering.
5013
5214
  const startAt = queryImpl.endAt
5014
- ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.before)
5215
+ ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
5015
5216
  : null;
5016
5217
  const endAt = queryImpl.startAt
5017
- ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.before)
5218
+ ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
5018
5219
  : null;
5019
5220
  // Now return as a LimitType.First query.
5020
5221
  queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
@@ -5102,11 +5303,11 @@ function queryMatchesFilters(query, doc) {
5102
5303
  /** Makes sure a document is within the bounds, if provided. */
5103
5304
  function queryMatchesBounds(query, doc) {
5104
5305
  if (query.startAt &&
5105
- !sortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5306
+ !boundSortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5106
5307
  return false;
5107
5308
  }
5108
5309
  if (query.endAt &&
5109
- sortsBeforeDocument(query.endAt, queryOrderBy(query), doc)) {
5310
+ !boundSortsAfterDocument(query.endAt, queryOrderBy(query), doc)) {
5110
5311
  return false;
5111
5312
  }
5112
5313
  return true;
@@ -6599,6 +6800,47 @@ class MutationBatchResult {
6599
6800
  }
6600
6801
  }
6601
6802
 
6803
+ /**
6804
+ * @license
6805
+ * Copyright 2022 Google LLC
6806
+ *
6807
+ * Licensed under the Apache License, Version 2.0 (the "License");
6808
+ * you may not use this file except in compliance with the License.
6809
+ * You may obtain a copy of the License at
6810
+ *
6811
+ * http://www.apache.org/licenses/LICENSE-2.0
6812
+ *
6813
+ * Unless required by applicable law or agreed to in writing, software
6814
+ * distributed under the License is distributed on an "AS IS" BASIS,
6815
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6816
+ * See the License for the specific language governing permissions and
6817
+ * limitations under the License.
6818
+ */
6819
+ /**
6820
+ * Representation of an overlay computed by Firestore.
6821
+ *
6822
+ * Holds information about a mutation and the largest batch id in Firestore when
6823
+ * the mutation was created.
6824
+ */
6825
+ class Overlay {
6826
+ constructor(largestBatchId, mutation) {
6827
+ this.largestBatchId = largestBatchId;
6828
+ this.mutation = mutation;
6829
+ }
6830
+ getKey() {
6831
+ return this.mutation.key;
6832
+ }
6833
+ isEqual(other) {
6834
+ return other !== null && this.mutation === other.mutation;
6835
+ }
6836
+ toString() {
6837
+ return `Overlay{
6838
+ largestBatchId: ${this.largestBatchId},
6839
+ mutation: ${this.mutation.toString()}
6840
+ }`;
6841
+ }
6842
+ }
6843
+
6602
6844
  /**
6603
6845
  * @license
6604
6846
  * Copyright 2017 Google LLC
@@ -7985,10 +8227,10 @@ function toQueryTarget(serializer, target) {
7985
8227
  result.structuredQuery.limit = limit;
7986
8228
  }
7987
8229
  if (target.startAt) {
7988
- result.structuredQuery.startAt = toCursor(target.startAt);
8230
+ result.structuredQuery.startAt = toStartAtCursor(target.startAt);
7989
8231
  }
7990
8232
  if (target.endAt) {
7991
- result.structuredQuery.endAt = toCursor(target.endAt);
8233
+ result.structuredQuery.endAt = toEndAtCursor(target.endAt);
7992
8234
  }
7993
8235
  return result;
7994
8236
  }
@@ -8021,11 +8263,11 @@ function convertQueryTargetToQuery(target) {
8021
8263
  }
8022
8264
  let startAt = null;
8023
8265
  if (query.startAt) {
8024
- startAt = fromCursor(query.startAt);
8266
+ startAt = fromStartAtCursor(query.startAt);
8025
8267
  }
8026
8268
  let endAt = null;
8027
8269
  if (query.endAt) {
8028
- endAt = fromCursor(query.endAt);
8270
+ endAt = fromEndAtCursor(query.endAt);
8029
8271
  }
8030
8272
  return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
8031
8273
  }
@@ -8116,16 +8358,27 @@ function toOrder(orderBys) {
8116
8358
  function fromOrder(orderBys) {
8117
8359
  return orderBys.map(order => fromPropertyOrder(order));
8118
8360
  }
8119
- function toCursor(cursor) {
8361
+ function toStartAtCursor(cursor) {
8362
+ return {
8363
+ before: cursor.inclusive,
8364
+ values: cursor.position
8365
+ };
8366
+ }
8367
+ function toEndAtCursor(cursor) {
8120
8368
  return {
8121
- before: cursor.before,
8369
+ before: !cursor.inclusive,
8122
8370
  values: cursor.position
8123
8371
  };
8124
8372
  }
8125
- function fromCursor(cursor) {
8126
- const before = !!cursor.before;
8373
+ function fromStartAtCursor(cursor) {
8374
+ const inclusive = !!cursor.before;
8127
8375
  const position = cursor.values || [];
8128
- return new Bound(position, before);
8376
+ return new Bound(position, inclusive);
8377
+ }
8378
+ function fromEndAtCursor(cursor) {
8379
+ const inclusive = !cursor.before;
8380
+ const position = cursor.values || [];
8381
+ return new Bound(position, inclusive);
8129
8382
  }
8130
8383
  // visible for testing
8131
8384
  function toDirection(dir) {
@@ -8589,6 +8842,37 @@ function fromBundleMetadata(metadata) {
8589
8842
  version: metadata.version,
8590
8843
  createTime: fromVersion(metadata.createTime)
8591
8844
  };
8845
+ }
8846
+ /** Encodes a DbDocumentOverlay object to an Overlay model object. */
8847
+ function fromDbDocumentOverlay(localSerializer, dbDocumentOverlay) {
8848
+ return new Overlay(dbDocumentOverlay.largestBatchId, fromMutation(localSerializer.remoteSerializer, dbDocumentOverlay.overlayMutation));
8849
+ }
8850
+ /** Decodes an Overlay model object into a DbDocumentOverlay object. */
8851
+ function toDbDocumentOverlay(localSerializer, userId, overlay) {
8852
+ const [_, collectionPath, documentId] = toDbDocumentOverlayKey(userId, overlay.mutation.key);
8853
+ return new DbDocumentOverlay(userId, collectionPath, documentId, overlay.mutation.key.getCollectionGroup(), overlay.largestBatchId, toMutation(localSerializer.remoteSerializer, overlay.mutation));
8854
+ }
8855
+ /**
8856
+ * Returns the DbDocumentOverlayKey corresponding to the given user and
8857
+ * document key.
8858
+ */
8859
+ function toDbDocumentOverlayKey(userId, docKey) {
8860
+ const docId = docKey.path.lastSegment();
8861
+ const collectionPath = encodeResourcePath(docKey.path.popLast());
8862
+ return [userId, collectionPath, docId];
8863
+ }
8864
+ function toDbIndexConfiguration(index) {
8865
+ return new DbIndexConfiguration(index.indexId, index.collectionGroup, index.fields.map(s => [s.fieldPath.canonicalString(), s.kind]));
8866
+ }
8867
+ function fromDbIndexConfiguration(index, state) {
8868
+ const decodedState = state
8869
+ ? new IndexState(state.sequenceNumber, new IndexOffset(fromDbTimestamp(state.readTime), new DocumentKey(decodeResourcePath(state.documentKey)), state.largestBatchId))
8870
+ : IndexState.empty();
8871
+ const decodedSegments = index.fields.map(([fieldPath, kind]) => new IndexSegment(FieldPath$1.fromServerFormat(fieldPath), kind));
8872
+ return new FieldIndex(index.indexId, index.collectionGroup, decodedSegments, decodedState);
8873
+ }
8874
+ function toDbIndexState(indexId, user, sequenceNumber, offset) {
8875
+ return new DbIndexState(indexId, user.uid || '', sequenceNumber, toDbTimestamp(offset.readTime), encodeResourcePath(offset.documentKey.path), offset.largestBatchId);
8592
8876
  }
8593
8877
 
8594
8878
  /**
@@ -8648,6 +8932,125 @@ function namedQueriesStore(txn) {
8648
8932
  return getStore(txn, DbNamedQuery.store);
8649
8933
  }
8650
8934
 
8935
+ /**
8936
+ * @license
8937
+ * Copyright 2022 Google LLC
8938
+ *
8939
+ * Licensed under the Apache License, Version 2.0 (the "License");
8940
+ * you may not use this file except in compliance with the License.
8941
+ * You may obtain a copy of the License at
8942
+ *
8943
+ * http://www.apache.org/licenses/LICENSE-2.0
8944
+ *
8945
+ * Unless required by applicable law or agreed to in writing, software
8946
+ * distributed under the License is distributed on an "AS IS" BASIS,
8947
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8948
+ * See the License for the specific language governing permissions and
8949
+ * limitations under the License.
8950
+ */
8951
+ /**
8952
+ * Implementation of DocumentOverlayCache using IndexedDb.
8953
+ */
8954
+ class IndexedDbDocumentOverlayCache {
8955
+ /**
8956
+ * @param serializer - The document serializer.
8957
+ * @param userId - The userId for which we are accessing overlays.
8958
+ */
8959
+ constructor(serializer, userId) {
8960
+ this.serializer = serializer;
8961
+ this.userId = userId;
8962
+ }
8963
+ static forUser(serializer, user) {
8964
+ const userId = user.uid || '';
8965
+ return new IndexedDbDocumentOverlayCache(serializer, userId);
8966
+ }
8967
+ getOverlay(transaction, key) {
8968
+ return documentOverlayStore(transaction)
8969
+ .get(toDbDocumentOverlayKey(this.userId, key))
8970
+ .next(dbOverlay => {
8971
+ if (dbOverlay) {
8972
+ return fromDbDocumentOverlay(this.serializer, dbOverlay);
8973
+ }
8974
+ return null;
8975
+ });
8976
+ }
8977
+ saveOverlays(transaction, largestBatchId, overlays) {
8978
+ const promises = [];
8979
+ overlays.forEach(mutation => {
8980
+ const overlay = new Overlay(largestBatchId, mutation);
8981
+ promises.push(this.saveOverlay(transaction, overlay));
8982
+ });
8983
+ return PersistencePromise.waitFor(promises);
8984
+ }
8985
+ removeOverlaysForBatchId(transaction, documentKeys, batchId) {
8986
+ const collectionPaths = new Set();
8987
+ // Get the set of unique collection paths.
8988
+ documentKeys.forEach(key => collectionPaths.add(encodeResourcePath(key.getCollectionPath())));
8989
+ const promises = [];
8990
+ collectionPaths.forEach(collectionPath => {
8991
+ const range = IDBKeyRange.bound([this.userId, collectionPath, batchId], [this.userId, collectionPath, batchId + 1],
8992
+ /*lowerOpen=*/ false,
8993
+ /*upperOpen=*/ true);
8994
+ promises.push(documentOverlayStore(transaction).deleteAll(DbDocumentOverlay.collectionPathOverlayIndex, range));
8995
+ });
8996
+ return PersistencePromise.waitFor(promises);
8997
+ }
8998
+ getOverlaysForCollection(transaction, collection, sinceBatchId) {
8999
+ const result = new Map();
9000
+ const collectionPath = encodeResourcePath(collection);
9001
+ // We want batch IDs larger than `sinceBatchId`, and so the lower bound
9002
+ // is not inclusive.
9003
+ const range = IDBKeyRange.bound([this.userId, collectionPath, sinceBatchId], [this.userId, collectionPath, Number.POSITIVE_INFINITY],
9004
+ /*lowerOpen=*/ true);
9005
+ return documentOverlayStore(transaction)
9006
+ .loadAll(DbDocumentOverlay.collectionPathOverlayIndex, range)
9007
+ .next(dbOverlays => {
9008
+ for (const dbOverlay of dbOverlays) {
9009
+ const overlay = fromDbDocumentOverlay(this.serializer, dbOverlay);
9010
+ result.set(overlay.getKey(), overlay);
9011
+ }
9012
+ return result;
9013
+ });
9014
+ }
9015
+ getOverlaysForCollectionGroup(transaction, collectionGroup, sinceBatchId, count) {
9016
+ const result = new Map();
9017
+ let currentBatchId = undefined;
9018
+ // We want batch IDs larger than `sinceBatchId`, and so the lower bound
9019
+ // is not inclusive.
9020
+ const range = IDBKeyRange.bound([this.userId, collectionGroup, sinceBatchId], [this.userId, collectionGroup, Number.POSITIVE_INFINITY],
9021
+ /*lowerOpen=*/ true);
9022
+ return documentOverlayStore(transaction)
9023
+ .iterate({
9024
+ index: DbDocumentOverlay.collectionGroupOverlayIndex,
9025
+ range
9026
+ }, (_, dbOverlay, control) => {
9027
+ // We do not want to return partial batch overlays, even if the size
9028
+ // of the result set exceeds the given `count` argument. Therefore, we
9029
+ // continue to aggregate results even after the result size exceeds
9030
+ // `count` if there are more overlays from the `currentBatchId`.
9031
+ const overlay = fromDbDocumentOverlay(this.serializer, dbOverlay);
9032
+ if (result.size < count ||
9033
+ overlay.largestBatchId === currentBatchId) {
9034
+ result.set(overlay.getKey(), overlay);
9035
+ currentBatchId = overlay.largestBatchId;
9036
+ }
9037
+ else {
9038
+ control.done();
9039
+ }
9040
+ })
9041
+ .next(() => result);
9042
+ }
9043
+ saveOverlay(transaction, overlay) {
9044
+ return documentOverlayStore(transaction).put(toDbDocumentOverlay(this.serializer, this.userId, overlay));
9045
+ }
9046
+ }
9047
+ /**
9048
+ * Helper to get a typed SimpleDbStore for the document overlay object store.
9049
+ */
9050
+ function documentOverlayStore(txn) {
9051
+ return getStore(txn, DbDocumentOverlay.store);
9052
+ }
9053
+
8651
9054
  /**
8652
9055
  * @license
8653
9056
  * Copyright 2019 Google LLC
@@ -8678,6 +9081,38 @@ class MemoryIndexManager {
8678
9081
  getCollectionParents(transaction, collectionId) {
8679
9082
  return PersistencePromise.resolve(this.collectionParentIndex.getEntries(collectionId));
8680
9083
  }
9084
+ addFieldIndex(transaction, index) {
9085
+ // Field indices are not supported with memory persistence.
9086
+ return PersistencePromise.resolve();
9087
+ }
9088
+ deleteFieldIndex(transaction, index) {
9089
+ // Field indices are not supported with memory persistence.
9090
+ return PersistencePromise.resolve();
9091
+ }
9092
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9093
+ // Field indices are not supported with memory persistence.
9094
+ return PersistencePromise.resolve(documentKeySet());
9095
+ }
9096
+ getFieldIndex(transaction, target) {
9097
+ // Field indices are not supported with memory persistence.
9098
+ return PersistencePromise.resolve(null);
9099
+ }
9100
+ getFieldIndexes(transaction, collectionGroup) {
9101
+ // Field indices are not supported with memory persistence.
9102
+ return PersistencePromise.resolve([]);
9103
+ }
9104
+ getNextCollectionGroupToUpdate(transaction) {
9105
+ // Field indices are not supported with memory persistence.
9106
+ return PersistencePromise.resolve(null);
9107
+ }
9108
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9109
+ // Field indices are not supported with memory persistence.
9110
+ return PersistencePromise.resolve();
9111
+ }
9112
+ updateIndexEntries(transaction, documents) {
9113
+ // Field indices are not supported with memory persistence.
9114
+ return PersistencePromise.resolve();
9115
+ }
8681
9116
  }
8682
9117
  /**
8683
9118
  * Internal implementation of the collection-parent index exposed by MemoryIndexManager.
@@ -8729,17 +9164,22 @@ class MemoryCollectionParentIndex {
8729
9164
  */
8730
9165
  /**
8731
9166
  * A persisted implementation of IndexManager.
9167
+ *
9168
+ * PORTING NOTE: Unlike iOS and Android, the Web SDK does not memoize index
9169
+ * data as it supports multi-tab access.
8732
9170
  */
8733
9171
  class IndexedDbIndexManager {
8734
- constructor() {
9172
+ constructor(user) {
9173
+ this.user = user;
8735
9174
  /**
8736
9175
  * An in-memory copy of the index entries we've already written since the SDK
8737
9176
  * launched. Used to avoid re-writing the same entry repeatedly.
8738
9177
  *
8739
- * This is *NOT* a complete cache of what's in persistence and so can never be used to
8740
- * satisfy reads.
9178
+ * This is *NOT* a complete cache of what's in persistence and so can never be
9179
+ * used to satisfy reads.
8741
9180
  */
8742
9181
  this.collectionParentsCache = new MemoryCollectionParentIndex();
9182
+ this.uid = user.uid || '';
8743
9183
  }
8744
9184
  /**
8745
9185
  * Adds a new entry to the collection parent index.
@@ -8786,6 +9226,85 @@ class IndexedDbIndexManager {
8786
9226
  return parentPaths;
8787
9227
  });
8788
9228
  }
9229
+ addFieldIndex(transaction, index) {
9230
+ // TODO(indexing): Verify that the auto-incrementing index ID works in
9231
+ // Safari & Firefox.
9232
+ const indexes = indexConfigurationStore(transaction);
9233
+ const dbIndex = toDbIndexConfiguration(index);
9234
+ delete dbIndex.indexId; // `indexId` is auto-populated by IndexedDb
9235
+ return indexes.add(dbIndex).next();
9236
+ }
9237
+ deleteFieldIndex(transaction, index) {
9238
+ const indexes = indexConfigurationStore(transaction);
9239
+ const states = indexStateStore(transaction);
9240
+ const entries = indexEntriesStore(transaction);
9241
+ return indexes
9242
+ .delete(index.indexId)
9243
+ .next(() => states.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9244
+ /*lowerOpen=*/ false,
9245
+ /*upperOpen=*/ true)))
9246
+ .next(() => entries.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9247
+ /*lowerOpen=*/ false,
9248
+ /*upperOpen=*/ true)));
9249
+ }
9250
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9251
+ // TODO(indexing): Implement
9252
+ return PersistencePromise.resolve(documentKeySet());
9253
+ }
9254
+ getFieldIndex(transaction, target) {
9255
+ // TODO(indexing): Implement
9256
+ return PersistencePromise.resolve(null);
9257
+ }
9258
+ getFieldIndexes(transaction, collectionGroup) {
9259
+ const indexes = indexConfigurationStore(transaction);
9260
+ const states = indexStateStore(transaction);
9261
+ return (collectionGroup
9262
+ ? indexes.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9263
+ : indexes.loadAll()).next(indexConfigs => {
9264
+ const result = [];
9265
+ return PersistencePromise.forEach(indexConfigs, (indexConfig) => {
9266
+ return states
9267
+ .get([indexConfig.indexId, this.uid])
9268
+ .next(indexState => {
9269
+ result.push(fromDbIndexConfiguration(indexConfig, indexState));
9270
+ });
9271
+ }).next(() => result);
9272
+ });
9273
+ }
9274
+ getNextCollectionGroupToUpdate(transaction) {
9275
+ return this.getFieldIndexes(transaction).next(indexes => {
9276
+ if (indexes.length === 0) {
9277
+ return null;
9278
+ }
9279
+ indexes.sort((l, r) => l.indexState.sequenceNumber - r.indexState.sequenceNumber);
9280
+ return indexes[0].collectionGroup;
9281
+ });
9282
+ }
9283
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9284
+ const indexes = indexConfigurationStore(transaction);
9285
+ const states = indexStateStore(transaction);
9286
+ return this.getNextSequenceNumber(transaction).next(nextSequenceNumber => indexes
9287
+ .loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9288
+ .next(configs => PersistencePromise.forEach(configs, (config) => states.put(toDbIndexState(config.indexId, this.user, nextSequenceNumber, offset)))));
9289
+ }
9290
+ updateIndexEntries(transaction, documents) {
9291
+ // TODO(indexing): Implement
9292
+ return PersistencePromise.resolve();
9293
+ }
9294
+ getNextSequenceNumber(transaction) {
9295
+ let nextSequenceNumber = 1;
9296
+ const states = indexStateStore(transaction);
9297
+ return states
9298
+ .iterate({
9299
+ index: DbIndexState.sequenceNumberIndex,
9300
+ reverse: true,
9301
+ range: IDBKeyRange.upperBound([this.uid, Number.MAX_SAFE_INTEGER])
9302
+ }, (_, state, controller) => {
9303
+ controller.done();
9304
+ nextSequenceNumber = state.sequenceNumber + 1;
9305
+ })
9306
+ .next(() => nextSequenceNumber);
9307
+ }
8789
9308
  }
8790
9309
  /**
8791
9310
  * Helper to get a typed SimpleDbStore for the collectionParents
@@ -8793,6 +9312,24 @@ class IndexedDbIndexManager {
8793
9312
  */
8794
9313
  function collectionParentsStore(txn) {
8795
9314
  return getStore(txn, DbCollectionParent.store);
9315
+ }
9316
+ /**
9317
+ * Helper to get a typed SimpleDbStore for the index entry object store.
9318
+ */
9319
+ function indexEntriesStore(txn) {
9320
+ return getStore(txn, DbIndexEntry.store);
9321
+ }
9322
+ /**
9323
+ * Helper to get a typed SimpleDbStore for the index configuration object store.
9324
+ */
9325
+ function indexConfigurationStore(txn) {
9326
+ return getStore(txn, DbIndexConfiguration.store);
9327
+ }
9328
+ /**
9329
+ * Helper to get a typed SimpleDbStore for the index state object store.
9330
+ */
9331
+ function indexStateStore(txn) {
9332
+ return getStore(txn, DbIndexState.store);
8796
9333
  }
8797
9334
 
8798
9335
  /**
@@ -10262,12 +10799,10 @@ class RemoteDocumentChangeBuffer {
10262
10799
  * `newIndexedDbRemoteDocumentCache()`.
10263
10800
  */
10264
10801
  class IndexedDbRemoteDocumentCacheImpl {
10265
- /**
10266
- * @param serializer - The document serializer.
10267
- * @param indexManager - The query indexes that need to be maintained.
10268
- */
10269
- constructor(serializer, indexManager) {
10802
+ constructor(serializer) {
10270
10803
  this.serializer = serializer;
10804
+ }
10805
+ setIndexManager(indexManager) {
10271
10806
  this.indexManager = indexManager;
10272
10807
  }
10273
10808
  /**
@@ -10389,21 +10924,21 @@ class IndexedDbRemoteDocumentCacheImpl {
10389
10924
  }
10390
10925
  });
10391
10926
  }
10392
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
10927
+ getAll(transaction, collection, sinceReadTime) {
10393
10928
  let results = mutableDocumentMap();
10394
- const immediateChildrenPathLength = query.path.length + 1;
10929
+ const immediateChildrenPathLength = collection.length + 1;
10395
10930
  const iterationOptions = {};
10396
10931
  if (sinceReadTime.isEqual(SnapshotVersion.min())) {
10397
10932
  // Documents are ordered by key, so we can use a prefix scan to narrow
10398
10933
  // down the documents we need to match the query against.
10399
- const startKey = query.path.toArray();
10934
+ const startKey = collection.toArray();
10400
10935
  iterationOptions.range = IDBKeyRange.lowerBound(startKey);
10401
10936
  }
10402
10937
  else {
10403
10938
  // Execute an index-free query and filter by read time. This is safe
10404
10939
  // since all document changes to queries that have a
10405
10940
  // lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read time set.
10406
- const collectionKey = query.path.toArray();
10941
+ const collectionKey = collection.toArray();
10407
10942
  const readTimeKey = toDbTimestampKey(sinceReadTime);
10408
10943
  iterationOptions.range = IDBKeyRange.lowerBound([collectionKey, readTimeKey],
10409
10944
  /* open= */ true);
@@ -10420,12 +10955,12 @@ class IndexedDbRemoteDocumentCacheImpl {
10420
10955
  return;
10421
10956
  }
10422
10957
  const document = this.maybeDecodeDocument(DocumentKey.fromSegments(key), dbRemoteDoc);
10423
- if (!query.path.isPrefixOf(document.key.path)) {
10424
- control.done();
10425
- }
10426
- else if (queryMatches(query, document)) {
10958
+ if (collection.isPrefixOf(document.key.path)) {
10427
10959
  results = results.insert(document.key, document);
10428
10960
  }
10961
+ else {
10962
+ control.done();
10963
+ }
10429
10964
  })
10430
10965
  .next(() => results);
10431
10966
  }
@@ -10463,14 +10998,9 @@ class IndexedDbRemoteDocumentCacheImpl {
10463
10998
  return MutableDocument.newInvalidDocument(documentKey);
10464
10999
  }
10465
11000
  }
10466
- /**
10467
- * Creates a new IndexedDbRemoteDocumentCache.
10468
- *
10469
- * @param serializer - The document serializer.
10470
- * @param indexManager - The query indexes that need to be maintained.
10471
- */
10472
- function newIndexedDbRemoteDocumentCache(serializer, indexManager) {
10473
- return new IndexedDbRemoteDocumentCacheImpl(serializer, indexManager);
11001
+ /** Creates a new IndexedDbRemoteDocumentCache. */
11002
+ function newIndexedDbRemoteDocumentCache(serializer) {
11003
+ return new IndexedDbRemoteDocumentCacheImpl(serializer);
10474
11004
  }
10475
11005
  /**
10476
11006
  * Returns the set of documents that have changed since the specified read
@@ -10637,9 +11167,6 @@ class SchemaConverter {
10637
11167
  * and local feature development.
10638
11168
  */
10639
11169
  createOrUpgrade(db, txn, fromVersion, toVersion) {
10640
- hardAssert(fromVersion < toVersion &&
10641
- fromVersion >= 0 &&
10642
- toVersion <= SCHEMA_VERSION);
10643
11170
  const simpleDbTransaction = new SimpleDbTransaction('createOrUpgrade', txn);
10644
11171
  if (fromVersion < 1 && toVersion >= 1) {
10645
11172
  createPrimaryClientStore(db);
@@ -10706,6 +11233,16 @@ class SchemaConverter {
10706
11233
  createNamedQueriesStore(db);
10707
11234
  });
10708
11235
  }
11236
+ if (fromVersion < 12 && toVersion >= 12) {
11237
+ p = p.next(() => {
11238
+ createDocumentOverlayStore(db);
11239
+ });
11240
+ }
11241
+ if (fromVersion < 13 && toVersion >= 13) {
11242
+ p = p.next(() => {
11243
+ createFieldIndex(db);
11244
+ });
11245
+ }
10709
11246
  return p;
10710
11247
  }
10711
11248
  addDocumentGlobal(txn) {
@@ -10912,6 +11449,27 @@ function createNamedQueriesStore(db) {
10912
11449
  db.createObjectStore(DbNamedQuery.store, {
10913
11450
  keyPath: DbNamedQuery.keyPath
10914
11451
  });
11452
+ }
11453
+ function createFieldIndex(db) {
11454
+ const indexConfiguratioStore = db.createObjectStore(DbIndexConfiguration.store, {
11455
+ keyPath: DbIndexConfiguration.keyPath,
11456
+ autoIncrement: true
11457
+ });
11458
+ indexConfiguratioStore.createIndex(DbIndexConfiguration.collectionGroupIndex, DbIndexConfiguration.collectionGroupIndexPath, { unique: false });
11459
+ const indexStateStore = db.createObjectStore(DbIndexState.store, {
11460
+ keyPath: DbIndexState.keyPath
11461
+ });
11462
+ indexStateStore.createIndex(DbIndexState.sequenceNumberIndex, DbIndexState.sequenceNumberIndexPath, { unique: false });
11463
+ db.createObjectStore(DbIndexEntry.store, {
11464
+ keyPath: DbIndexEntry.keyPath
11465
+ });
11466
+ }
11467
+ function createDocumentOverlayStore(db) {
11468
+ const documentOverlayStore = db.createObjectStore(DbDocumentOverlay.store, {
11469
+ keyPath: DbDocumentOverlay.keyPath
11470
+ });
11471
+ documentOverlayStore.createIndex(DbDocumentOverlay.collectionPathOverlayIndex, DbDocumentOverlay.collectionPathOverlayIndexPath, { unique: false });
11472
+ documentOverlayStore.createIndex(DbDocumentOverlay.collectionGroupOverlayIndex, DbDocumentOverlay.collectionGroupOverlayIndexPath, { unique: false });
10915
11473
  }
10916
11474
 
10917
11475
  /**
@@ -11023,7 +11581,7 @@ class IndexedDbPersistence {
11023
11581
  * If set to true, forcefully obtains database access. Existing tabs will
11024
11582
  * no longer be able to access IndexedDB.
11025
11583
  */
11026
- forceOwningTab) {
11584
+ forceOwningTab, schemaVersion = SCHEMA_VERSION) {
11027
11585
  this.allowTabSynchronization = allowTabSynchronization;
11028
11586
  this.persistenceKey = persistenceKey;
11029
11587
  this.clientId = clientId;
@@ -11032,6 +11590,7 @@ class IndexedDbPersistence {
11032
11590
  this.document = document;
11033
11591
  this.sequenceNumberSyncer = sequenceNumberSyncer;
11034
11592
  this.forceOwningTab = forceOwningTab;
11593
+ this.schemaVersion = schemaVersion;
11035
11594
  this.listenSequence = null;
11036
11595
  this._started = false;
11037
11596
  this.isPrimary = false;
@@ -11053,10 +11612,9 @@ class IndexedDbPersistence {
11053
11612
  this.referenceDelegate = new IndexedDbLruDelegateImpl(this, lruParams);
11054
11613
  this.dbName = persistenceKey + MAIN_DATABASE;
11055
11614
  this.serializer = new LocalSerializer(serializer);
11056
- this.simpleDb = new SimpleDb(this.dbName, SCHEMA_VERSION, new SchemaConverter(this.serializer));
11615
+ this.simpleDb = new SimpleDb(this.dbName, this.schemaVersion, new SchemaConverter(this.serializer));
11057
11616
  this.targetCache = new IndexedDbTargetCache(this.referenceDelegate, this.serializer);
11058
- this.indexManager = new IndexedDbIndexManager();
11059
- this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer, this.indexManager);
11617
+ this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer);
11060
11618
  this.bundleCache = new IndexedDbBundleCache();
11061
11619
  if (this.window && this.window.localStorage) {
11062
11620
  this.webStorage = this.window.localStorage;
@@ -11392,8 +11950,8 @@ class IndexedDbPersistence {
11392
11950
  get started() {
11393
11951
  return this._started;
11394
11952
  }
11395
- getMutationQueue(user) {
11396
- return IndexedDbMutationQueue.forUser(user, this.serializer, this.indexManager, this.referenceDelegate);
11953
+ getMutationQueue(user, indexManager) {
11954
+ return IndexedDbMutationQueue.forUser(user, this.serializer, indexManager, this.referenceDelegate);
11397
11955
  }
11398
11956
  getTargetCache() {
11399
11957
  return this.targetCache;
@@ -11401,8 +11959,11 @@ class IndexedDbPersistence {
11401
11959
  getRemoteDocumentCache() {
11402
11960
  return this.remoteDocumentCache;
11403
11961
  }
11404
- getIndexManager() {
11405
- return this.indexManager;
11962
+ getIndexManager(user) {
11963
+ return new IndexedDbIndexManager(user);
11964
+ }
11965
+ getDocumentOverlayCache(user) {
11966
+ return IndexedDbDocumentOverlayCache.forUser(this.serializer, user);
11406
11967
  }
11407
11968
  getBundleCache() {
11408
11969
  return this.bundleCache;
@@ -11410,11 +11971,12 @@ class IndexedDbPersistence {
11410
11971
  runTransaction(action, mode, transactionOperation) {
11411
11972
  logDebug(LOG_TAG$d, 'Starting transaction:', action);
11412
11973
  const simpleDbMode = mode === 'readonly' ? 'readonly' : 'readwrite';
11974
+ const objectStores = getObjectStores(this.schemaVersion);
11413
11975
  let persistenceTransaction;
11414
11976
  // Do all transactions as readwrite against all object stores, since we
11415
11977
  // are the only reader/writer.
11416
11978
  return this.simpleDb
11417
- .runTransaction(action, simpleDbMode, ALL_STORES, simpleDbTxn => {
11979
+ .runTransaction(action, simpleDbMode, objectStores, simpleDbTxn => {
11418
11980
  persistenceTransaction = new IndexedDbTransaction(simpleDbTxn, this.listenSequence
11419
11981
  ? this.listenSequence.next()
11420
11982
  : ListenSequence.INVALID);
@@ -11786,39 +12348,28 @@ class LocalDocumentsView {
11786
12348
  getDocumentsMatchingCollectionQuery(transaction, query, sinceReadTime) {
11787
12349
  // Query the remote documents and overlay mutations.
11788
12350
  let results;
11789
- let mutationBatches;
11790
12351
  return this.remoteDocumentCache
11791
- .getDocumentsMatchingQuery(transaction, query, sinceReadTime)
12352
+ .getAll(transaction, query.path, sinceReadTime)
11792
12353
  .next(queryResults => {
11793
12354
  results = queryResults;
11794
12355
  return this.mutationQueue.getAllMutationBatchesAffectingQuery(transaction, query);
11795
12356
  })
11796
- .next(matchingMutationBatches => {
11797
- mutationBatches = matchingMutationBatches;
11798
- // It is possible that a PatchMutation can make a document match a query, even if
11799
- // the version in the RemoteDocumentCache is not a match yet (waiting for server
11800
- // to ack). To handle this, we find all document keys affected by the PatchMutations
11801
- // that are not in `result` yet, and back fill them via `remoteDocumentCache.getEntries`,
11802
- // otherwise those `PatchMutations` will be ignored because no base document can be found,
11803
- // and lead to missing result for the query.
11804
- return this.addMissingBaseDocuments(transaction, mutationBatches, results).next(mergedDocuments => {
11805
- results = mergedDocuments;
11806
- for (const batch of mutationBatches) {
11807
- for (const mutation of batch.mutations) {
11808
- const key = mutation.key;
11809
- let document = results.get(key);
11810
- if (document == null) {
11811
- // Create invalid document to apply mutations on top of
11812
- document = MutableDocument.newInvalidDocument(key);
11813
- results = results.insert(key, document);
11814
- }
11815
- mutationApplyToLocalView(mutation, document, batch.localWriteTime);
11816
- if (!document.isFoundDocument()) {
11817
- results = results.remove(key);
11818
- }
12357
+ .next(mutationBatches => {
12358
+ for (const batch of mutationBatches) {
12359
+ for (const mutation of batch.mutations) {
12360
+ const key = mutation.key;
12361
+ let document = results.get(key);
12362
+ if (document == null) {
12363
+ // Create invalid document to apply mutations on top of
12364
+ document = MutableDocument.newInvalidDocument(key);
12365
+ results = results.insert(key, document);
12366
+ }
12367
+ mutationApplyToLocalView(mutation, document, batch.localWriteTime);
12368
+ if (!document.isFoundDocument()) {
12369
+ results = results.remove(key);
11819
12370
  }
11820
12371
  }
11821
- });
12372
+ }
11822
12373
  })
11823
12374
  .next(() => {
11824
12375
  // Finally, filter out any documents that don't actually match
@@ -11831,29 +12382,6 @@ class LocalDocumentsView {
11831
12382
  return results;
11832
12383
  });
11833
12384
  }
11834
- addMissingBaseDocuments(transaction, matchingMutationBatches, existingDocuments) {
11835
- let missingBaseDocEntriesForPatching = documentKeySet();
11836
- for (const batch of matchingMutationBatches) {
11837
- for (const mutation of batch.mutations) {
11838
- if (mutation instanceof PatchMutation &&
11839
- existingDocuments.get(mutation.key) === null) {
11840
- missingBaseDocEntriesForPatching =
11841
- missingBaseDocEntriesForPatching.add(mutation.key);
11842
- }
11843
- }
11844
- }
11845
- let mergedDocuments = existingDocuments;
11846
- return this.remoteDocumentCache
11847
- .getEntries(transaction, missingBaseDocEntriesForPatching)
11848
- .next(missingBaseDocs => {
11849
- missingBaseDocs.forEach((key, doc) => {
11850
- if (doc.isFoundDocument()) {
11851
- mergedDocuments = mergedDocuments.insert(key, doc);
11852
- }
11853
- });
11854
- return mergedDocuments;
11855
- });
11856
- }
11857
12385
  }
11858
12386
 
11859
12387
  /**
@@ -11912,11 +12440,18 @@ class LocalStoreImpl {
11912
12440
  * PORTING NOTE: This is only used for multi-tab synchronization.
11913
12441
  */
11914
12442
  this.lastDocumentChangeReadTime = SnapshotVersion.min();
11915
- this.mutationQueue = persistence.getMutationQueue(initialUser);
11916
12443
  this.remoteDocuments = persistence.getRemoteDocumentCache();
11917
12444
  this.targetCache = persistence.getTargetCache();
11918
- this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.persistence.getIndexManager());
11919
12445
  this.bundleCache = persistence.getBundleCache();
12446
+ this.initializeUserComponents(initialUser);
12447
+ }
12448
+ initializeUserComponents(user) {
12449
+ // TODO(indexing): Add spec tests that test these components change after a
12450
+ // user change
12451
+ this.indexManager = this.persistence.getIndexManager(user);
12452
+ this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
12453
+ this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
12454
+ this.remoteDocuments.setIndexManager(this.indexManager);
11920
12455
  this.queryEngine.setLocalDocumentsView(this.localDocuments);
11921
12456
  }
11922
12457
  collectGarbage(garbageCollector) {
@@ -11938,8 +12473,6 @@ persistence, queryEngine, initialUser, serializer) {
11938
12473
  // change.
11939
12474
  async function localStoreHandleUserChange(localStore, user) {
11940
12475
  const localStoreImpl = debugCast(localStore);
11941
- let newMutationQueue = localStoreImpl.mutationQueue;
11942
- let newLocalDocuments = localStoreImpl.localDocuments;
11943
12476
  const result = await localStoreImpl.persistence.runTransaction('Handle user change', 'readonly', txn => {
11944
12477
  // Swap out the mutation queue, grabbing the pending mutation batches
11945
12478
  // before and after.
@@ -11948,11 +12481,8 @@ async function localStoreHandleUserChange(localStore, user) {
11948
12481
  .getAllMutationBatches(txn)
11949
12482
  .next(promisedOldBatches => {
11950
12483
  oldBatches = promisedOldBatches;
11951
- newMutationQueue = localStoreImpl.persistence.getMutationQueue(user);
11952
- // Recreate our LocalDocumentsView using the new
11953
- // MutationQueue.
11954
- newLocalDocuments = new LocalDocumentsView(localStoreImpl.remoteDocuments, newMutationQueue, localStoreImpl.persistence.getIndexManager());
11955
- return newMutationQueue.getAllMutationBatches(txn);
12484
+ localStoreImpl.initializeUserComponents(user);
12485
+ return localStoreImpl.mutationQueue.getAllMutationBatches(txn);
11956
12486
  })
11957
12487
  .next(newBatches => {
11958
12488
  const removedBatchIds = [];
@@ -11973,7 +12503,7 @@ async function localStoreHandleUserChange(localStore, user) {
11973
12503
  }
11974
12504
  // Return the set of all (potentially) changed documents and the list
11975
12505
  // of mutation batch IDs that were affected by change.
11976
- return newLocalDocuments
12506
+ return localStoreImpl.localDocuments
11977
12507
  .getDocuments(txn, changedKeys)
11978
12508
  .next(affectedDocuments => {
11979
12509
  return {
@@ -11984,9 +12514,6 @@ async function localStoreHandleUserChange(localStore, user) {
11984
12514
  });
11985
12515
  });
11986
12516
  });
11987
- localStoreImpl.mutationQueue = newMutationQueue;
11988
- localStoreImpl.localDocuments = newLocalDocuments;
11989
- localStoreImpl.queryEngine.setLocalDocumentsView(localStoreImpl.localDocuments);
11990
12517
  return result;
11991
12518
  }
11992
12519
  /* Accepts locally generated Mutations and commit them to storage. */
@@ -12699,6 +13226,122 @@ class MemoryBundleCache {
12699
13226
  }
12700
13227
  }
12701
13228
 
13229
+ /**
13230
+ * @license
13231
+ * Copyright 2022 Google LLC
13232
+ *
13233
+ * Licensed under the Apache License, Version 2.0 (the "License");
13234
+ * you may not use this file except in compliance with the License.
13235
+ * You may obtain a copy of the License at
13236
+ *
13237
+ * http://www.apache.org/licenses/LICENSE-2.0
13238
+ *
13239
+ * Unless required by applicable law or agreed to in writing, software
13240
+ * distributed under the License is distributed on an "AS IS" BASIS,
13241
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13242
+ * See the License for the specific language governing permissions and
13243
+ * limitations under the License.
13244
+ */
13245
+ /**
13246
+ * An in-memory implementation of DocumentOverlayCache.
13247
+ */
13248
+ class MemoryDocumentOverlayCache {
13249
+ constructor() {
13250
+ // A map sorted by DocumentKey, whose value is a pair of the largest batch id
13251
+ // for the overlay and the overlay itself.
13252
+ this.overlays = new SortedMap(DocumentKey.comparator);
13253
+ this.overlayByBatchId = new Map();
13254
+ }
13255
+ getOverlay(transaction, key) {
13256
+ return PersistencePromise.resolve(this.overlays.get(key));
13257
+ }
13258
+ saveOverlays(transaction, largestBatchId, overlays) {
13259
+ overlays.forEach(mutation => {
13260
+ this.saveOverlay(transaction, largestBatchId, mutation);
13261
+ });
13262
+ return PersistencePromise.resolve();
13263
+ }
13264
+ removeOverlaysForBatchId(transaction, documentKeys, batchId) {
13265
+ const keys = this.overlayByBatchId.get(batchId);
13266
+ if (keys !== undefined) {
13267
+ keys.forEach(key => (this.overlays = this.overlays.remove(key)));
13268
+ this.overlayByBatchId.delete(batchId);
13269
+ }
13270
+ return PersistencePromise.resolve();
13271
+ }
13272
+ getOverlaysForCollection(transaction, collection, sinceBatchId) {
13273
+ const result = new Map();
13274
+ const immediateChildrenPathLength = collection.length + 1;
13275
+ const prefix = new DocumentKey(collection.child(''));
13276
+ const iter = this.overlays.getIteratorFrom(prefix);
13277
+ while (iter.hasNext()) {
13278
+ const entry = iter.getNext();
13279
+ const overlay = entry.value;
13280
+ const key = overlay.getKey();
13281
+ if (!collection.isPrefixOf(key.path)) {
13282
+ break;
13283
+ }
13284
+ // Documents from sub-collections
13285
+ if (key.path.length !== immediateChildrenPathLength) {
13286
+ continue;
13287
+ }
13288
+ if (overlay.largestBatchId > sinceBatchId) {
13289
+ result.set(overlay.getKey(), overlay);
13290
+ }
13291
+ }
13292
+ return PersistencePromise.resolve(result);
13293
+ }
13294
+ getOverlaysForCollectionGroup(transaction, collectionGroup, sinceBatchId, count) {
13295
+ let batchIdToOverlays = new SortedMap((key1, key2) => key1 - key2);
13296
+ const iter = this.overlays.getIterator();
13297
+ while (iter.hasNext()) {
13298
+ const entry = iter.getNext();
13299
+ const overlay = entry.value;
13300
+ const key = overlay.getKey();
13301
+ if (key.getCollectionGroup() !== collectionGroup) {
13302
+ continue;
13303
+ }
13304
+ if (overlay.largestBatchId > sinceBatchId) {
13305
+ let overlaysForBatchId = batchIdToOverlays.get(overlay.largestBatchId);
13306
+ if (overlaysForBatchId === null) {
13307
+ overlaysForBatchId = new Map();
13308
+ batchIdToOverlays = batchIdToOverlays.insert(overlay.largestBatchId, overlaysForBatchId);
13309
+ }
13310
+ overlaysForBatchId.set(overlay.getKey(), overlay);
13311
+ }
13312
+ }
13313
+ const result = new Map();
13314
+ const batchIter = batchIdToOverlays.getIterator();
13315
+ while (batchIter.hasNext()) {
13316
+ const entry = batchIter.getNext();
13317
+ const overlays = entry.value;
13318
+ overlays.forEach((overlay, key) => result.set(key, overlay));
13319
+ if (result.size >= count) {
13320
+ break;
13321
+ }
13322
+ }
13323
+ return PersistencePromise.resolve(result);
13324
+ }
13325
+ saveOverlay(transaction, largestBatchId, mutation) {
13326
+ if (mutation === null) {
13327
+ return;
13328
+ }
13329
+ // Remove the association of the overlay to its batch id.
13330
+ const existing = this.overlays.get(mutation.key);
13331
+ if (existing !== null) {
13332
+ this.overlayByBatchId.get(existing.largestBatchId).delete(mutation.key);
13333
+ }
13334
+ this.overlays = this.overlays.insert(mutation.key, new Overlay(largestBatchId, mutation));
13335
+ // Create the association of this overlay to the given largestBatchId.
13336
+ let batch = this.overlayByBatchId.get(largestBatchId);
13337
+ if (batch === undefined) {
13338
+ batch = new Set();
13339
+ this.overlayByBatchId.set(largestBatchId, batch);
13340
+ }
13341
+ batch.add(mutation.key);
13342
+ }
13343
+ }
13344
+
12702
13345
  /**
12703
13346
  * @license
12704
13347
  * Copyright 2017 Google LLC
@@ -13052,14 +13695,16 @@ class MemoryRemoteDocumentCacheImpl {
13052
13695
  * expected to just return 0 to avoid unnecessarily doing the work of
13053
13696
  * calculating the size.
13054
13697
  */
13055
- constructor(indexManager, sizer) {
13056
- this.indexManager = indexManager;
13698
+ constructor(sizer) {
13057
13699
  this.sizer = sizer;
13058
13700
  /** Underlying cache of documents and their read times. */
13059
13701
  this.docs = documentEntryMap();
13060
13702
  /** Size of all cached documents. */
13061
13703
  this.size = 0;
13062
13704
  }
13705
+ setIndexManager(indexManager) {
13706
+ this.indexManager = indexManager;
13707
+ }
13063
13708
  /**
13064
13709
  * Adds the supplied entry to the cache and updates the cache size as appropriate.
13065
13710
  *
@@ -13107,21 +13752,22 @@ class MemoryRemoteDocumentCacheImpl {
13107
13752
  });
13108
13753
  return PersistencePromise.resolve(results);
13109
13754
  }
13110
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
13755
+ getAll(transaction, collectionPath, sinceReadTime) {
13111
13756
  let results = mutableDocumentMap();
13112
13757
  // Documents are ordered by key, so we can use a prefix scan to narrow down
13113
13758
  // the documents we need to match the query against.
13114
- const prefix = new DocumentKey(query.path.child(''));
13759
+ const prefix = new DocumentKey(collectionPath.child(''));
13115
13760
  const iterator = this.docs.getIteratorFrom(prefix);
13116
13761
  while (iterator.hasNext()) {
13117
13762
  const { key, value: { document } } = iterator.getNext();
13118
- if (!query.path.isPrefixOf(key.path)) {
13763
+ if (!collectionPath.isPrefixOf(key.path)) {
13119
13764
  break;
13120
13765
  }
13121
- if (document.readTime.compareTo(sinceReadTime) <= 0) {
13766
+ if (key.path.length > collectionPath.length + 1) {
13767
+ // Exclude entries from subcollections.
13122
13768
  continue;
13123
13769
  }
13124
- if (!queryMatches(query, document)) {
13770
+ if (document.readTime.compareTo(sinceReadTime) <= 0) {
13125
13771
  continue;
13126
13772
  }
13127
13773
  results = results.insert(document.key, document.mutableCopy());
@@ -13143,13 +13789,12 @@ class MemoryRemoteDocumentCacheImpl {
13143
13789
  /**
13144
13790
  * Creates a new memory-only RemoteDocumentCache.
13145
13791
  *
13146
- * @param indexManager - A class that manages collection group indices.
13147
13792
  * @param sizer - Used to assess the size of a document. For eager GC, this is
13148
13793
  * expected to just return 0 to avoid unnecessarily doing the work of
13149
13794
  * calculating the size.
13150
13795
  */
13151
- function newMemoryRemoteDocumentCache(indexManager, sizer) {
13152
- return new MemoryRemoteDocumentCacheImpl(indexManager, sizer);
13796
+ function newMemoryRemoteDocumentCache(sizer) {
13797
+ return new MemoryRemoteDocumentCacheImpl(sizer);
13153
13798
  }
13154
13799
  /**
13155
13800
  * Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
@@ -13343,6 +13988,7 @@ class MemoryPersistence {
13343
13988
  */
13344
13989
  constructor(referenceDelegateFactory, serializer) {
13345
13990
  this.mutationQueues = {};
13991
+ this.overlays = {};
13346
13992
  this.listenSequence = new ListenSequence(0);
13347
13993
  this._started = false;
13348
13994
  this._started = true;
@@ -13350,7 +13996,7 @@ class MemoryPersistence {
13350
13996
  this.targetCache = new MemoryTargetCache(this);
13351
13997
  const sizer = (doc) => this.referenceDelegate.documentSize(doc);
13352
13998
  this.indexManager = new MemoryIndexManager();
13353
- this.remoteDocumentCache = newMemoryRemoteDocumentCache(this.indexManager, sizer);
13999
+ this.remoteDocumentCache = newMemoryRemoteDocumentCache(sizer);
13354
14000
  this.serializer = new LocalSerializer(serializer);
13355
14001
  this.bundleCache = new MemoryBundleCache(this.serializer);
13356
14002
  }
@@ -13371,13 +14017,23 @@ class MemoryPersistence {
13371
14017
  setNetworkEnabled() {
13372
14018
  // No op.
13373
14019
  }
13374
- getIndexManager() {
14020
+ getIndexManager(user) {
14021
+ // We do not currently support indices for memory persistence, so we can
14022
+ // return the same shared instance of the memory index manager.
13375
14023
  return this.indexManager;
13376
14024
  }
13377
- getMutationQueue(user) {
14025
+ getDocumentOverlayCache(user) {
14026
+ let overlay = this.overlays[user.toKey()];
14027
+ if (!overlay) {
14028
+ overlay = new MemoryDocumentOverlayCache();
14029
+ this.overlays[user.toKey()] = overlay;
14030
+ }
14031
+ return overlay;
14032
+ }
14033
+ getMutationQueue(user, indexManager) {
13378
14034
  let queue = this.mutationQueues[user.toKey()];
13379
14035
  if (!queue) {
13380
- queue = new MemoryMutationQueue(this.indexManager, this.referenceDelegate);
14036
+ queue = new MemoryMutationQueue(indexManager, this.referenceDelegate);
13381
14037
  this.mutationQueues[user.toKey()] = queue;
13382
14038
  }
13383
14039
  return queue;
@@ -20340,12 +20996,12 @@ async function syncEngineListen(syncEngine, query) {
20340
20996
  }
20341
20997
  else {
20342
20998
  const targetData = await localStoreAllocateTarget(syncEngineImpl.localStore, queryToTarget(query));
20343
- const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
20344
- targetId = targetData.targetId;
20345
- viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20346
20999
  if (syncEngineImpl.isPrimaryClient) {
20347
21000
  remoteStoreListen(syncEngineImpl.remoteStore, targetData);
20348
21001
  }
21002
+ const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
21003
+ targetId = targetData.targetId;
21004
+ viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20349
21005
  }
20350
21006
  return viewSnapshot;
20351
21007
  }
@@ -24853,8 +25509,7 @@ class DocumentSnapshot extends DocumentSnapshot$1 {
24853
25509
  this.metadata = metadata;
24854
25510
  }
24855
25511
  /**
24856
- * Property of the `DocumentSnapshot` that signals whether or not the data
24857
- * exists. True if the document exists.
25512
+ * Returns whether or not the data exists. True if the document exists.
24858
25513
  */
24859
25514
  exists() {
24860
25515
  return super.exists();
@@ -25228,51 +25883,53 @@ function limitToLast(limit) {
25228
25883
  return new QueryLimitConstraint('limitToLast', limit, "L" /* Last */);
25229
25884
  }
25230
25885
  class QueryStartAtConstraint extends QueryConstraint {
25231
- constructor(type, _docOrFields, _before) {
25886
+ constructor(type, _docOrFields, _inclusive) {
25232
25887
  super();
25233
25888
  this.type = type;
25234
25889
  this._docOrFields = _docOrFields;
25235
- this._before = _before;
25890
+ this._inclusive = _inclusive;
25236
25891
  }
25237
25892
  _apply(query) {
25238
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25893
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25239
25894
  return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
25240
25895
  }
25241
25896
  }
25242
25897
  function startAt(...docOrFields) {
25243
- return new QueryStartAtConstraint('startAt', docOrFields, /*before=*/ true);
25898
+ return new QueryStartAtConstraint('startAt', docOrFields,
25899
+ /*inclusive=*/ true);
25244
25900
  }
25245
25901
  function startAfter(...docOrFields) {
25246
25902
  return new QueryStartAtConstraint('startAfter', docOrFields,
25247
- /*before=*/ false);
25903
+ /*inclusive=*/ false);
25248
25904
  }
25249
25905
  class QueryEndAtConstraint extends QueryConstraint {
25250
- constructor(type, _docOrFields, _before) {
25906
+ constructor(type, _docOrFields, _inclusive) {
25251
25907
  super();
25252
25908
  this.type = type;
25253
25909
  this._docOrFields = _docOrFields;
25254
- this._before = _before;
25910
+ this._inclusive = _inclusive;
25255
25911
  }
25256
25912
  _apply(query) {
25257
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25913
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25258
25914
  return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
25259
25915
  }
25260
25916
  }
25261
25917
  function endBefore(...docOrFields) {
25262
- return new QueryEndAtConstraint('endBefore', docOrFields, /*before=*/ true);
25918
+ return new QueryEndAtConstraint('endBefore', docOrFields,
25919
+ /*inclusive=*/ false);
25263
25920
  }
25264
25921
  function endAt(...docOrFields) {
25265
- return new QueryEndAtConstraint('endAt', docOrFields, /*before=*/ false);
25922
+ return new QueryEndAtConstraint('endAt', docOrFields, /*inclusive=*/ true);
25266
25923
  }
25267
25924
  /** Helper function to create a bound from a document or fields */
25268
- function newQueryBoundFromDocOrFields(query, methodName, docOrFields, before) {
25925
+ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
25269
25926
  docOrFields[0] = getModularInstance(docOrFields[0]);
25270
25927
  if (docOrFields[0] instanceof DocumentSnapshot$1) {
25271
- return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, before);
25928
+ return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive);
25272
25929
  }
25273
25930
  else {
25274
25931
  const reader = newUserDataReader(query.firestore);
25275
- return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, before);
25932
+ return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive);
25276
25933
  }
25277
25934
  }
25278
25935
  function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
@@ -25330,7 +25987,7 @@ function newQueryOrderBy(query, fieldPath, direction) {
25330
25987
  * of the query or if any of the fields in the order by are an uncommitted
25331
25988
  * server timestamp.
25332
25989
  */
25333
- function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25990
+ function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) {
25334
25991
  if (!doc) {
25335
25992
  throw new FirestoreError(Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` +
25336
25993
  `${methodName}().`);
@@ -25367,12 +26024,12 @@ function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25367
26024
  }
25368
26025
  }
25369
26026
  }
25370
- return new Bound(components, before);
26027
+ return new Bound(components, inclusive);
25371
26028
  }
25372
26029
  /**
25373
26030
  * Converts a list of field values to a `Bound` for the given query.
25374
26031
  */
25375
- function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, before) {
26032
+ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) {
25376
26033
  // Use explicit order by's because it has to match the query the user made
25377
26034
  const orderBy = query.explicitOrderBy;
25378
26035
  if (values.length > orderBy.length) {
@@ -25409,7 +26066,7 @@ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, valu
25409
26066
  components.push(wrapped);
25410
26067
  }
25411
26068
  }
25412
- return new Bound(components, before);
26069
+ return new Bound(components, inclusive);
25413
26070
  }
25414
26071
  /**
25415
26072
  * Parses the given `documentIdValue` into a `ReferenceValue`, throwing