@firebase/firestore 3.4.4-canary.b20cf306a → 3.4.4-canary.bb8f37c3e

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 (132) 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/index_manager.d.ts +52 -0
  6. package/dist/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  7. package/dist/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  8. package/dist/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  9. package/dist/firestore/src/local/indexeddb_schema.d.ts +149 -7
  10. package/dist/firestore/src/local/local_documents_view.d.ts +0 -1
  11. package/dist/firestore/src/local/local_serializer.d.ts +7 -2
  12. package/dist/firestore/src/local/memory_index_manager.d.ts +11 -0
  13. package/dist/firestore/src/local/memory_persistence.d.ts +3 -2
  14. package/dist/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  15. package/dist/firestore/src/local/persistence.d.ts +2 -2
  16. package/dist/firestore/src/local/remote_document_cache.d.ts +7 -9
  17. package/dist/firestore/src/local/simple_db.d.ts +1 -0
  18. package/dist/firestore/src/model/field_index.d.ts +2 -2
  19. package/dist/firestore/src/model/target_index_matcher.d.ts +70 -0
  20. package/dist/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  21. package/dist/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  22. package/dist/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  23. package/dist/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  24. package/dist/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  25. package/dist/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  26. package/dist/firestore/test/util/helpers.d.ts +1 -1
  27. package/dist/index.d.ts +1 -2
  28. package/dist/index.esm2017.js +3373 -3129
  29. package/dist/index.esm2017.js.map +1 -1
  30. package/dist/index.esm5.js +3823 -3602
  31. package/dist/index.esm5.js.map +1 -1
  32. package/dist/index.node.cjs.js +506 -220
  33. package/dist/index.node.cjs.js.map +1 -1
  34. package/dist/index.node.mjs +506 -220
  35. package/dist/index.node.mjs.map +1 -1
  36. package/dist/index.rn.js +3623 -3379
  37. package/dist/index.rn.js.map +1 -1
  38. package/dist/internal.d.ts +178 -14
  39. package/dist/lite/firestore/src/api/credentials.d.ts +1 -0
  40. package/dist/lite/firestore/src/api/snapshot.d.ts +1 -2
  41. package/dist/lite/firestore/src/core/target.d.ts +8 -4
  42. package/dist/lite/firestore/src/lite-api/query.d.ts +2 -2
  43. package/dist/lite/firestore/src/local/index_manager.d.ts +52 -0
  44. package/dist/lite/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  45. package/dist/lite/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  46. package/dist/lite/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  47. package/dist/lite/firestore/src/local/indexeddb_schema.d.ts +149 -7
  48. package/dist/lite/firestore/src/local/local_documents_view.d.ts +0 -1
  49. package/dist/lite/firestore/src/local/local_serializer.d.ts +7 -2
  50. package/dist/lite/firestore/src/local/memory_index_manager.d.ts +11 -0
  51. package/dist/lite/firestore/src/local/memory_persistence.d.ts +3 -2
  52. package/dist/lite/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  53. package/dist/lite/firestore/src/local/persistence.d.ts +2 -2
  54. package/dist/lite/firestore/src/local/remote_document_cache.d.ts +7 -9
  55. package/dist/lite/firestore/src/local/simple_db.d.ts +1 -0
  56. package/dist/lite/firestore/src/model/field_index.d.ts +2 -2
  57. package/dist/lite/firestore/src/model/target_index_matcher.d.ts +70 -0
  58. package/dist/lite/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  59. package/dist/lite/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  60. package/dist/lite/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  61. package/dist/lite/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  62. package/dist/lite/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  63. package/dist/lite/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  64. package/dist/lite/firestore/test/util/helpers.d.ts +1 -1
  65. package/dist/lite/index.browser.esm2017.js +1146 -1143
  66. package/dist/lite/index.browser.esm2017.js.map +1 -1
  67. package/dist/lite/index.browser.esm5.js +332 -331
  68. package/dist/lite/index.browser.esm5.js.map +1 -1
  69. package/dist/lite/index.node.cjs.js +36 -29
  70. package/dist/lite/index.node.cjs.js.map +1 -1
  71. package/dist/lite/index.node.mjs +36 -29
  72. package/dist/lite/index.node.mjs.map +1 -1
  73. package/dist/lite/index.rn.esm2017.js +301 -298
  74. package/dist/lite/index.rn.esm2017.js.map +1 -1
  75. package/dist/lite/internal.d.ts +2 -2
  76. package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +121 -121
  77. package/dist/lite/packages/firestore/src/api/credentials.d.ts +1 -0
  78. package/dist/lite/packages/firestore/src/api/snapshot.d.ts +1 -2
  79. package/dist/lite/packages/firestore/src/core/target.d.ts +8 -4
  80. package/dist/lite/packages/firestore/src/lite-api/query.d.ts +2 -2
  81. package/dist/lite/packages/firestore/src/local/index_manager.d.ts +52 -0
  82. package/dist/lite/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  83. package/dist/lite/packages/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  84. package/dist/lite/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  85. package/dist/lite/packages/firestore/src/local/indexeddb_schema.d.ts +149 -7
  86. package/dist/lite/packages/firestore/src/local/local_documents_view.d.ts +0 -1
  87. package/dist/lite/packages/firestore/src/local/local_serializer.d.ts +7 -2
  88. package/dist/lite/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
  89. package/dist/lite/packages/firestore/src/local/memory_persistence.d.ts +3 -2
  90. package/dist/lite/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  91. package/dist/lite/packages/firestore/src/local/persistence.d.ts +2 -2
  92. package/dist/lite/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
  93. package/dist/lite/packages/firestore/src/local/simple_db.d.ts +1 -0
  94. package/dist/lite/packages/firestore/src/model/field_index.d.ts +2 -2
  95. package/dist/lite/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
  96. package/dist/lite/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  97. package/dist/lite/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  98. package/dist/lite/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  99. package/dist/lite/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  100. package/dist/lite/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  101. package/dist/lite/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  102. package/dist/lite/packages/firestore/test/util/helpers.d.ts +1 -1
  103. package/dist/lite/private.d.ts +2 -2
  104. package/dist/packages/firestore/dist/index.esm2017.d.ts +170 -170
  105. package/dist/packages/firestore/src/api/credentials.d.ts +1 -0
  106. package/dist/packages/firestore/src/api/snapshot.d.ts +1 -2
  107. package/dist/packages/firestore/src/core/target.d.ts +8 -4
  108. package/dist/packages/firestore/src/lite-api/query.d.ts +2 -2
  109. package/dist/packages/firestore/src/local/index_manager.d.ts +52 -0
  110. package/dist/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  111. package/dist/packages/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  112. package/dist/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  113. package/dist/packages/firestore/src/local/indexeddb_schema.d.ts +149 -7
  114. package/dist/packages/firestore/src/local/local_documents_view.d.ts +0 -1
  115. package/dist/packages/firestore/src/local/local_serializer.d.ts +7 -2
  116. package/dist/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
  117. package/dist/packages/firestore/src/local/memory_persistence.d.ts +3 -2
  118. package/dist/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  119. package/dist/packages/firestore/src/local/persistence.d.ts +2 -2
  120. package/dist/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
  121. package/dist/packages/firestore/src/local/simple_db.d.ts +1 -0
  122. package/dist/packages/firestore/src/model/field_index.d.ts +2 -2
  123. package/dist/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
  124. package/dist/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  125. package/dist/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  126. package/dist/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  127. package/dist/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  128. package/dist/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  129. package/dist/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  130. package/dist/packages/firestore/test/util/helpers.d.ts +1 -1
  131. package/dist/private.d.ts +178 -14
  132. 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.b20cf306a";
15
+ const version$1 = "3.4.4-canary.bb8f37c3e";
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.b20cf306a";
68
+ const version = "9.6.6-canary.bb8f37c3e";
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,6 +1221,7 @@ 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 indexing support.
1234
1225
  */
1235
1226
  const SCHEMA_VERSION = 11;
1236
1227
  /**
@@ -1757,9 +1748,7 @@ class DbClientMetadata {
1757
1748
  DbClientMetadata.store = 'clientMetadata';
1758
1749
  /** Keys are automatically assigned via the clientId properties. */
1759
1750
  DbClientMetadata.keyPath = 'clientId';
1760
- /**
1761
- * A object representing a bundle loaded by the SDK.
1762
- */
1751
+ /** An object representing a bundle loaded by the SDK. */
1763
1752
  class DbBundle {
1764
1753
  constructor(
1765
1754
  /** The ID of the loaded bundle. */
@@ -1776,9 +1765,7 @@ class DbBundle {
1776
1765
  /** Name of the IndexedDb object store. */
1777
1766
  DbBundle.store = 'bundles';
1778
1767
  DbBundle.keyPath = 'bundleId';
1779
- /**
1780
- * A object representing a named query loaded by the SDK via a bundle.
1781
- */
1768
+ /** An object representing a named query loaded by the SDK via a bundle. */
1782
1769
  class DbNamedQuery {
1783
1770
  constructor(
1784
1771
  /** The name of the query. */
@@ -1795,6 +1782,116 @@ class DbNamedQuery {
1795
1782
  /** Name of the IndexedDb object store. */
1796
1783
  DbNamedQuery.store = 'namedQueries';
1797
1784
  DbNamedQuery.keyPath = 'name';
1785
+ /** An object representing the global configuration for a field index. */
1786
+ class DbIndexConfiguration {
1787
+ constructor(
1788
+ /**
1789
+ * The index id for this entry. Undefined for indexes that are not yet
1790
+ * persisted.
1791
+ */
1792
+ indexId,
1793
+ /** The collection group this index belongs to. */
1794
+ collectionGroup,
1795
+ /** The fields to index for this index. */
1796
+ fields) {
1797
+ this.indexId = indexId;
1798
+ this.collectionGroup = collectionGroup;
1799
+ this.fields = fields;
1800
+ }
1801
+ }
1802
+ /** Name of the IndexedDb object store. */
1803
+ DbIndexConfiguration.store = 'indexConfiguration';
1804
+ DbIndexConfiguration.keyPath = 'indexId';
1805
+ /**
1806
+ * An index that provides access to the index configurations by collection
1807
+ * group.
1808
+ *
1809
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1810
+ * not possible here as the Web client supports concurrent access to
1811
+ * persistence via multi-tab.
1812
+ */
1813
+ DbIndexConfiguration.collectionGroupIndex = 'collectionGroupIndex';
1814
+ DbIndexConfiguration.collectionGroupIndexPath = 'collectionGroup';
1815
+ /**
1816
+ * An object describing how up-to-date the index backfill is for each user and
1817
+ * index.
1818
+ */
1819
+ class DbIndexState {
1820
+ constructor(
1821
+ /** The index id for this entry. */
1822
+ indexId,
1823
+ /** The user id for this entry. */
1824
+ uid,
1825
+ /**
1826
+ * A number that indicates when the index was last updated (relative to
1827
+ * other indexes).
1828
+ */
1829
+ sequenceNumber,
1830
+ /**
1831
+ * The latest read time that has been indexed by Firestore for this field
1832
+ * index. Set to `{seconds: 0, nanos: 0}` if no documents have been indexed.
1833
+ */
1834
+ readTime,
1835
+ /**
1836
+ * The last document that has been indexed for this field index. Empty if
1837
+ * no documents have been indexed.
1838
+ */
1839
+ documentKey,
1840
+ /**
1841
+ * The largest mutation batch id that has been processed for this index. -1
1842
+ * if no mutations have been indexed.
1843
+ */
1844
+ largestBatchId) {
1845
+ this.indexId = indexId;
1846
+ this.uid = uid;
1847
+ this.sequenceNumber = sequenceNumber;
1848
+ this.readTime = readTime;
1849
+ this.documentKey = documentKey;
1850
+ this.largestBatchId = largestBatchId;
1851
+ }
1852
+ }
1853
+ /** Name of the IndexedDb object store. */
1854
+ DbIndexState.store = 'indexState';
1855
+ DbIndexState.keyPath = ['indexId', 'uid'];
1856
+ /**
1857
+ * An index that provides access to documents in a collection sorted by last
1858
+ * update time. Used by the backfiller.
1859
+ *
1860
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1861
+ * not possible here as the Web client supports concurrent access to
1862
+ * persistence via multi-tab.
1863
+ */
1864
+ DbIndexState.sequenceNumberIndex = 'sequenceNumberIndex';
1865
+ DbIndexState.sequenceNumberIndexPath = ['uid', 'sequenceNumber'];
1866
+ /** An object that stores the encoded entries for all documents and fields. */
1867
+ class DbIndexEntry {
1868
+ constructor(
1869
+ /** The index id for this entry. */
1870
+ indexId,
1871
+ /** The user id for this entry. */
1872
+ uid,
1873
+ /** The encoded array index value for this entry. */
1874
+ arrayValue,
1875
+ /** The encoded directional value for equality and inequality filters. */
1876
+ directionalValue,
1877
+ /** The document key this entry points to. */
1878
+ documentKey) {
1879
+ this.indexId = indexId;
1880
+ this.uid = uid;
1881
+ this.arrayValue = arrayValue;
1882
+ this.directionalValue = directionalValue;
1883
+ this.documentKey = documentKey;
1884
+ }
1885
+ }
1886
+ /** Name of the IndexedDb object store. */
1887
+ DbIndexEntry.store = 'indexEntries';
1888
+ DbIndexEntry.keyPath = [
1889
+ 'indexId',
1890
+ 'uid',
1891
+ 'arrayValue',
1892
+ 'directionalValue',
1893
+ 'documentKey'
1894
+ ];
1798
1895
  // Visible for testing
1799
1896
  const V1_STORES = [
1800
1897
  DbMutationQueue.store,
@@ -1809,7 +1906,6 @@ const V1_STORES = [
1809
1906
  // V2 is no longer usable (see comment at top of file)
1810
1907
  // Visible for testing
1811
1908
  const V3_STORES = V1_STORES;
1812
- // Visible for testing
1813
1909
  // Note: DbRemoteDocumentChanges is no longer used and dropped with v9.
1814
1910
  const V4_STORES = [...V3_STORES, DbClientMetadata.store];
1815
1911
  // V5 does not change the set of stores.
@@ -1819,12 +1915,24 @@ const V8_STORES = [...V6_STORES, DbCollectionParent.store];
1819
1915
  // V9 does not change the set of stores.
1820
1916
  // V10 does not change the set of stores.
1821
1917
  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;
1918
+ const V12_STORES = [
1919
+ ...V11_STORES,
1920
+ DbIndexConfiguration.store,
1921
+ DbIndexState.store,
1922
+ DbIndexEntry.store
1923
+ ];
1924
+ /** Returns the object stores for the provided schema. */
1925
+ function getObjectStores(schemaVersion) {
1926
+ if (schemaVersion === 12) {
1927
+ return V12_STORES;
1928
+ }
1929
+ else if (schemaVersion === 11) {
1930
+ return V11_STORES;
1931
+ }
1932
+ else {
1933
+ fail();
1934
+ }
1935
+ }
1828
1936
 
1829
1937
  /**
1830
1938
  * @license
@@ -2121,6 +2229,15 @@ class SimpleDbTransaction {
2121
2229
  this.transaction.abort();
2122
2230
  }
2123
2231
  }
2232
+ maybeCommit() {
2233
+ // If the browser supports V3 IndexedDB, we invoke commit() explicitly to
2234
+ // speed up index DB processing if the event loop remains blocks.
2235
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2236
+ const maybeV3IndexedDb = this.transaction;
2237
+ if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {
2238
+ maybeV3IndexedDb.commit();
2239
+ }
2240
+ }
2124
2241
  /**
2125
2242
  * Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
2126
2243
  * operations performed on the SimpleDbStore happen within the context of this
@@ -2317,6 +2434,10 @@ class SimpleDb {
2317
2434
  this.db = await this.ensureDb(action);
2318
2435
  const transaction = SimpleDbTransaction.open(this.db, action, readonly ? 'readonly' : 'readwrite', objectStores);
2319
2436
  const transactionFnResult = transactionFn(transaction)
2437
+ .next(result => {
2438
+ transaction.maybeCommit();
2439
+ return result;
2440
+ })
2320
2441
  .catch(error => {
2321
2442
  // Abort the transaction if there was an error.
2322
2443
  transaction.abort(error);
@@ -2489,13 +2610,29 @@ class SimpleDbStore {
2489
2610
  return wrapRequest(request);
2490
2611
  }
2491
2612
  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
- });
2613
+ const iterateOptions = this.options(indexOrRange, range);
2614
+ // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly
2615
+ // 20% faster. Unfortunately, getAll() does not support custom indices.
2616
+ if (!iterateOptions.index && typeof this.store.getAll === 'function') {
2617
+ const request = this.store.getAll(iterateOptions.range);
2618
+ return new PersistencePromise((resolve, reject) => {
2619
+ request.onerror = (event) => {
2620
+ reject(event.target.error);
2621
+ };
2622
+ request.onsuccess = (event) => {
2623
+ resolve(event.target.result);
2624
+ };
2625
+ });
2626
+ }
2627
+ else {
2628
+ const cursor = this.cursor(iterateOptions);
2629
+ const results = [];
2630
+ return this.iterateCursor(cursor, (key, value) => {
2631
+ results.push(value);
2632
+ }).next(() => {
2633
+ return results;
2634
+ });
2635
+ }
2499
2636
  }
2500
2637
  deleteAll(indexOrRange, range) {
2501
2638
  logDebug(LOG_TAG$g, 'DELETE ALL', this.store.name);
@@ -4349,12 +4486,12 @@ class FieldIndex {
4349
4486
  /** The collection ID this index applies to. */
4350
4487
  collectionGroup,
4351
4488
  /** The field segments for this index. */
4352
- segments,
4489
+ fields,
4353
4490
  /** Shows how up-to-date the index is for the current user. */
4354
4491
  indexState) {
4355
4492
  this.indexId = indexId;
4356
4493
  this.collectionGroup = collectionGroup;
4357
- this.segments = segments;
4494
+ this.fields = fields;
4358
4495
  this.indexState = indexState;
4359
4496
  }
4360
4497
  }
@@ -4464,27 +4601,29 @@ function newTarget(path, collectionGroup = null, orderBy = [], filters = [], lim
4464
4601
  function canonifyTarget(target) {
4465
4602
  const targetImpl = debugCast(target);
4466
4603
  if (targetImpl.memoizedCanonicalId === null) {
4467
- let canonicalId = targetImpl.path.canonicalString();
4604
+ let str = targetImpl.path.canonicalString();
4468
4605
  if (targetImpl.collectionGroup !== null) {
4469
- canonicalId += '|cg:' + targetImpl.collectionGroup;
4606
+ str += '|cg:' + targetImpl.collectionGroup;
4470
4607
  }
4471
- canonicalId += '|f:';
4472
- canonicalId += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4473
- canonicalId += '|ob:';
4474
- canonicalId += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4608
+ str += '|f:';
4609
+ str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4610
+ str += '|ob:';
4611
+ str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4475
4612
  if (!isNullOrUndefined(targetImpl.limit)) {
4476
- canonicalId += '|l:';
4477
- canonicalId += targetImpl.limit;
4613
+ str += '|l:';
4614
+ str += targetImpl.limit;
4478
4615
  }
4479
4616
  if (targetImpl.startAt) {
4480
- canonicalId += '|lb:';
4481
- canonicalId += canonifyBound(targetImpl.startAt);
4617
+ str += '|lb:';
4618
+ str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
4619
+ str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
4482
4620
  }
4483
4621
  if (targetImpl.endAt) {
4484
- canonicalId += '|ub:';
4485
- canonicalId += canonifyBound(targetImpl.endAt);
4622
+ str += '|ub:';
4623
+ str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
4624
+ str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
4486
4625
  }
4487
- targetImpl.memoizedCanonicalId = canonicalId;
4626
+ targetImpl.memoizedCanonicalId = str;
4488
4627
  }
4489
4628
  return targetImpl.memoizedCanonicalId;
4490
4629
  }
@@ -4507,10 +4646,14 @@ function stringifyTarget(target) {
4507
4646
  .join(', ')}]`;
4508
4647
  }
4509
4648
  if (target.startAt) {
4510
- str += ', startAt: ' + canonifyBound(target.startAt);
4649
+ str += ', startAt: ';
4650
+ str += target.startAt.inclusive ? 'b:' : 'a:';
4651
+ str += target.startAt.position.map(p => canonicalId(p)).join(',');
4511
4652
  }
4512
4653
  if (target.endAt) {
4513
- str += ', endAt: ' + canonifyBound(target.endAt);
4654
+ str += ', endAt: ';
4655
+ str += target.endAt.inclusive ? 'a:' : 'b:';
4656
+ str += target.endAt.position.map(p => canonicalId(p)).join(',');
4514
4657
  }
4515
4658
  return `Target(${str})`;
4516
4659
  }
@@ -4733,7 +4876,6 @@ class ArrayContainsAnyFilter extends FieldFilter {
4733
4876
  return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
4734
4877
  }
4735
4878
  }
4736
- // TODO(indexing): Change Bound.before to "inclusive"
4737
4879
  /**
4738
4880
  * Represents a bound of a query.
4739
4881
  *
@@ -4749,17 +4891,11 @@ class ArrayContainsAnyFilter extends FieldFilter {
4749
4891
  * just after the provided values.
4750
4892
  */
4751
4893
  class Bound {
4752
- constructor(position, before) {
4894
+ constructor(position, inclusive) {
4753
4895
  this.position = position;
4754
- this.before = before;
4896
+ this.inclusive = inclusive;
4755
4897
  }
4756
4898
  }
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
4899
  /**
4764
4900
  * An ordering on a field, in some Direction. Direction defaults to ASCENDING.
4765
4901
  */
@@ -4779,11 +4915,7 @@ function stringifyOrderBy(orderBy) {
4779
4915
  function orderByEquals(left, right) {
4780
4916
  return left.dir === right.dir && left.field.isEqual(right.field);
4781
4917
  }
4782
- /**
4783
- * Returns true if a document sorts before a bound using the provided sort
4784
- * order.
4785
- */
4786
- function sortsBeforeDocument(bound, orderBy, doc) {
4918
+ function boundCompareToDocument(bound, orderBy, doc) {
4787
4919
  let comparison = 0;
4788
4920
  for (let i = 0; i < bound.position.length; i++) {
4789
4921
  const orderByComponent = orderBy[i];
@@ -4802,7 +4934,23 @@ function sortsBeforeDocument(bound, orderBy, doc) {
4802
4934
  break;
4803
4935
  }
4804
4936
  }
4805
- return bound.before ? comparison <= 0 : comparison < 0;
4937
+ return comparison;
4938
+ }
4939
+ /**
4940
+ * Returns true if a document sorts after a bound using the provided sort
4941
+ * order.
4942
+ */
4943
+ function boundSortsAfterDocument(bound, orderBy, doc) {
4944
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4945
+ return bound.inclusive ? comparison >= 0 : comparison > 0;
4946
+ }
4947
+ /**
4948
+ * Returns true if a document sorts before a bound using the provided sort
4949
+ * order.
4950
+ */
4951
+ function boundSortsBeforeDocument(bound, orderBy, doc) {
4952
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4953
+ return bound.inclusive ? comparison <= 0 : comparison < 0;
4806
4954
  }
4807
4955
  function boundEquals(left, right) {
4808
4956
  if (left === null) {
@@ -4811,7 +4959,7 @@ function boundEquals(left, right) {
4811
4959
  else if (right === null) {
4812
4960
  return false;
4813
4961
  }
4814
- if (left.before !== right.before ||
4962
+ if (left.inclusive !== right.inclusive ||
4815
4963
  left.position.length !== right.position.length) {
4816
4964
  return false;
4817
4965
  }
@@ -5015,10 +5163,10 @@ function queryToTarget(query) {
5015
5163
  }
5016
5164
  // We need to swap the cursors to match the now-flipped query ordering.
5017
5165
  const startAt = queryImpl.endAt
5018
- ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.before)
5166
+ ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
5019
5167
  : null;
5020
5168
  const endAt = queryImpl.startAt
5021
- ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.before)
5169
+ ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
5022
5170
  : null;
5023
5171
  // Now return as a LimitType.First query.
5024
5172
  queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
@@ -5106,11 +5254,11 @@ function queryMatchesFilters(query, doc) {
5106
5254
  /** Makes sure a document is within the bounds, if provided. */
5107
5255
  function queryMatchesBounds(query, doc) {
5108
5256
  if (query.startAt &&
5109
- !sortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5257
+ !boundSortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5110
5258
  return false;
5111
5259
  }
5112
5260
  if (query.endAt &&
5113
- sortsBeforeDocument(query.endAt, queryOrderBy(query), doc)) {
5261
+ !boundSortsAfterDocument(query.endAt, queryOrderBy(query), doc)) {
5114
5262
  return false;
5115
5263
  }
5116
5264
  return true;
@@ -7989,10 +8137,10 @@ function toQueryTarget(serializer, target) {
7989
8137
  result.structuredQuery.limit = limit;
7990
8138
  }
7991
8139
  if (target.startAt) {
7992
- result.structuredQuery.startAt = toCursor(target.startAt);
8140
+ result.structuredQuery.startAt = toStartAtCursor(target.startAt);
7993
8141
  }
7994
8142
  if (target.endAt) {
7995
- result.structuredQuery.endAt = toCursor(target.endAt);
8143
+ result.structuredQuery.endAt = toEndAtCursor(target.endAt);
7996
8144
  }
7997
8145
  return result;
7998
8146
  }
@@ -8025,11 +8173,11 @@ function convertQueryTargetToQuery(target) {
8025
8173
  }
8026
8174
  let startAt = null;
8027
8175
  if (query.startAt) {
8028
- startAt = fromCursor(query.startAt);
8176
+ startAt = fromStartAtCursor(query.startAt);
8029
8177
  }
8030
8178
  let endAt = null;
8031
8179
  if (query.endAt) {
8032
- endAt = fromCursor(query.endAt);
8180
+ endAt = fromEndAtCursor(query.endAt);
8033
8181
  }
8034
8182
  return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
8035
8183
  }
@@ -8120,16 +8268,27 @@ function toOrder(orderBys) {
8120
8268
  function fromOrder(orderBys) {
8121
8269
  return orderBys.map(order => fromPropertyOrder(order));
8122
8270
  }
8123
- function toCursor(cursor) {
8271
+ function toStartAtCursor(cursor) {
8124
8272
  return {
8125
- before: cursor.before,
8273
+ before: cursor.inclusive,
8126
8274
  values: cursor.position
8127
8275
  };
8128
8276
  }
8129
- function fromCursor(cursor) {
8130
- const before = !!cursor.before;
8277
+ function toEndAtCursor(cursor) {
8278
+ return {
8279
+ before: !cursor.inclusive,
8280
+ values: cursor.position
8281
+ };
8282
+ }
8283
+ function fromStartAtCursor(cursor) {
8284
+ const inclusive = !!cursor.before;
8285
+ const position = cursor.values || [];
8286
+ return new Bound(position, inclusive);
8287
+ }
8288
+ function fromEndAtCursor(cursor) {
8289
+ const inclusive = !cursor.before;
8131
8290
  const position = cursor.values || [];
8132
- return new Bound(position, before);
8291
+ return new Bound(position, inclusive);
8133
8292
  }
8134
8293
  // visible for testing
8135
8294
  function toDirection(dir) {
@@ -8593,6 +8752,19 @@ function fromBundleMetadata(metadata) {
8593
8752
  version: metadata.version,
8594
8753
  createTime: fromVersion(metadata.createTime)
8595
8754
  };
8755
+ }
8756
+ function toDbIndexConfiguration(index) {
8757
+ return new DbIndexConfiguration(index.indexId, index.collectionGroup, index.fields.map(s => [s.fieldPath.canonicalString(), s.kind]));
8758
+ }
8759
+ function fromDbIndexConfiguration(index, state) {
8760
+ const decodedState = state
8761
+ ? new IndexState(state.sequenceNumber, new IndexOffset(fromDbTimestamp(state.readTime), new DocumentKey(decodeResourcePath(state.documentKey)), state.largestBatchId))
8762
+ : IndexState.empty();
8763
+ const decodedSegments = index.fields.map(([fieldPath, kind]) => new IndexSegment(FieldPath$1.fromServerFormat(fieldPath), kind));
8764
+ return new FieldIndex(index.indexId, index.collectionGroup, decodedSegments, decodedState);
8765
+ }
8766
+ function toDbIndexState(indexId, user, sequenceNumber, offset) {
8767
+ return new DbIndexState(indexId, user.uid || '', sequenceNumber, toDbTimestamp(offset.readTime), encodeResourcePath(offset.documentKey.path), offset.largestBatchId);
8596
8768
  }
8597
8769
 
8598
8770
  /**
@@ -8682,6 +8854,38 @@ class MemoryIndexManager {
8682
8854
  getCollectionParents(transaction, collectionId) {
8683
8855
  return PersistencePromise.resolve(this.collectionParentIndex.getEntries(collectionId));
8684
8856
  }
8857
+ addFieldIndex(transaction, index) {
8858
+ // Field indices are not supported with memory persistence.
8859
+ return PersistencePromise.resolve();
8860
+ }
8861
+ deleteFieldIndex(transaction, index) {
8862
+ // Field indices are not supported with memory persistence.
8863
+ return PersistencePromise.resolve();
8864
+ }
8865
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
8866
+ // Field indices are not supported with memory persistence.
8867
+ return PersistencePromise.resolve(documentKeySet());
8868
+ }
8869
+ getFieldIndex(transaction, target) {
8870
+ // Field indices are not supported with memory persistence.
8871
+ return PersistencePromise.resolve(null);
8872
+ }
8873
+ getFieldIndexes(transaction, collectionGroup) {
8874
+ // Field indices are not supported with memory persistence.
8875
+ return PersistencePromise.resolve([]);
8876
+ }
8877
+ getNextCollectionGroupToUpdate(transaction) {
8878
+ // Field indices are not supported with memory persistence.
8879
+ return PersistencePromise.resolve(null);
8880
+ }
8881
+ updateCollectionGroup(transaction, collectionGroup, offset) {
8882
+ // Field indices are not supported with memory persistence.
8883
+ return PersistencePromise.resolve();
8884
+ }
8885
+ updateIndexEntries(transaction, documents) {
8886
+ // Field indices are not supported with memory persistence.
8887
+ return PersistencePromise.resolve();
8888
+ }
8685
8889
  }
8686
8890
  /**
8687
8891
  * Internal implementation of the collection-parent index exposed by MemoryIndexManager.
@@ -8733,17 +8937,22 @@ class MemoryCollectionParentIndex {
8733
8937
  */
8734
8938
  /**
8735
8939
  * A persisted implementation of IndexManager.
8940
+ *
8941
+ * PORTING NOTE: Unlike iOS and Android, the Web SDK does not memoize index
8942
+ * data as it supports multi-tab access.
8736
8943
  */
8737
8944
  class IndexedDbIndexManager {
8738
- constructor() {
8945
+ constructor(user) {
8946
+ this.user = user;
8739
8947
  /**
8740
8948
  * An in-memory copy of the index entries we've already written since the SDK
8741
8949
  * launched. Used to avoid re-writing the same entry repeatedly.
8742
8950
  *
8743
- * This is *NOT* a complete cache of what's in persistence and so can never be used to
8744
- * satisfy reads.
8951
+ * This is *NOT* a complete cache of what's in persistence and so can never be
8952
+ * used to satisfy reads.
8745
8953
  */
8746
8954
  this.collectionParentsCache = new MemoryCollectionParentIndex();
8955
+ this.uid = user.uid || '';
8747
8956
  }
8748
8957
  /**
8749
8958
  * Adds a new entry to the collection parent index.
@@ -8790,6 +8999,85 @@ class IndexedDbIndexManager {
8790
8999
  return parentPaths;
8791
9000
  });
8792
9001
  }
9002
+ addFieldIndex(transaction, index) {
9003
+ // TODO(indexing): Verify that the auto-incrementing index ID works in
9004
+ // Safari & Firefox.
9005
+ const indexes = indexConfigurationStore(transaction);
9006
+ const dbIndex = toDbIndexConfiguration(index);
9007
+ delete dbIndex.indexId; // `indexId` is auto-populated by IndexedDb
9008
+ return indexes.add(dbIndex).next();
9009
+ }
9010
+ deleteFieldIndex(transaction, index) {
9011
+ const indexes = indexConfigurationStore(transaction);
9012
+ const states = indexStateStore(transaction);
9013
+ const entries = indexEntriesStore(transaction);
9014
+ return indexes
9015
+ .delete(index.indexId)
9016
+ .next(() => states.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9017
+ /*lowerOpen=*/ false,
9018
+ /*upperOpen=*/ true)))
9019
+ .next(() => entries.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9020
+ /*lowerOpen=*/ false,
9021
+ /*upperOpen=*/ true)));
9022
+ }
9023
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9024
+ // TODO(indexing): Implement
9025
+ return PersistencePromise.resolve(documentKeySet());
9026
+ }
9027
+ getFieldIndex(transaction, target) {
9028
+ // TODO(indexing): Implement
9029
+ return PersistencePromise.resolve(null);
9030
+ }
9031
+ getFieldIndexes(transaction, collectionGroup) {
9032
+ const indexes = indexConfigurationStore(transaction);
9033
+ const states = indexStateStore(transaction);
9034
+ return (collectionGroup
9035
+ ? indexes.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9036
+ : indexes.loadAll()).next(indexConfigs => {
9037
+ const result = [];
9038
+ return PersistencePromise.forEach(indexConfigs, (indexConfig) => {
9039
+ return states
9040
+ .get([indexConfig.indexId, this.uid])
9041
+ .next(indexState => {
9042
+ result.push(fromDbIndexConfiguration(indexConfig, indexState));
9043
+ });
9044
+ }).next(() => result);
9045
+ });
9046
+ }
9047
+ getNextCollectionGroupToUpdate(transaction) {
9048
+ return this.getFieldIndexes(transaction).next(indexes => {
9049
+ if (indexes.length === 0) {
9050
+ return null;
9051
+ }
9052
+ indexes.sort((l, r) => l.indexState.sequenceNumber - r.indexState.sequenceNumber);
9053
+ return indexes[0].collectionGroup;
9054
+ });
9055
+ }
9056
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9057
+ const indexes = indexConfigurationStore(transaction);
9058
+ const states = indexStateStore(transaction);
9059
+ return this.getNextSequenceNumber(transaction).next(nextSequenceNumber => indexes
9060
+ .loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9061
+ .next(configs => PersistencePromise.forEach(configs, (config) => states.put(toDbIndexState(config.indexId, this.user, nextSequenceNumber, offset)))));
9062
+ }
9063
+ updateIndexEntries(transaction, documents) {
9064
+ // TODO(indexing): Implement
9065
+ return PersistencePromise.resolve();
9066
+ }
9067
+ getNextSequenceNumber(transaction) {
9068
+ let nextSequenceNumber = 1;
9069
+ const states = indexStateStore(transaction);
9070
+ return states
9071
+ .iterate({
9072
+ index: DbIndexState.sequenceNumberIndex,
9073
+ reverse: true,
9074
+ range: IDBKeyRange.upperBound([this.uid, Number.MAX_SAFE_INTEGER])
9075
+ }, (_, state, controller) => {
9076
+ controller.done();
9077
+ nextSequenceNumber = state.sequenceNumber + 1;
9078
+ })
9079
+ .next(() => nextSequenceNumber);
9080
+ }
8793
9081
  }
8794
9082
  /**
8795
9083
  * Helper to get a typed SimpleDbStore for the collectionParents
@@ -8797,6 +9085,24 @@ class IndexedDbIndexManager {
8797
9085
  */
8798
9086
  function collectionParentsStore(txn) {
8799
9087
  return getStore(txn, DbCollectionParent.store);
9088
+ }
9089
+ /**
9090
+ * Helper to get a typed SimpleDbStore for the index entry object store.
9091
+ */
9092
+ function indexEntriesStore(txn) {
9093
+ return getStore(txn, DbIndexEntry.store);
9094
+ }
9095
+ /**
9096
+ * Helper to get a typed SimpleDbStore for the index configuration object store.
9097
+ */
9098
+ function indexConfigurationStore(txn) {
9099
+ return getStore(txn, DbIndexConfiguration.store);
9100
+ }
9101
+ /**
9102
+ * Helper to get a typed SimpleDbStore for the index state object store.
9103
+ */
9104
+ function indexStateStore(txn) {
9105
+ return getStore(txn, DbIndexState.store);
8800
9106
  }
8801
9107
 
8802
9108
  /**
@@ -10266,12 +10572,10 @@ class RemoteDocumentChangeBuffer {
10266
10572
  * `newIndexedDbRemoteDocumentCache()`.
10267
10573
  */
10268
10574
  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) {
10575
+ constructor(serializer) {
10274
10576
  this.serializer = serializer;
10577
+ }
10578
+ setIndexManager(indexManager) {
10275
10579
  this.indexManager = indexManager;
10276
10580
  }
10277
10581
  /**
@@ -10393,21 +10697,21 @@ class IndexedDbRemoteDocumentCacheImpl {
10393
10697
  }
10394
10698
  });
10395
10699
  }
10396
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
10700
+ getAll(transaction, collection, sinceReadTime) {
10397
10701
  let results = mutableDocumentMap();
10398
- const immediateChildrenPathLength = query.path.length + 1;
10702
+ const immediateChildrenPathLength = collection.length + 1;
10399
10703
  const iterationOptions = {};
10400
10704
  if (sinceReadTime.isEqual(SnapshotVersion.min())) {
10401
10705
  // Documents are ordered by key, so we can use a prefix scan to narrow
10402
10706
  // down the documents we need to match the query against.
10403
- const startKey = query.path.toArray();
10707
+ const startKey = collection.toArray();
10404
10708
  iterationOptions.range = IDBKeyRange.lowerBound(startKey);
10405
10709
  }
10406
10710
  else {
10407
10711
  // Execute an index-free query and filter by read time. This is safe
10408
10712
  // since all document changes to queries that have a
10409
10713
  // lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read time set.
10410
- const collectionKey = query.path.toArray();
10714
+ const collectionKey = collection.toArray();
10411
10715
  const readTimeKey = toDbTimestampKey(sinceReadTime);
10412
10716
  iterationOptions.range = IDBKeyRange.lowerBound([collectionKey, readTimeKey],
10413
10717
  /* open= */ true);
@@ -10424,12 +10728,12 @@ class IndexedDbRemoteDocumentCacheImpl {
10424
10728
  return;
10425
10729
  }
10426
10730
  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)) {
10731
+ if (collection.isPrefixOf(document.key.path)) {
10431
10732
  results = results.insert(document.key, document);
10432
10733
  }
10734
+ else {
10735
+ control.done();
10736
+ }
10433
10737
  })
10434
10738
  .next(() => results);
10435
10739
  }
@@ -10467,14 +10771,9 @@ class IndexedDbRemoteDocumentCacheImpl {
10467
10771
  return MutableDocument.newInvalidDocument(documentKey);
10468
10772
  }
10469
10773
  }
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);
10774
+ /** Creates a new IndexedDbRemoteDocumentCache. */
10775
+ function newIndexedDbRemoteDocumentCache(serializer) {
10776
+ return new IndexedDbRemoteDocumentCacheImpl(serializer);
10478
10777
  }
10479
10778
  /**
10480
10779
  * Returns the set of documents that have changed since the specified read
@@ -10641,9 +10940,6 @@ class SchemaConverter {
10641
10940
  * and local feature development.
10642
10941
  */
10643
10942
  createOrUpgrade(db, txn, fromVersion, toVersion) {
10644
- hardAssert(fromVersion < toVersion &&
10645
- fromVersion >= 0 &&
10646
- toVersion <= SCHEMA_VERSION);
10647
10943
  const simpleDbTransaction = new SimpleDbTransaction('createOrUpgrade', txn);
10648
10944
  if (fromVersion < 1 && toVersion >= 1) {
10649
10945
  createPrimaryClientStore(db);
@@ -10710,6 +11006,11 @@ class SchemaConverter {
10710
11006
  createNamedQueriesStore(db);
10711
11007
  });
10712
11008
  }
11009
+ if (fromVersion < 12 && toVersion >= 12) {
11010
+ p = p.next(() => {
11011
+ createFieldIndex(db);
11012
+ });
11013
+ }
10713
11014
  return p;
10714
11015
  }
10715
11016
  addDocumentGlobal(txn) {
@@ -10916,6 +11217,20 @@ function createNamedQueriesStore(db) {
10916
11217
  db.createObjectStore(DbNamedQuery.store, {
10917
11218
  keyPath: DbNamedQuery.keyPath
10918
11219
  });
11220
+ }
11221
+ function createFieldIndex(db) {
11222
+ const indexConfiguratioStore = db.createObjectStore(DbIndexConfiguration.store, {
11223
+ keyPath: DbIndexConfiguration.keyPath,
11224
+ autoIncrement: true
11225
+ });
11226
+ indexConfiguratioStore.createIndex(DbIndexConfiguration.collectionGroupIndex, DbIndexConfiguration.collectionGroupIndexPath, { unique: false });
11227
+ const indexStateStore = db.createObjectStore(DbIndexState.store, {
11228
+ keyPath: DbIndexState.keyPath
11229
+ });
11230
+ indexStateStore.createIndex(DbIndexState.sequenceNumberIndex, DbIndexState.sequenceNumberIndexPath, { unique: false });
11231
+ db.createObjectStore(DbIndexEntry.store, {
11232
+ keyPath: DbIndexEntry.keyPath
11233
+ });
10919
11234
  }
10920
11235
 
10921
11236
  /**
@@ -11027,7 +11342,7 @@ class IndexedDbPersistence {
11027
11342
  * If set to true, forcefully obtains database access. Existing tabs will
11028
11343
  * no longer be able to access IndexedDB.
11029
11344
  */
11030
- forceOwningTab) {
11345
+ forceOwningTab, schemaVersion = SCHEMA_VERSION) {
11031
11346
  this.allowTabSynchronization = allowTabSynchronization;
11032
11347
  this.persistenceKey = persistenceKey;
11033
11348
  this.clientId = clientId;
@@ -11036,6 +11351,7 @@ class IndexedDbPersistence {
11036
11351
  this.document = document;
11037
11352
  this.sequenceNumberSyncer = sequenceNumberSyncer;
11038
11353
  this.forceOwningTab = forceOwningTab;
11354
+ this.schemaVersion = schemaVersion;
11039
11355
  this.listenSequence = null;
11040
11356
  this._started = false;
11041
11357
  this.isPrimary = false;
@@ -11057,10 +11373,9 @@ class IndexedDbPersistence {
11057
11373
  this.referenceDelegate = new IndexedDbLruDelegateImpl(this, lruParams);
11058
11374
  this.dbName = persistenceKey + MAIN_DATABASE;
11059
11375
  this.serializer = new LocalSerializer(serializer);
11060
- this.simpleDb = new SimpleDb(this.dbName, SCHEMA_VERSION, new SchemaConverter(this.serializer));
11376
+ this.simpleDb = new SimpleDb(this.dbName, this.schemaVersion, new SchemaConverter(this.serializer));
11061
11377
  this.targetCache = new IndexedDbTargetCache(this.referenceDelegate, this.serializer);
11062
- this.indexManager = new IndexedDbIndexManager();
11063
- this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer, this.indexManager);
11378
+ this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer);
11064
11379
  this.bundleCache = new IndexedDbBundleCache();
11065
11380
  if (this.window && this.window.localStorage) {
11066
11381
  this.webStorage = this.window.localStorage;
@@ -11396,8 +11711,8 @@ class IndexedDbPersistence {
11396
11711
  get started() {
11397
11712
  return this._started;
11398
11713
  }
11399
- getMutationQueue(user) {
11400
- return IndexedDbMutationQueue.forUser(user, this.serializer, this.indexManager, this.referenceDelegate);
11714
+ getMutationQueue(user, indexManager) {
11715
+ return IndexedDbMutationQueue.forUser(user, this.serializer, indexManager, this.referenceDelegate);
11401
11716
  }
11402
11717
  getTargetCache() {
11403
11718
  return this.targetCache;
@@ -11405,8 +11720,8 @@ class IndexedDbPersistence {
11405
11720
  getRemoteDocumentCache() {
11406
11721
  return this.remoteDocumentCache;
11407
11722
  }
11408
- getIndexManager() {
11409
- return this.indexManager;
11723
+ getIndexManager(user) {
11724
+ return new IndexedDbIndexManager(user);
11410
11725
  }
11411
11726
  getBundleCache() {
11412
11727
  return this.bundleCache;
@@ -11414,11 +11729,12 @@ class IndexedDbPersistence {
11414
11729
  runTransaction(action, mode, transactionOperation) {
11415
11730
  logDebug(LOG_TAG$d, 'Starting transaction:', action);
11416
11731
  const simpleDbMode = mode === 'readonly' ? 'readonly' : 'readwrite';
11732
+ const objectStores = getObjectStores(this.schemaVersion);
11417
11733
  let persistenceTransaction;
11418
11734
  // Do all transactions as readwrite against all object stores, since we
11419
11735
  // are the only reader/writer.
11420
11736
  return this.simpleDb
11421
- .runTransaction(action, simpleDbMode, ALL_STORES, simpleDbTxn => {
11737
+ .runTransaction(action, simpleDbMode, objectStores, simpleDbTxn => {
11422
11738
  persistenceTransaction = new IndexedDbTransaction(simpleDbTxn, this.listenSequence
11423
11739
  ? this.listenSequence.next()
11424
11740
  : ListenSequence.INVALID);
@@ -11790,39 +12106,28 @@ class LocalDocumentsView {
11790
12106
  getDocumentsMatchingCollectionQuery(transaction, query, sinceReadTime) {
11791
12107
  // Query the remote documents and overlay mutations.
11792
12108
  let results;
11793
- let mutationBatches;
11794
12109
  return this.remoteDocumentCache
11795
- .getDocumentsMatchingQuery(transaction, query, sinceReadTime)
12110
+ .getAll(transaction, query.path, sinceReadTime)
11796
12111
  .next(queryResults => {
11797
12112
  results = queryResults;
11798
12113
  return this.mutationQueue.getAllMutationBatchesAffectingQuery(transaction, query);
11799
12114
  })
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
- }
12115
+ .next(mutationBatches => {
12116
+ for (const batch of mutationBatches) {
12117
+ for (const mutation of batch.mutations) {
12118
+ const key = mutation.key;
12119
+ let document = results.get(key);
12120
+ if (document == null) {
12121
+ // Create invalid document to apply mutations on top of
12122
+ document = MutableDocument.newInvalidDocument(key);
12123
+ results = results.insert(key, document);
12124
+ }
12125
+ mutationApplyToLocalView(mutation, document, batch.localWriteTime);
12126
+ if (!document.isFoundDocument()) {
12127
+ results = results.remove(key);
11823
12128
  }
11824
12129
  }
11825
- });
12130
+ }
11826
12131
  })
11827
12132
  .next(() => {
11828
12133
  // Finally, filter out any documents that don't actually match
@@ -11835,29 +12140,6 @@ class LocalDocumentsView {
11835
12140
  return results;
11836
12141
  });
11837
12142
  }
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
12143
  }
11862
12144
 
11863
12145
  /**
@@ -11916,11 +12198,18 @@ class LocalStoreImpl {
11916
12198
  * PORTING NOTE: This is only used for multi-tab synchronization.
11917
12199
  */
11918
12200
  this.lastDocumentChangeReadTime = SnapshotVersion.min();
11919
- this.mutationQueue = persistence.getMutationQueue(initialUser);
11920
12201
  this.remoteDocuments = persistence.getRemoteDocumentCache();
11921
12202
  this.targetCache = persistence.getTargetCache();
11922
- this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.persistence.getIndexManager());
11923
12203
  this.bundleCache = persistence.getBundleCache();
12204
+ this.initializeUserComponents(initialUser);
12205
+ }
12206
+ initializeUserComponents(user) {
12207
+ // TODO(indexing): Add spec tests that test these components change after a
12208
+ // user change
12209
+ this.indexManager = this.persistence.getIndexManager(user);
12210
+ this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
12211
+ this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
12212
+ this.remoteDocuments.setIndexManager(this.indexManager);
11924
12213
  this.queryEngine.setLocalDocumentsView(this.localDocuments);
11925
12214
  }
11926
12215
  collectGarbage(garbageCollector) {
@@ -11942,8 +12231,6 @@ persistence, queryEngine, initialUser, serializer) {
11942
12231
  // change.
11943
12232
  async function localStoreHandleUserChange(localStore, user) {
11944
12233
  const localStoreImpl = debugCast(localStore);
11945
- let newMutationQueue = localStoreImpl.mutationQueue;
11946
- let newLocalDocuments = localStoreImpl.localDocuments;
11947
12234
  const result = await localStoreImpl.persistence.runTransaction('Handle user change', 'readonly', txn => {
11948
12235
  // Swap out the mutation queue, grabbing the pending mutation batches
11949
12236
  // before and after.
@@ -11952,11 +12239,8 @@ async function localStoreHandleUserChange(localStore, user) {
11952
12239
  .getAllMutationBatches(txn)
11953
12240
  .next(promisedOldBatches => {
11954
12241
  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);
12242
+ localStoreImpl.initializeUserComponents(user);
12243
+ return localStoreImpl.mutationQueue.getAllMutationBatches(txn);
11960
12244
  })
11961
12245
  .next(newBatches => {
11962
12246
  const removedBatchIds = [];
@@ -11977,7 +12261,7 @@ async function localStoreHandleUserChange(localStore, user) {
11977
12261
  }
11978
12262
  // Return the set of all (potentially) changed documents and the list
11979
12263
  // of mutation batch IDs that were affected by change.
11980
- return newLocalDocuments
12264
+ return localStoreImpl.localDocuments
11981
12265
  .getDocuments(txn, changedKeys)
11982
12266
  .next(affectedDocuments => {
11983
12267
  return {
@@ -11988,9 +12272,6 @@ async function localStoreHandleUserChange(localStore, user) {
11988
12272
  });
11989
12273
  });
11990
12274
  });
11991
- localStoreImpl.mutationQueue = newMutationQueue;
11992
- localStoreImpl.localDocuments = newLocalDocuments;
11993
- localStoreImpl.queryEngine.setLocalDocumentsView(localStoreImpl.localDocuments);
11994
12275
  return result;
11995
12276
  }
11996
12277
  /* Accepts locally generated Mutations and commit them to storage. */
@@ -13056,14 +13337,16 @@ class MemoryRemoteDocumentCacheImpl {
13056
13337
  * expected to just return 0 to avoid unnecessarily doing the work of
13057
13338
  * calculating the size.
13058
13339
  */
13059
- constructor(indexManager, sizer) {
13060
- this.indexManager = indexManager;
13340
+ constructor(sizer) {
13061
13341
  this.sizer = sizer;
13062
13342
  /** Underlying cache of documents and their read times. */
13063
13343
  this.docs = documentEntryMap();
13064
13344
  /** Size of all cached documents. */
13065
13345
  this.size = 0;
13066
13346
  }
13347
+ setIndexManager(indexManager) {
13348
+ this.indexManager = indexManager;
13349
+ }
13067
13350
  /**
13068
13351
  * Adds the supplied entry to the cache and updates the cache size as appropriate.
13069
13352
  *
@@ -13111,21 +13394,22 @@ class MemoryRemoteDocumentCacheImpl {
13111
13394
  });
13112
13395
  return PersistencePromise.resolve(results);
13113
13396
  }
13114
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
13397
+ getAll(transaction, collectionPath, sinceReadTime) {
13115
13398
  let results = mutableDocumentMap();
13116
13399
  // Documents are ordered by key, so we can use a prefix scan to narrow down
13117
13400
  // the documents we need to match the query against.
13118
- const prefix = new DocumentKey(query.path.child(''));
13401
+ const prefix = new DocumentKey(collectionPath.child(''));
13119
13402
  const iterator = this.docs.getIteratorFrom(prefix);
13120
13403
  while (iterator.hasNext()) {
13121
13404
  const { key, value: { document } } = iterator.getNext();
13122
- if (!query.path.isPrefixOf(key.path)) {
13405
+ if (!collectionPath.isPrefixOf(key.path)) {
13123
13406
  break;
13124
13407
  }
13125
- if (document.readTime.compareTo(sinceReadTime) <= 0) {
13408
+ if (key.path.length > collectionPath.length + 1) {
13409
+ // Exclude entries from subcollections.
13126
13410
  continue;
13127
13411
  }
13128
- if (!queryMatches(query, document)) {
13412
+ if (document.readTime.compareTo(sinceReadTime) <= 0) {
13129
13413
  continue;
13130
13414
  }
13131
13415
  results = results.insert(document.key, document.mutableCopy());
@@ -13147,13 +13431,12 @@ class MemoryRemoteDocumentCacheImpl {
13147
13431
  /**
13148
13432
  * Creates a new memory-only RemoteDocumentCache.
13149
13433
  *
13150
- * @param indexManager - A class that manages collection group indices.
13151
13434
  * @param sizer - Used to assess the size of a document. For eager GC, this is
13152
13435
  * expected to just return 0 to avoid unnecessarily doing the work of
13153
13436
  * calculating the size.
13154
13437
  */
13155
- function newMemoryRemoteDocumentCache(indexManager, sizer) {
13156
- return new MemoryRemoteDocumentCacheImpl(indexManager, sizer);
13438
+ function newMemoryRemoteDocumentCache(sizer) {
13439
+ return new MemoryRemoteDocumentCacheImpl(sizer);
13157
13440
  }
13158
13441
  /**
13159
13442
  * Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
@@ -13354,7 +13637,7 @@ class MemoryPersistence {
13354
13637
  this.targetCache = new MemoryTargetCache(this);
13355
13638
  const sizer = (doc) => this.referenceDelegate.documentSize(doc);
13356
13639
  this.indexManager = new MemoryIndexManager();
13357
- this.remoteDocumentCache = newMemoryRemoteDocumentCache(this.indexManager, sizer);
13640
+ this.remoteDocumentCache = newMemoryRemoteDocumentCache(sizer);
13358
13641
  this.serializer = new LocalSerializer(serializer);
13359
13642
  this.bundleCache = new MemoryBundleCache(this.serializer);
13360
13643
  }
@@ -13375,13 +13658,15 @@ class MemoryPersistence {
13375
13658
  setNetworkEnabled() {
13376
13659
  // No op.
13377
13660
  }
13378
- getIndexManager() {
13661
+ getIndexManager(user) {
13662
+ // We do not currently support indices for memory persistence, so we can
13663
+ // return the same shared instance of the memory index manager.
13379
13664
  return this.indexManager;
13380
13665
  }
13381
- getMutationQueue(user) {
13666
+ getMutationQueue(user, indexManager) {
13382
13667
  let queue = this.mutationQueues[user.toKey()];
13383
13668
  if (!queue) {
13384
- queue = new MemoryMutationQueue(this.indexManager, this.referenceDelegate);
13669
+ queue = new MemoryMutationQueue(indexManager, this.referenceDelegate);
13385
13670
  this.mutationQueues[user.toKey()] = queue;
13386
13671
  }
13387
13672
  return queue;
@@ -20344,12 +20629,12 @@ async function syncEngineListen(syncEngine, query) {
20344
20629
  }
20345
20630
  else {
20346
20631
  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
20632
  if (syncEngineImpl.isPrimaryClient) {
20351
20633
  remoteStoreListen(syncEngineImpl.remoteStore, targetData);
20352
20634
  }
20635
+ const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
20636
+ targetId = targetData.targetId;
20637
+ viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20353
20638
  }
20354
20639
  return viewSnapshot;
20355
20640
  }
@@ -24857,8 +25142,7 @@ class DocumentSnapshot extends DocumentSnapshot$1 {
24857
25142
  this.metadata = metadata;
24858
25143
  }
24859
25144
  /**
24860
- * Property of the `DocumentSnapshot` that signals whether or not the data
24861
- * exists. True if the document exists.
25145
+ * Returns whether or not the data exists. True if the document exists.
24862
25146
  */
24863
25147
  exists() {
24864
25148
  return super.exists();
@@ -25232,51 +25516,53 @@ function limitToLast(limit) {
25232
25516
  return new QueryLimitConstraint('limitToLast', limit, "L" /* Last */);
25233
25517
  }
25234
25518
  class QueryStartAtConstraint extends QueryConstraint {
25235
- constructor(type, _docOrFields, _before) {
25519
+ constructor(type, _docOrFields, _inclusive) {
25236
25520
  super();
25237
25521
  this.type = type;
25238
25522
  this._docOrFields = _docOrFields;
25239
- this._before = _before;
25523
+ this._inclusive = _inclusive;
25240
25524
  }
25241
25525
  _apply(query) {
25242
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25526
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25243
25527
  return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
25244
25528
  }
25245
25529
  }
25246
25530
  function startAt(...docOrFields) {
25247
- return new QueryStartAtConstraint('startAt', docOrFields, /*before=*/ true);
25531
+ return new QueryStartAtConstraint('startAt', docOrFields,
25532
+ /*inclusive=*/ true);
25248
25533
  }
25249
25534
  function startAfter(...docOrFields) {
25250
25535
  return new QueryStartAtConstraint('startAfter', docOrFields,
25251
- /*before=*/ false);
25536
+ /*inclusive=*/ false);
25252
25537
  }
25253
25538
  class QueryEndAtConstraint extends QueryConstraint {
25254
- constructor(type, _docOrFields, _before) {
25539
+ constructor(type, _docOrFields, _inclusive) {
25255
25540
  super();
25256
25541
  this.type = type;
25257
25542
  this._docOrFields = _docOrFields;
25258
- this._before = _before;
25543
+ this._inclusive = _inclusive;
25259
25544
  }
25260
25545
  _apply(query) {
25261
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25546
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25262
25547
  return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
25263
25548
  }
25264
25549
  }
25265
25550
  function endBefore(...docOrFields) {
25266
- return new QueryEndAtConstraint('endBefore', docOrFields, /*before=*/ true);
25551
+ return new QueryEndAtConstraint('endBefore', docOrFields,
25552
+ /*inclusive=*/ false);
25267
25553
  }
25268
25554
  function endAt(...docOrFields) {
25269
- return new QueryEndAtConstraint('endAt', docOrFields, /*before=*/ false);
25555
+ return new QueryEndAtConstraint('endAt', docOrFields, /*inclusive=*/ true);
25270
25556
  }
25271
25557
  /** Helper function to create a bound from a document or fields */
25272
- function newQueryBoundFromDocOrFields(query, methodName, docOrFields, before) {
25558
+ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
25273
25559
  docOrFields[0] = util$1.getModularInstance(docOrFields[0]);
25274
25560
  if (docOrFields[0] instanceof DocumentSnapshot$1) {
25275
- return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, before);
25561
+ return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive);
25276
25562
  }
25277
25563
  else {
25278
25564
  const reader = newUserDataReader(query.firestore);
25279
- return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, before);
25565
+ return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive);
25280
25566
  }
25281
25567
  }
25282
25568
  function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
@@ -25334,7 +25620,7 @@ function newQueryOrderBy(query, fieldPath, direction) {
25334
25620
  * of the query or if any of the fields in the order by are an uncommitted
25335
25621
  * server timestamp.
25336
25622
  */
25337
- function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25623
+ function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) {
25338
25624
  if (!doc) {
25339
25625
  throw new FirestoreError(Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` +
25340
25626
  `${methodName}().`);
@@ -25371,12 +25657,12 @@ function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25371
25657
  }
25372
25658
  }
25373
25659
  }
25374
- return new Bound(components, before);
25660
+ return new Bound(components, inclusive);
25375
25661
  }
25376
25662
  /**
25377
25663
  * Converts a list of field values to a `Bound` for the given query.
25378
25664
  */
25379
- function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, before) {
25665
+ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) {
25380
25666
  // Use explicit order by's because it has to match the query the user made
25381
25667
  const orderBy = query.explicitOrderBy;
25382
25668
  if (values.length > orderBy.length) {
@@ -25413,7 +25699,7 @@ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, valu
25413
25699
  components.push(wrapped);
25414
25700
  }
25415
25701
  }
25416
- return new Bound(components, before);
25702
+ return new Bound(components, inclusive);
25417
25703
  }
25418
25704
  /**
25419
25705
  * Parses the given `documentIdValue` into a `ReferenceValue`, throwing