@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
@@ -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.b20cf306a";
11
+ const version$1 = "3.4.4-canary.bb8f37c3e";
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.b20cf306a";
64
+ const version = "9.6.6-canary.bb8f37c3e";
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,6 +1217,7 @@ 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 indexing support.
1230
1221
  */
1231
1222
  const SCHEMA_VERSION = 11;
1232
1223
  /**
@@ -1753,9 +1744,7 @@ class DbClientMetadata {
1753
1744
  DbClientMetadata.store = 'clientMetadata';
1754
1745
  /** Keys are automatically assigned via the clientId properties. */
1755
1746
  DbClientMetadata.keyPath = 'clientId';
1756
- /**
1757
- * A object representing a bundle loaded by the SDK.
1758
- */
1747
+ /** An object representing a bundle loaded by the SDK. */
1759
1748
  class DbBundle {
1760
1749
  constructor(
1761
1750
  /** The ID of the loaded bundle. */
@@ -1772,9 +1761,7 @@ class DbBundle {
1772
1761
  /** Name of the IndexedDb object store. */
1773
1762
  DbBundle.store = 'bundles';
1774
1763
  DbBundle.keyPath = 'bundleId';
1775
- /**
1776
- * A object representing a named query loaded by the SDK via a bundle.
1777
- */
1764
+ /** An object representing a named query loaded by the SDK via a bundle. */
1778
1765
  class DbNamedQuery {
1779
1766
  constructor(
1780
1767
  /** The name of the query. */
@@ -1791,6 +1778,116 @@ class DbNamedQuery {
1791
1778
  /** Name of the IndexedDb object store. */
1792
1779
  DbNamedQuery.store = 'namedQueries';
1793
1780
  DbNamedQuery.keyPath = 'name';
1781
+ /** An object representing the global configuration for a field index. */
1782
+ class DbIndexConfiguration {
1783
+ constructor(
1784
+ /**
1785
+ * The index id for this entry. Undefined for indexes that are not yet
1786
+ * persisted.
1787
+ */
1788
+ indexId,
1789
+ /** The collection group this index belongs to. */
1790
+ collectionGroup,
1791
+ /** The fields to index for this index. */
1792
+ fields) {
1793
+ this.indexId = indexId;
1794
+ this.collectionGroup = collectionGroup;
1795
+ this.fields = fields;
1796
+ }
1797
+ }
1798
+ /** Name of the IndexedDb object store. */
1799
+ DbIndexConfiguration.store = 'indexConfiguration';
1800
+ DbIndexConfiguration.keyPath = 'indexId';
1801
+ /**
1802
+ * An index that provides access to the index configurations by collection
1803
+ * group.
1804
+ *
1805
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1806
+ * not possible here as the Web client supports concurrent access to
1807
+ * persistence via multi-tab.
1808
+ */
1809
+ DbIndexConfiguration.collectionGroupIndex = 'collectionGroupIndex';
1810
+ DbIndexConfiguration.collectionGroupIndexPath = 'collectionGroup';
1811
+ /**
1812
+ * An object describing how up-to-date the index backfill is for each user and
1813
+ * index.
1814
+ */
1815
+ class DbIndexState {
1816
+ constructor(
1817
+ /** The index id for this entry. */
1818
+ indexId,
1819
+ /** The user id for this entry. */
1820
+ uid,
1821
+ /**
1822
+ * A number that indicates when the index was last updated (relative to
1823
+ * other indexes).
1824
+ */
1825
+ sequenceNumber,
1826
+ /**
1827
+ * The latest read time that has been indexed by Firestore for this field
1828
+ * index. Set to `{seconds: 0, nanos: 0}` if no documents have been indexed.
1829
+ */
1830
+ readTime,
1831
+ /**
1832
+ * The last document that has been indexed for this field index. Empty if
1833
+ * no documents have been indexed.
1834
+ */
1835
+ documentKey,
1836
+ /**
1837
+ * The largest mutation batch id that has been processed for this index. -1
1838
+ * if no mutations have been indexed.
1839
+ */
1840
+ largestBatchId) {
1841
+ this.indexId = indexId;
1842
+ this.uid = uid;
1843
+ this.sequenceNumber = sequenceNumber;
1844
+ this.readTime = readTime;
1845
+ this.documentKey = documentKey;
1846
+ this.largestBatchId = largestBatchId;
1847
+ }
1848
+ }
1849
+ /** Name of the IndexedDb object store. */
1850
+ DbIndexState.store = 'indexState';
1851
+ DbIndexState.keyPath = ['indexId', 'uid'];
1852
+ /**
1853
+ * An index that provides access to documents in a collection sorted by last
1854
+ * update time. Used by the backfiller.
1855
+ *
1856
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1857
+ * not possible here as the Web client supports concurrent access to
1858
+ * persistence via multi-tab.
1859
+ */
1860
+ DbIndexState.sequenceNumberIndex = 'sequenceNumberIndex';
1861
+ DbIndexState.sequenceNumberIndexPath = ['uid', 'sequenceNumber'];
1862
+ /** An object that stores the encoded entries for all documents and fields. */
1863
+ class DbIndexEntry {
1864
+ constructor(
1865
+ /** The index id for this entry. */
1866
+ indexId,
1867
+ /** The user id for this entry. */
1868
+ uid,
1869
+ /** The encoded array index value for this entry. */
1870
+ arrayValue,
1871
+ /** The encoded directional value for equality and inequality filters. */
1872
+ directionalValue,
1873
+ /** The document key this entry points to. */
1874
+ documentKey) {
1875
+ this.indexId = indexId;
1876
+ this.uid = uid;
1877
+ this.arrayValue = arrayValue;
1878
+ this.directionalValue = directionalValue;
1879
+ this.documentKey = documentKey;
1880
+ }
1881
+ }
1882
+ /** Name of the IndexedDb object store. */
1883
+ DbIndexEntry.store = 'indexEntries';
1884
+ DbIndexEntry.keyPath = [
1885
+ 'indexId',
1886
+ 'uid',
1887
+ 'arrayValue',
1888
+ 'directionalValue',
1889
+ 'documentKey'
1890
+ ];
1794
1891
  // Visible for testing
1795
1892
  const V1_STORES = [
1796
1893
  DbMutationQueue.store,
@@ -1805,7 +1902,6 @@ const V1_STORES = [
1805
1902
  // V2 is no longer usable (see comment at top of file)
1806
1903
  // Visible for testing
1807
1904
  const V3_STORES = V1_STORES;
1808
- // Visible for testing
1809
1905
  // Note: DbRemoteDocumentChanges is no longer used and dropped with v9.
1810
1906
  const V4_STORES = [...V3_STORES, DbClientMetadata.store];
1811
1907
  // V5 does not change the set of stores.
@@ -1815,12 +1911,24 @@ const V8_STORES = [...V6_STORES, DbCollectionParent.store];
1815
1911
  // V9 does not change the set of stores.
1816
1912
  // V10 does not change the set of stores.
1817
1913
  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;
1914
+ const V12_STORES = [
1915
+ ...V11_STORES,
1916
+ DbIndexConfiguration.store,
1917
+ DbIndexState.store,
1918
+ DbIndexEntry.store
1919
+ ];
1920
+ /** Returns the object stores for the provided schema. */
1921
+ function getObjectStores(schemaVersion) {
1922
+ if (schemaVersion === 12) {
1923
+ return V12_STORES;
1924
+ }
1925
+ else if (schemaVersion === 11) {
1926
+ return V11_STORES;
1927
+ }
1928
+ else {
1929
+ fail();
1930
+ }
1931
+ }
1824
1932
 
1825
1933
  /**
1826
1934
  * @license
@@ -2117,6 +2225,15 @@ class SimpleDbTransaction {
2117
2225
  this.transaction.abort();
2118
2226
  }
2119
2227
  }
2228
+ maybeCommit() {
2229
+ // If the browser supports V3 IndexedDB, we invoke commit() explicitly to
2230
+ // speed up index DB processing if the event loop remains blocks.
2231
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2232
+ const maybeV3IndexedDb = this.transaction;
2233
+ if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {
2234
+ maybeV3IndexedDb.commit();
2235
+ }
2236
+ }
2120
2237
  /**
2121
2238
  * Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
2122
2239
  * operations performed on the SimpleDbStore happen within the context of this
@@ -2313,6 +2430,10 @@ class SimpleDb {
2313
2430
  this.db = await this.ensureDb(action);
2314
2431
  const transaction = SimpleDbTransaction.open(this.db, action, readonly ? 'readonly' : 'readwrite', objectStores);
2315
2432
  const transactionFnResult = transactionFn(transaction)
2433
+ .next(result => {
2434
+ transaction.maybeCommit();
2435
+ return result;
2436
+ })
2316
2437
  .catch(error => {
2317
2438
  // Abort the transaction if there was an error.
2318
2439
  transaction.abort(error);
@@ -2485,13 +2606,29 @@ class SimpleDbStore {
2485
2606
  return wrapRequest(request);
2486
2607
  }
2487
2608
  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
- });
2609
+ const iterateOptions = this.options(indexOrRange, range);
2610
+ // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly
2611
+ // 20% faster. Unfortunately, getAll() does not support custom indices.
2612
+ if (!iterateOptions.index && typeof this.store.getAll === 'function') {
2613
+ const request = this.store.getAll(iterateOptions.range);
2614
+ return new PersistencePromise((resolve, reject) => {
2615
+ request.onerror = (event) => {
2616
+ reject(event.target.error);
2617
+ };
2618
+ request.onsuccess = (event) => {
2619
+ resolve(event.target.result);
2620
+ };
2621
+ });
2622
+ }
2623
+ else {
2624
+ const cursor = this.cursor(iterateOptions);
2625
+ const results = [];
2626
+ return this.iterateCursor(cursor, (key, value) => {
2627
+ results.push(value);
2628
+ }).next(() => {
2629
+ return results;
2630
+ });
2631
+ }
2495
2632
  }
2496
2633
  deleteAll(indexOrRange, range) {
2497
2634
  logDebug(LOG_TAG$g, 'DELETE ALL', this.store.name);
@@ -4345,12 +4482,12 @@ class FieldIndex {
4345
4482
  /** The collection ID this index applies to. */
4346
4483
  collectionGroup,
4347
4484
  /** The field segments for this index. */
4348
- segments,
4485
+ fields,
4349
4486
  /** Shows how up-to-date the index is for the current user. */
4350
4487
  indexState) {
4351
4488
  this.indexId = indexId;
4352
4489
  this.collectionGroup = collectionGroup;
4353
- this.segments = segments;
4490
+ this.fields = fields;
4354
4491
  this.indexState = indexState;
4355
4492
  }
4356
4493
  }
@@ -4460,27 +4597,29 @@ function newTarget(path, collectionGroup = null, orderBy = [], filters = [], lim
4460
4597
  function canonifyTarget(target) {
4461
4598
  const targetImpl = debugCast(target);
4462
4599
  if (targetImpl.memoizedCanonicalId === null) {
4463
- let canonicalId = targetImpl.path.canonicalString();
4600
+ let str = targetImpl.path.canonicalString();
4464
4601
  if (targetImpl.collectionGroup !== null) {
4465
- canonicalId += '|cg:' + targetImpl.collectionGroup;
4602
+ str += '|cg:' + targetImpl.collectionGroup;
4466
4603
  }
4467
- canonicalId += '|f:';
4468
- canonicalId += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4469
- canonicalId += '|ob:';
4470
- canonicalId += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4604
+ str += '|f:';
4605
+ str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4606
+ str += '|ob:';
4607
+ str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4471
4608
  if (!isNullOrUndefined(targetImpl.limit)) {
4472
- canonicalId += '|l:';
4473
- canonicalId += targetImpl.limit;
4609
+ str += '|l:';
4610
+ str += targetImpl.limit;
4474
4611
  }
4475
4612
  if (targetImpl.startAt) {
4476
- canonicalId += '|lb:';
4477
- canonicalId += canonifyBound(targetImpl.startAt);
4613
+ str += '|lb:';
4614
+ str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
4615
+ str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
4478
4616
  }
4479
4617
  if (targetImpl.endAt) {
4480
- canonicalId += '|ub:';
4481
- canonicalId += canonifyBound(targetImpl.endAt);
4618
+ str += '|ub:';
4619
+ str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
4620
+ str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
4482
4621
  }
4483
- targetImpl.memoizedCanonicalId = canonicalId;
4622
+ targetImpl.memoizedCanonicalId = str;
4484
4623
  }
4485
4624
  return targetImpl.memoizedCanonicalId;
4486
4625
  }
@@ -4503,10 +4642,14 @@ function stringifyTarget(target) {
4503
4642
  .join(', ')}]`;
4504
4643
  }
4505
4644
  if (target.startAt) {
4506
- str += ', startAt: ' + canonifyBound(target.startAt);
4645
+ str += ', startAt: ';
4646
+ str += target.startAt.inclusive ? 'b:' : 'a:';
4647
+ str += target.startAt.position.map(p => canonicalId(p)).join(',');
4507
4648
  }
4508
4649
  if (target.endAt) {
4509
- str += ', endAt: ' + canonifyBound(target.endAt);
4650
+ str += ', endAt: ';
4651
+ str += target.endAt.inclusive ? 'a:' : 'b:';
4652
+ str += target.endAt.position.map(p => canonicalId(p)).join(',');
4510
4653
  }
4511
4654
  return `Target(${str})`;
4512
4655
  }
@@ -4729,7 +4872,6 @@ class ArrayContainsAnyFilter extends FieldFilter {
4729
4872
  return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
4730
4873
  }
4731
4874
  }
4732
- // TODO(indexing): Change Bound.before to "inclusive"
4733
4875
  /**
4734
4876
  * Represents a bound of a query.
4735
4877
  *
@@ -4745,17 +4887,11 @@ class ArrayContainsAnyFilter extends FieldFilter {
4745
4887
  * just after the provided values.
4746
4888
  */
4747
4889
  class Bound {
4748
- constructor(position, before) {
4890
+ constructor(position, inclusive) {
4749
4891
  this.position = position;
4750
- this.before = before;
4892
+ this.inclusive = inclusive;
4751
4893
  }
4752
4894
  }
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
4895
  /**
4760
4896
  * An ordering on a field, in some Direction. Direction defaults to ASCENDING.
4761
4897
  */
@@ -4775,11 +4911,7 @@ function stringifyOrderBy(orderBy) {
4775
4911
  function orderByEquals(left, right) {
4776
4912
  return left.dir === right.dir && left.field.isEqual(right.field);
4777
4913
  }
4778
- /**
4779
- * Returns true if a document sorts before a bound using the provided sort
4780
- * order.
4781
- */
4782
- function sortsBeforeDocument(bound, orderBy, doc) {
4914
+ function boundCompareToDocument(bound, orderBy, doc) {
4783
4915
  let comparison = 0;
4784
4916
  for (let i = 0; i < bound.position.length; i++) {
4785
4917
  const orderByComponent = orderBy[i];
@@ -4798,7 +4930,23 @@ function sortsBeforeDocument(bound, orderBy, doc) {
4798
4930
  break;
4799
4931
  }
4800
4932
  }
4801
- return bound.before ? comparison <= 0 : comparison < 0;
4933
+ return comparison;
4934
+ }
4935
+ /**
4936
+ * Returns true if a document sorts after a bound using the provided sort
4937
+ * order.
4938
+ */
4939
+ function boundSortsAfterDocument(bound, orderBy, doc) {
4940
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4941
+ return bound.inclusive ? comparison >= 0 : comparison > 0;
4942
+ }
4943
+ /**
4944
+ * Returns true if a document sorts before a bound using the provided sort
4945
+ * order.
4946
+ */
4947
+ function boundSortsBeforeDocument(bound, orderBy, doc) {
4948
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4949
+ return bound.inclusive ? comparison <= 0 : comparison < 0;
4802
4950
  }
4803
4951
  function boundEquals(left, right) {
4804
4952
  if (left === null) {
@@ -4807,7 +4955,7 @@ function boundEquals(left, right) {
4807
4955
  else if (right === null) {
4808
4956
  return false;
4809
4957
  }
4810
- if (left.before !== right.before ||
4958
+ if (left.inclusive !== right.inclusive ||
4811
4959
  left.position.length !== right.position.length) {
4812
4960
  return false;
4813
4961
  }
@@ -5011,10 +5159,10 @@ function queryToTarget(query) {
5011
5159
  }
5012
5160
  // We need to swap the cursors to match the now-flipped query ordering.
5013
5161
  const startAt = queryImpl.endAt
5014
- ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.before)
5162
+ ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
5015
5163
  : null;
5016
5164
  const endAt = queryImpl.startAt
5017
- ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.before)
5165
+ ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
5018
5166
  : null;
5019
5167
  // Now return as a LimitType.First query.
5020
5168
  queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
@@ -5102,11 +5250,11 @@ function queryMatchesFilters(query, doc) {
5102
5250
  /** Makes sure a document is within the bounds, if provided. */
5103
5251
  function queryMatchesBounds(query, doc) {
5104
5252
  if (query.startAt &&
5105
- !sortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5253
+ !boundSortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5106
5254
  return false;
5107
5255
  }
5108
5256
  if (query.endAt &&
5109
- sortsBeforeDocument(query.endAt, queryOrderBy(query), doc)) {
5257
+ !boundSortsAfterDocument(query.endAt, queryOrderBy(query), doc)) {
5110
5258
  return false;
5111
5259
  }
5112
5260
  return true;
@@ -7985,10 +8133,10 @@ function toQueryTarget(serializer, target) {
7985
8133
  result.structuredQuery.limit = limit;
7986
8134
  }
7987
8135
  if (target.startAt) {
7988
- result.structuredQuery.startAt = toCursor(target.startAt);
8136
+ result.structuredQuery.startAt = toStartAtCursor(target.startAt);
7989
8137
  }
7990
8138
  if (target.endAt) {
7991
- result.structuredQuery.endAt = toCursor(target.endAt);
8139
+ result.structuredQuery.endAt = toEndAtCursor(target.endAt);
7992
8140
  }
7993
8141
  return result;
7994
8142
  }
@@ -8021,11 +8169,11 @@ function convertQueryTargetToQuery(target) {
8021
8169
  }
8022
8170
  let startAt = null;
8023
8171
  if (query.startAt) {
8024
- startAt = fromCursor(query.startAt);
8172
+ startAt = fromStartAtCursor(query.startAt);
8025
8173
  }
8026
8174
  let endAt = null;
8027
8175
  if (query.endAt) {
8028
- endAt = fromCursor(query.endAt);
8176
+ endAt = fromEndAtCursor(query.endAt);
8029
8177
  }
8030
8178
  return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
8031
8179
  }
@@ -8116,16 +8264,27 @@ function toOrder(orderBys) {
8116
8264
  function fromOrder(orderBys) {
8117
8265
  return orderBys.map(order => fromPropertyOrder(order));
8118
8266
  }
8119
- function toCursor(cursor) {
8267
+ function toStartAtCursor(cursor) {
8120
8268
  return {
8121
- before: cursor.before,
8269
+ before: cursor.inclusive,
8122
8270
  values: cursor.position
8123
8271
  };
8124
8272
  }
8125
- function fromCursor(cursor) {
8126
- const before = !!cursor.before;
8273
+ function toEndAtCursor(cursor) {
8274
+ return {
8275
+ before: !cursor.inclusive,
8276
+ values: cursor.position
8277
+ };
8278
+ }
8279
+ function fromStartAtCursor(cursor) {
8280
+ const inclusive = !!cursor.before;
8281
+ const position = cursor.values || [];
8282
+ return new Bound(position, inclusive);
8283
+ }
8284
+ function fromEndAtCursor(cursor) {
8285
+ const inclusive = !cursor.before;
8127
8286
  const position = cursor.values || [];
8128
- return new Bound(position, before);
8287
+ return new Bound(position, inclusive);
8129
8288
  }
8130
8289
  // visible for testing
8131
8290
  function toDirection(dir) {
@@ -8589,6 +8748,19 @@ function fromBundleMetadata(metadata) {
8589
8748
  version: metadata.version,
8590
8749
  createTime: fromVersion(metadata.createTime)
8591
8750
  };
8751
+ }
8752
+ function toDbIndexConfiguration(index) {
8753
+ return new DbIndexConfiguration(index.indexId, index.collectionGroup, index.fields.map(s => [s.fieldPath.canonicalString(), s.kind]));
8754
+ }
8755
+ function fromDbIndexConfiguration(index, state) {
8756
+ const decodedState = state
8757
+ ? new IndexState(state.sequenceNumber, new IndexOffset(fromDbTimestamp(state.readTime), new DocumentKey(decodeResourcePath(state.documentKey)), state.largestBatchId))
8758
+ : IndexState.empty();
8759
+ const decodedSegments = index.fields.map(([fieldPath, kind]) => new IndexSegment(FieldPath$1.fromServerFormat(fieldPath), kind));
8760
+ return new FieldIndex(index.indexId, index.collectionGroup, decodedSegments, decodedState);
8761
+ }
8762
+ function toDbIndexState(indexId, user, sequenceNumber, offset) {
8763
+ return new DbIndexState(indexId, user.uid || '', sequenceNumber, toDbTimestamp(offset.readTime), encodeResourcePath(offset.documentKey.path), offset.largestBatchId);
8592
8764
  }
8593
8765
 
8594
8766
  /**
@@ -8678,6 +8850,38 @@ class MemoryIndexManager {
8678
8850
  getCollectionParents(transaction, collectionId) {
8679
8851
  return PersistencePromise.resolve(this.collectionParentIndex.getEntries(collectionId));
8680
8852
  }
8853
+ addFieldIndex(transaction, index) {
8854
+ // Field indices are not supported with memory persistence.
8855
+ return PersistencePromise.resolve();
8856
+ }
8857
+ deleteFieldIndex(transaction, index) {
8858
+ // Field indices are not supported with memory persistence.
8859
+ return PersistencePromise.resolve();
8860
+ }
8861
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
8862
+ // Field indices are not supported with memory persistence.
8863
+ return PersistencePromise.resolve(documentKeySet());
8864
+ }
8865
+ getFieldIndex(transaction, target) {
8866
+ // Field indices are not supported with memory persistence.
8867
+ return PersistencePromise.resolve(null);
8868
+ }
8869
+ getFieldIndexes(transaction, collectionGroup) {
8870
+ // Field indices are not supported with memory persistence.
8871
+ return PersistencePromise.resolve([]);
8872
+ }
8873
+ getNextCollectionGroupToUpdate(transaction) {
8874
+ // Field indices are not supported with memory persistence.
8875
+ return PersistencePromise.resolve(null);
8876
+ }
8877
+ updateCollectionGroup(transaction, collectionGroup, offset) {
8878
+ // Field indices are not supported with memory persistence.
8879
+ return PersistencePromise.resolve();
8880
+ }
8881
+ updateIndexEntries(transaction, documents) {
8882
+ // Field indices are not supported with memory persistence.
8883
+ return PersistencePromise.resolve();
8884
+ }
8681
8885
  }
8682
8886
  /**
8683
8887
  * Internal implementation of the collection-parent index exposed by MemoryIndexManager.
@@ -8729,17 +8933,22 @@ class MemoryCollectionParentIndex {
8729
8933
  */
8730
8934
  /**
8731
8935
  * A persisted implementation of IndexManager.
8936
+ *
8937
+ * PORTING NOTE: Unlike iOS and Android, the Web SDK does not memoize index
8938
+ * data as it supports multi-tab access.
8732
8939
  */
8733
8940
  class IndexedDbIndexManager {
8734
- constructor() {
8941
+ constructor(user) {
8942
+ this.user = user;
8735
8943
  /**
8736
8944
  * An in-memory copy of the index entries we've already written since the SDK
8737
8945
  * launched. Used to avoid re-writing the same entry repeatedly.
8738
8946
  *
8739
- * This is *NOT* a complete cache of what's in persistence and so can never be used to
8740
- * satisfy reads.
8947
+ * This is *NOT* a complete cache of what's in persistence and so can never be
8948
+ * used to satisfy reads.
8741
8949
  */
8742
8950
  this.collectionParentsCache = new MemoryCollectionParentIndex();
8951
+ this.uid = user.uid || '';
8743
8952
  }
8744
8953
  /**
8745
8954
  * Adds a new entry to the collection parent index.
@@ -8786,6 +8995,85 @@ class IndexedDbIndexManager {
8786
8995
  return parentPaths;
8787
8996
  });
8788
8997
  }
8998
+ addFieldIndex(transaction, index) {
8999
+ // TODO(indexing): Verify that the auto-incrementing index ID works in
9000
+ // Safari & Firefox.
9001
+ const indexes = indexConfigurationStore(transaction);
9002
+ const dbIndex = toDbIndexConfiguration(index);
9003
+ delete dbIndex.indexId; // `indexId` is auto-populated by IndexedDb
9004
+ return indexes.add(dbIndex).next();
9005
+ }
9006
+ deleteFieldIndex(transaction, index) {
9007
+ const indexes = indexConfigurationStore(transaction);
9008
+ const states = indexStateStore(transaction);
9009
+ const entries = indexEntriesStore(transaction);
9010
+ return indexes
9011
+ .delete(index.indexId)
9012
+ .next(() => states.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9013
+ /*lowerOpen=*/ false,
9014
+ /*upperOpen=*/ true)))
9015
+ .next(() => entries.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9016
+ /*lowerOpen=*/ false,
9017
+ /*upperOpen=*/ true)));
9018
+ }
9019
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9020
+ // TODO(indexing): Implement
9021
+ return PersistencePromise.resolve(documentKeySet());
9022
+ }
9023
+ getFieldIndex(transaction, target) {
9024
+ // TODO(indexing): Implement
9025
+ return PersistencePromise.resolve(null);
9026
+ }
9027
+ getFieldIndexes(transaction, collectionGroup) {
9028
+ const indexes = indexConfigurationStore(transaction);
9029
+ const states = indexStateStore(transaction);
9030
+ return (collectionGroup
9031
+ ? indexes.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9032
+ : indexes.loadAll()).next(indexConfigs => {
9033
+ const result = [];
9034
+ return PersistencePromise.forEach(indexConfigs, (indexConfig) => {
9035
+ return states
9036
+ .get([indexConfig.indexId, this.uid])
9037
+ .next(indexState => {
9038
+ result.push(fromDbIndexConfiguration(indexConfig, indexState));
9039
+ });
9040
+ }).next(() => result);
9041
+ });
9042
+ }
9043
+ getNextCollectionGroupToUpdate(transaction) {
9044
+ return this.getFieldIndexes(transaction).next(indexes => {
9045
+ if (indexes.length === 0) {
9046
+ return null;
9047
+ }
9048
+ indexes.sort((l, r) => l.indexState.sequenceNumber - r.indexState.sequenceNumber);
9049
+ return indexes[0].collectionGroup;
9050
+ });
9051
+ }
9052
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9053
+ const indexes = indexConfigurationStore(transaction);
9054
+ const states = indexStateStore(transaction);
9055
+ return this.getNextSequenceNumber(transaction).next(nextSequenceNumber => indexes
9056
+ .loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9057
+ .next(configs => PersistencePromise.forEach(configs, (config) => states.put(toDbIndexState(config.indexId, this.user, nextSequenceNumber, offset)))));
9058
+ }
9059
+ updateIndexEntries(transaction, documents) {
9060
+ // TODO(indexing): Implement
9061
+ return PersistencePromise.resolve();
9062
+ }
9063
+ getNextSequenceNumber(transaction) {
9064
+ let nextSequenceNumber = 1;
9065
+ const states = indexStateStore(transaction);
9066
+ return states
9067
+ .iterate({
9068
+ index: DbIndexState.sequenceNumberIndex,
9069
+ reverse: true,
9070
+ range: IDBKeyRange.upperBound([this.uid, Number.MAX_SAFE_INTEGER])
9071
+ }, (_, state, controller) => {
9072
+ controller.done();
9073
+ nextSequenceNumber = state.sequenceNumber + 1;
9074
+ })
9075
+ .next(() => nextSequenceNumber);
9076
+ }
8789
9077
  }
8790
9078
  /**
8791
9079
  * Helper to get a typed SimpleDbStore for the collectionParents
@@ -8793,6 +9081,24 @@ class IndexedDbIndexManager {
8793
9081
  */
8794
9082
  function collectionParentsStore(txn) {
8795
9083
  return getStore(txn, DbCollectionParent.store);
9084
+ }
9085
+ /**
9086
+ * Helper to get a typed SimpleDbStore for the index entry object store.
9087
+ */
9088
+ function indexEntriesStore(txn) {
9089
+ return getStore(txn, DbIndexEntry.store);
9090
+ }
9091
+ /**
9092
+ * Helper to get a typed SimpleDbStore for the index configuration object store.
9093
+ */
9094
+ function indexConfigurationStore(txn) {
9095
+ return getStore(txn, DbIndexConfiguration.store);
9096
+ }
9097
+ /**
9098
+ * Helper to get a typed SimpleDbStore for the index state object store.
9099
+ */
9100
+ function indexStateStore(txn) {
9101
+ return getStore(txn, DbIndexState.store);
8796
9102
  }
8797
9103
 
8798
9104
  /**
@@ -10262,12 +10568,10 @@ class RemoteDocumentChangeBuffer {
10262
10568
  * `newIndexedDbRemoteDocumentCache()`.
10263
10569
  */
10264
10570
  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) {
10571
+ constructor(serializer) {
10270
10572
  this.serializer = serializer;
10573
+ }
10574
+ setIndexManager(indexManager) {
10271
10575
  this.indexManager = indexManager;
10272
10576
  }
10273
10577
  /**
@@ -10389,21 +10693,21 @@ class IndexedDbRemoteDocumentCacheImpl {
10389
10693
  }
10390
10694
  });
10391
10695
  }
10392
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
10696
+ getAll(transaction, collection, sinceReadTime) {
10393
10697
  let results = mutableDocumentMap();
10394
- const immediateChildrenPathLength = query.path.length + 1;
10698
+ const immediateChildrenPathLength = collection.length + 1;
10395
10699
  const iterationOptions = {};
10396
10700
  if (sinceReadTime.isEqual(SnapshotVersion.min())) {
10397
10701
  // Documents are ordered by key, so we can use a prefix scan to narrow
10398
10702
  // down the documents we need to match the query against.
10399
- const startKey = query.path.toArray();
10703
+ const startKey = collection.toArray();
10400
10704
  iterationOptions.range = IDBKeyRange.lowerBound(startKey);
10401
10705
  }
10402
10706
  else {
10403
10707
  // Execute an index-free query and filter by read time. This is safe
10404
10708
  // since all document changes to queries that have a
10405
10709
  // lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read time set.
10406
- const collectionKey = query.path.toArray();
10710
+ const collectionKey = collection.toArray();
10407
10711
  const readTimeKey = toDbTimestampKey(sinceReadTime);
10408
10712
  iterationOptions.range = IDBKeyRange.lowerBound([collectionKey, readTimeKey],
10409
10713
  /* open= */ true);
@@ -10420,12 +10724,12 @@ class IndexedDbRemoteDocumentCacheImpl {
10420
10724
  return;
10421
10725
  }
10422
10726
  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)) {
10727
+ if (collection.isPrefixOf(document.key.path)) {
10427
10728
  results = results.insert(document.key, document);
10428
10729
  }
10730
+ else {
10731
+ control.done();
10732
+ }
10429
10733
  })
10430
10734
  .next(() => results);
10431
10735
  }
@@ -10463,14 +10767,9 @@ class IndexedDbRemoteDocumentCacheImpl {
10463
10767
  return MutableDocument.newInvalidDocument(documentKey);
10464
10768
  }
10465
10769
  }
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);
10770
+ /** Creates a new IndexedDbRemoteDocumentCache. */
10771
+ function newIndexedDbRemoteDocumentCache(serializer) {
10772
+ return new IndexedDbRemoteDocumentCacheImpl(serializer);
10474
10773
  }
10475
10774
  /**
10476
10775
  * Returns the set of documents that have changed since the specified read
@@ -10637,9 +10936,6 @@ class SchemaConverter {
10637
10936
  * and local feature development.
10638
10937
  */
10639
10938
  createOrUpgrade(db, txn, fromVersion, toVersion) {
10640
- hardAssert(fromVersion < toVersion &&
10641
- fromVersion >= 0 &&
10642
- toVersion <= SCHEMA_VERSION);
10643
10939
  const simpleDbTransaction = new SimpleDbTransaction('createOrUpgrade', txn);
10644
10940
  if (fromVersion < 1 && toVersion >= 1) {
10645
10941
  createPrimaryClientStore(db);
@@ -10706,6 +11002,11 @@ class SchemaConverter {
10706
11002
  createNamedQueriesStore(db);
10707
11003
  });
10708
11004
  }
11005
+ if (fromVersion < 12 && toVersion >= 12) {
11006
+ p = p.next(() => {
11007
+ createFieldIndex(db);
11008
+ });
11009
+ }
10709
11010
  return p;
10710
11011
  }
10711
11012
  addDocumentGlobal(txn) {
@@ -10912,6 +11213,20 @@ function createNamedQueriesStore(db) {
10912
11213
  db.createObjectStore(DbNamedQuery.store, {
10913
11214
  keyPath: DbNamedQuery.keyPath
10914
11215
  });
11216
+ }
11217
+ function createFieldIndex(db) {
11218
+ const indexConfiguratioStore = db.createObjectStore(DbIndexConfiguration.store, {
11219
+ keyPath: DbIndexConfiguration.keyPath,
11220
+ autoIncrement: true
11221
+ });
11222
+ indexConfiguratioStore.createIndex(DbIndexConfiguration.collectionGroupIndex, DbIndexConfiguration.collectionGroupIndexPath, { unique: false });
11223
+ const indexStateStore = db.createObjectStore(DbIndexState.store, {
11224
+ keyPath: DbIndexState.keyPath
11225
+ });
11226
+ indexStateStore.createIndex(DbIndexState.sequenceNumberIndex, DbIndexState.sequenceNumberIndexPath, { unique: false });
11227
+ db.createObjectStore(DbIndexEntry.store, {
11228
+ keyPath: DbIndexEntry.keyPath
11229
+ });
10915
11230
  }
10916
11231
 
10917
11232
  /**
@@ -11023,7 +11338,7 @@ class IndexedDbPersistence {
11023
11338
  * If set to true, forcefully obtains database access. Existing tabs will
11024
11339
  * no longer be able to access IndexedDB.
11025
11340
  */
11026
- forceOwningTab) {
11341
+ forceOwningTab, schemaVersion = SCHEMA_VERSION) {
11027
11342
  this.allowTabSynchronization = allowTabSynchronization;
11028
11343
  this.persistenceKey = persistenceKey;
11029
11344
  this.clientId = clientId;
@@ -11032,6 +11347,7 @@ class IndexedDbPersistence {
11032
11347
  this.document = document;
11033
11348
  this.sequenceNumberSyncer = sequenceNumberSyncer;
11034
11349
  this.forceOwningTab = forceOwningTab;
11350
+ this.schemaVersion = schemaVersion;
11035
11351
  this.listenSequence = null;
11036
11352
  this._started = false;
11037
11353
  this.isPrimary = false;
@@ -11053,10 +11369,9 @@ class IndexedDbPersistence {
11053
11369
  this.referenceDelegate = new IndexedDbLruDelegateImpl(this, lruParams);
11054
11370
  this.dbName = persistenceKey + MAIN_DATABASE;
11055
11371
  this.serializer = new LocalSerializer(serializer);
11056
- this.simpleDb = new SimpleDb(this.dbName, SCHEMA_VERSION, new SchemaConverter(this.serializer));
11372
+ this.simpleDb = new SimpleDb(this.dbName, this.schemaVersion, new SchemaConverter(this.serializer));
11057
11373
  this.targetCache = new IndexedDbTargetCache(this.referenceDelegate, this.serializer);
11058
- this.indexManager = new IndexedDbIndexManager();
11059
- this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer, this.indexManager);
11374
+ this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer);
11060
11375
  this.bundleCache = new IndexedDbBundleCache();
11061
11376
  if (this.window && this.window.localStorage) {
11062
11377
  this.webStorage = this.window.localStorage;
@@ -11392,8 +11707,8 @@ class IndexedDbPersistence {
11392
11707
  get started() {
11393
11708
  return this._started;
11394
11709
  }
11395
- getMutationQueue(user) {
11396
- return IndexedDbMutationQueue.forUser(user, this.serializer, this.indexManager, this.referenceDelegate);
11710
+ getMutationQueue(user, indexManager) {
11711
+ return IndexedDbMutationQueue.forUser(user, this.serializer, indexManager, this.referenceDelegate);
11397
11712
  }
11398
11713
  getTargetCache() {
11399
11714
  return this.targetCache;
@@ -11401,8 +11716,8 @@ class IndexedDbPersistence {
11401
11716
  getRemoteDocumentCache() {
11402
11717
  return this.remoteDocumentCache;
11403
11718
  }
11404
- getIndexManager() {
11405
- return this.indexManager;
11719
+ getIndexManager(user) {
11720
+ return new IndexedDbIndexManager(user);
11406
11721
  }
11407
11722
  getBundleCache() {
11408
11723
  return this.bundleCache;
@@ -11410,11 +11725,12 @@ class IndexedDbPersistence {
11410
11725
  runTransaction(action, mode, transactionOperation) {
11411
11726
  logDebug(LOG_TAG$d, 'Starting transaction:', action);
11412
11727
  const simpleDbMode = mode === 'readonly' ? 'readonly' : 'readwrite';
11728
+ const objectStores = getObjectStores(this.schemaVersion);
11413
11729
  let persistenceTransaction;
11414
11730
  // Do all transactions as readwrite against all object stores, since we
11415
11731
  // are the only reader/writer.
11416
11732
  return this.simpleDb
11417
- .runTransaction(action, simpleDbMode, ALL_STORES, simpleDbTxn => {
11733
+ .runTransaction(action, simpleDbMode, objectStores, simpleDbTxn => {
11418
11734
  persistenceTransaction = new IndexedDbTransaction(simpleDbTxn, this.listenSequence
11419
11735
  ? this.listenSequence.next()
11420
11736
  : ListenSequence.INVALID);
@@ -11786,39 +12102,28 @@ class LocalDocumentsView {
11786
12102
  getDocumentsMatchingCollectionQuery(transaction, query, sinceReadTime) {
11787
12103
  // Query the remote documents and overlay mutations.
11788
12104
  let results;
11789
- let mutationBatches;
11790
12105
  return this.remoteDocumentCache
11791
- .getDocumentsMatchingQuery(transaction, query, sinceReadTime)
12106
+ .getAll(transaction, query.path, sinceReadTime)
11792
12107
  .next(queryResults => {
11793
12108
  results = queryResults;
11794
12109
  return this.mutationQueue.getAllMutationBatchesAffectingQuery(transaction, query);
11795
12110
  })
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
- }
12111
+ .next(mutationBatches => {
12112
+ for (const batch of mutationBatches) {
12113
+ for (const mutation of batch.mutations) {
12114
+ const key = mutation.key;
12115
+ let document = results.get(key);
12116
+ if (document == null) {
12117
+ // Create invalid document to apply mutations on top of
12118
+ document = MutableDocument.newInvalidDocument(key);
12119
+ results = results.insert(key, document);
12120
+ }
12121
+ mutationApplyToLocalView(mutation, document, batch.localWriteTime);
12122
+ if (!document.isFoundDocument()) {
12123
+ results = results.remove(key);
11819
12124
  }
11820
12125
  }
11821
- });
12126
+ }
11822
12127
  })
11823
12128
  .next(() => {
11824
12129
  // Finally, filter out any documents that don't actually match
@@ -11831,29 +12136,6 @@ class LocalDocumentsView {
11831
12136
  return results;
11832
12137
  });
11833
12138
  }
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
12139
  }
11858
12140
 
11859
12141
  /**
@@ -11912,11 +12194,18 @@ class LocalStoreImpl {
11912
12194
  * PORTING NOTE: This is only used for multi-tab synchronization.
11913
12195
  */
11914
12196
  this.lastDocumentChangeReadTime = SnapshotVersion.min();
11915
- this.mutationQueue = persistence.getMutationQueue(initialUser);
11916
12197
  this.remoteDocuments = persistence.getRemoteDocumentCache();
11917
12198
  this.targetCache = persistence.getTargetCache();
11918
- this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.persistence.getIndexManager());
11919
12199
  this.bundleCache = persistence.getBundleCache();
12200
+ this.initializeUserComponents(initialUser);
12201
+ }
12202
+ initializeUserComponents(user) {
12203
+ // TODO(indexing): Add spec tests that test these components change after a
12204
+ // user change
12205
+ this.indexManager = this.persistence.getIndexManager(user);
12206
+ this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
12207
+ this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
12208
+ this.remoteDocuments.setIndexManager(this.indexManager);
11920
12209
  this.queryEngine.setLocalDocumentsView(this.localDocuments);
11921
12210
  }
11922
12211
  collectGarbage(garbageCollector) {
@@ -11938,8 +12227,6 @@ persistence, queryEngine, initialUser, serializer) {
11938
12227
  // change.
11939
12228
  async function localStoreHandleUserChange(localStore, user) {
11940
12229
  const localStoreImpl = debugCast(localStore);
11941
- let newMutationQueue = localStoreImpl.mutationQueue;
11942
- let newLocalDocuments = localStoreImpl.localDocuments;
11943
12230
  const result = await localStoreImpl.persistence.runTransaction('Handle user change', 'readonly', txn => {
11944
12231
  // Swap out the mutation queue, grabbing the pending mutation batches
11945
12232
  // before and after.
@@ -11948,11 +12235,8 @@ async function localStoreHandleUserChange(localStore, user) {
11948
12235
  .getAllMutationBatches(txn)
11949
12236
  .next(promisedOldBatches => {
11950
12237
  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);
12238
+ localStoreImpl.initializeUserComponents(user);
12239
+ return localStoreImpl.mutationQueue.getAllMutationBatches(txn);
11956
12240
  })
11957
12241
  .next(newBatches => {
11958
12242
  const removedBatchIds = [];
@@ -11973,7 +12257,7 @@ async function localStoreHandleUserChange(localStore, user) {
11973
12257
  }
11974
12258
  // Return the set of all (potentially) changed documents and the list
11975
12259
  // of mutation batch IDs that were affected by change.
11976
- return newLocalDocuments
12260
+ return localStoreImpl.localDocuments
11977
12261
  .getDocuments(txn, changedKeys)
11978
12262
  .next(affectedDocuments => {
11979
12263
  return {
@@ -11984,9 +12268,6 @@ async function localStoreHandleUserChange(localStore, user) {
11984
12268
  });
11985
12269
  });
11986
12270
  });
11987
- localStoreImpl.mutationQueue = newMutationQueue;
11988
- localStoreImpl.localDocuments = newLocalDocuments;
11989
- localStoreImpl.queryEngine.setLocalDocumentsView(localStoreImpl.localDocuments);
11990
12271
  return result;
11991
12272
  }
11992
12273
  /* Accepts locally generated Mutations and commit them to storage. */
@@ -13052,14 +13333,16 @@ class MemoryRemoteDocumentCacheImpl {
13052
13333
  * expected to just return 0 to avoid unnecessarily doing the work of
13053
13334
  * calculating the size.
13054
13335
  */
13055
- constructor(indexManager, sizer) {
13056
- this.indexManager = indexManager;
13336
+ constructor(sizer) {
13057
13337
  this.sizer = sizer;
13058
13338
  /** Underlying cache of documents and their read times. */
13059
13339
  this.docs = documentEntryMap();
13060
13340
  /** Size of all cached documents. */
13061
13341
  this.size = 0;
13062
13342
  }
13343
+ setIndexManager(indexManager) {
13344
+ this.indexManager = indexManager;
13345
+ }
13063
13346
  /**
13064
13347
  * Adds the supplied entry to the cache and updates the cache size as appropriate.
13065
13348
  *
@@ -13107,21 +13390,22 @@ class MemoryRemoteDocumentCacheImpl {
13107
13390
  });
13108
13391
  return PersistencePromise.resolve(results);
13109
13392
  }
13110
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
13393
+ getAll(transaction, collectionPath, sinceReadTime) {
13111
13394
  let results = mutableDocumentMap();
13112
13395
  // Documents are ordered by key, so we can use a prefix scan to narrow down
13113
13396
  // the documents we need to match the query against.
13114
- const prefix = new DocumentKey(query.path.child(''));
13397
+ const prefix = new DocumentKey(collectionPath.child(''));
13115
13398
  const iterator = this.docs.getIteratorFrom(prefix);
13116
13399
  while (iterator.hasNext()) {
13117
13400
  const { key, value: { document } } = iterator.getNext();
13118
- if (!query.path.isPrefixOf(key.path)) {
13401
+ if (!collectionPath.isPrefixOf(key.path)) {
13119
13402
  break;
13120
13403
  }
13121
- if (document.readTime.compareTo(sinceReadTime) <= 0) {
13404
+ if (key.path.length > collectionPath.length + 1) {
13405
+ // Exclude entries from subcollections.
13122
13406
  continue;
13123
13407
  }
13124
- if (!queryMatches(query, document)) {
13408
+ if (document.readTime.compareTo(sinceReadTime) <= 0) {
13125
13409
  continue;
13126
13410
  }
13127
13411
  results = results.insert(document.key, document.mutableCopy());
@@ -13143,13 +13427,12 @@ class MemoryRemoteDocumentCacheImpl {
13143
13427
  /**
13144
13428
  * Creates a new memory-only RemoteDocumentCache.
13145
13429
  *
13146
- * @param indexManager - A class that manages collection group indices.
13147
13430
  * @param sizer - Used to assess the size of a document. For eager GC, this is
13148
13431
  * expected to just return 0 to avoid unnecessarily doing the work of
13149
13432
  * calculating the size.
13150
13433
  */
13151
- function newMemoryRemoteDocumentCache(indexManager, sizer) {
13152
- return new MemoryRemoteDocumentCacheImpl(indexManager, sizer);
13434
+ function newMemoryRemoteDocumentCache(sizer) {
13435
+ return new MemoryRemoteDocumentCacheImpl(sizer);
13153
13436
  }
13154
13437
  /**
13155
13438
  * Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
@@ -13350,7 +13633,7 @@ class MemoryPersistence {
13350
13633
  this.targetCache = new MemoryTargetCache(this);
13351
13634
  const sizer = (doc) => this.referenceDelegate.documentSize(doc);
13352
13635
  this.indexManager = new MemoryIndexManager();
13353
- this.remoteDocumentCache = newMemoryRemoteDocumentCache(this.indexManager, sizer);
13636
+ this.remoteDocumentCache = newMemoryRemoteDocumentCache(sizer);
13354
13637
  this.serializer = new LocalSerializer(serializer);
13355
13638
  this.bundleCache = new MemoryBundleCache(this.serializer);
13356
13639
  }
@@ -13371,13 +13654,15 @@ class MemoryPersistence {
13371
13654
  setNetworkEnabled() {
13372
13655
  // No op.
13373
13656
  }
13374
- getIndexManager() {
13657
+ getIndexManager(user) {
13658
+ // We do not currently support indices for memory persistence, so we can
13659
+ // return the same shared instance of the memory index manager.
13375
13660
  return this.indexManager;
13376
13661
  }
13377
- getMutationQueue(user) {
13662
+ getMutationQueue(user, indexManager) {
13378
13663
  let queue = this.mutationQueues[user.toKey()];
13379
13664
  if (!queue) {
13380
- queue = new MemoryMutationQueue(this.indexManager, this.referenceDelegate);
13665
+ queue = new MemoryMutationQueue(indexManager, this.referenceDelegate);
13381
13666
  this.mutationQueues[user.toKey()] = queue;
13382
13667
  }
13383
13668
  return queue;
@@ -20340,12 +20625,12 @@ async function syncEngineListen(syncEngine, query) {
20340
20625
  }
20341
20626
  else {
20342
20627
  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
20628
  if (syncEngineImpl.isPrimaryClient) {
20347
20629
  remoteStoreListen(syncEngineImpl.remoteStore, targetData);
20348
20630
  }
20631
+ const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
20632
+ targetId = targetData.targetId;
20633
+ viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20349
20634
  }
20350
20635
  return viewSnapshot;
20351
20636
  }
@@ -24853,8 +25138,7 @@ class DocumentSnapshot extends DocumentSnapshot$1 {
24853
25138
  this.metadata = metadata;
24854
25139
  }
24855
25140
  /**
24856
- * Property of the `DocumentSnapshot` that signals whether or not the data
24857
- * exists. True if the document exists.
25141
+ * Returns whether or not the data exists. True if the document exists.
24858
25142
  */
24859
25143
  exists() {
24860
25144
  return super.exists();
@@ -25228,51 +25512,53 @@ function limitToLast(limit) {
25228
25512
  return new QueryLimitConstraint('limitToLast', limit, "L" /* Last */);
25229
25513
  }
25230
25514
  class QueryStartAtConstraint extends QueryConstraint {
25231
- constructor(type, _docOrFields, _before) {
25515
+ constructor(type, _docOrFields, _inclusive) {
25232
25516
  super();
25233
25517
  this.type = type;
25234
25518
  this._docOrFields = _docOrFields;
25235
- this._before = _before;
25519
+ this._inclusive = _inclusive;
25236
25520
  }
25237
25521
  _apply(query) {
25238
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25522
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25239
25523
  return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
25240
25524
  }
25241
25525
  }
25242
25526
  function startAt(...docOrFields) {
25243
- return new QueryStartAtConstraint('startAt', docOrFields, /*before=*/ true);
25527
+ return new QueryStartAtConstraint('startAt', docOrFields,
25528
+ /*inclusive=*/ true);
25244
25529
  }
25245
25530
  function startAfter(...docOrFields) {
25246
25531
  return new QueryStartAtConstraint('startAfter', docOrFields,
25247
- /*before=*/ false);
25532
+ /*inclusive=*/ false);
25248
25533
  }
25249
25534
  class QueryEndAtConstraint extends QueryConstraint {
25250
- constructor(type, _docOrFields, _before) {
25535
+ constructor(type, _docOrFields, _inclusive) {
25251
25536
  super();
25252
25537
  this.type = type;
25253
25538
  this._docOrFields = _docOrFields;
25254
- this._before = _before;
25539
+ this._inclusive = _inclusive;
25255
25540
  }
25256
25541
  _apply(query) {
25257
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25542
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25258
25543
  return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
25259
25544
  }
25260
25545
  }
25261
25546
  function endBefore(...docOrFields) {
25262
- return new QueryEndAtConstraint('endBefore', docOrFields, /*before=*/ true);
25547
+ return new QueryEndAtConstraint('endBefore', docOrFields,
25548
+ /*inclusive=*/ false);
25263
25549
  }
25264
25550
  function endAt(...docOrFields) {
25265
- return new QueryEndAtConstraint('endAt', docOrFields, /*before=*/ false);
25551
+ return new QueryEndAtConstraint('endAt', docOrFields, /*inclusive=*/ true);
25266
25552
  }
25267
25553
  /** Helper function to create a bound from a document or fields */
25268
- function newQueryBoundFromDocOrFields(query, methodName, docOrFields, before) {
25554
+ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
25269
25555
  docOrFields[0] = getModularInstance(docOrFields[0]);
25270
25556
  if (docOrFields[0] instanceof DocumentSnapshot$1) {
25271
- return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, before);
25557
+ return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive);
25272
25558
  }
25273
25559
  else {
25274
25560
  const reader = newUserDataReader(query.firestore);
25275
- return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, before);
25561
+ return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive);
25276
25562
  }
25277
25563
  }
25278
25564
  function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
@@ -25330,7 +25616,7 @@ function newQueryOrderBy(query, fieldPath, direction) {
25330
25616
  * of the query or if any of the fields in the order by are an uncommitted
25331
25617
  * server timestamp.
25332
25618
  */
25333
- function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25619
+ function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) {
25334
25620
  if (!doc) {
25335
25621
  throw new FirestoreError(Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` +
25336
25622
  `${methodName}().`);
@@ -25367,12 +25653,12 @@ function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25367
25653
  }
25368
25654
  }
25369
25655
  }
25370
- return new Bound(components, before);
25656
+ return new Bound(components, inclusive);
25371
25657
  }
25372
25658
  /**
25373
25659
  * Converts a list of field values to a `Bound` for the given query.
25374
25660
  */
25375
- function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, before) {
25661
+ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) {
25376
25662
  // Use explicit order by's because it has to match the query the user made
25377
25663
  const orderBy = query.explicitOrderBy;
25378
25664
  if (values.length > orderBy.length) {
@@ -25409,7 +25695,7 @@ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, valu
25409
25695
  components.push(wrapped);
25410
25696
  }
25411
25697
  }
25412
- return new Bound(components, before);
25698
+ return new Bound(components, inclusive);
25413
25699
  }
25414
25700
  /**
25415
25701
  * Parses the given `documentIdValue` into a `ReferenceValue`, throwing