@firebase/firestore 3.4.4-canary.4cec42313 → 3.4.4-canary.50de44c2e

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 (128) hide show
  1. package/dist/firestore/src/api/snapshot.d.ts +1 -2
  2. package/dist/firestore/src/core/target.d.ts +8 -4
  3. package/dist/firestore/src/lite-api/query.d.ts +2 -2
  4. package/dist/firestore/src/local/index_manager.d.ts +52 -0
  5. package/dist/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  6. package/dist/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  7. package/dist/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  8. package/dist/firestore/src/local/indexeddb_schema.d.ts +35 -7
  9. package/dist/firestore/src/local/local_documents_view.d.ts +0 -1
  10. package/dist/firestore/src/local/local_serializer.d.ts +7 -2
  11. package/dist/firestore/src/local/memory_index_manager.d.ts +11 -0
  12. package/dist/firestore/src/local/memory_persistence.d.ts +3 -2
  13. package/dist/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  14. package/dist/firestore/src/local/persistence.d.ts +2 -2
  15. package/dist/firestore/src/local/remote_document_cache.d.ts +7 -9
  16. package/dist/firestore/src/local/simple_db.d.ts +1 -0
  17. package/dist/firestore/src/model/field_index.d.ts +2 -2
  18. package/dist/firestore/src/model/target_index_matcher.d.ts +70 -0
  19. package/dist/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  20. package/dist/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  21. package/dist/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  22. package/dist/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  23. package/dist/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  24. package/dist/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  25. package/dist/firestore/test/util/helpers.d.ts +1 -1
  26. package/dist/index.d.ts +1 -2
  27. package/dist/index.esm2017.js +2967 -2808
  28. package/dist/index.esm2017.js.map +1 -1
  29. package/dist/index.esm5.js +2870 -2698
  30. package/dist/index.esm5.js.map +1 -1
  31. package/dist/index.node.cjs.js +397 -203
  32. package/dist/index.node.cjs.js.map +1 -1
  33. package/dist/index.node.mjs +397 -203
  34. package/dist/index.node.mjs.map +1 -1
  35. package/dist/index.rn.js +3215 -3060
  36. package/dist/index.rn.js.map +1 -1
  37. package/dist/internal.d.ts +178 -14
  38. package/dist/lite/firestore/src/api/snapshot.d.ts +1 -2
  39. package/dist/lite/firestore/src/core/target.d.ts +8 -4
  40. package/dist/lite/firestore/src/lite-api/query.d.ts +2 -2
  41. package/dist/lite/firestore/src/local/index_manager.d.ts +52 -0
  42. package/dist/lite/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  43. package/dist/lite/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  44. package/dist/lite/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  45. package/dist/lite/firestore/src/local/indexeddb_schema.d.ts +35 -7
  46. package/dist/lite/firestore/src/local/local_documents_view.d.ts +0 -1
  47. package/dist/lite/firestore/src/local/local_serializer.d.ts +7 -2
  48. package/dist/lite/firestore/src/local/memory_index_manager.d.ts +11 -0
  49. package/dist/lite/firestore/src/local/memory_persistence.d.ts +3 -2
  50. package/dist/lite/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  51. package/dist/lite/firestore/src/local/persistence.d.ts +2 -2
  52. package/dist/lite/firestore/src/local/remote_document_cache.d.ts +7 -9
  53. package/dist/lite/firestore/src/local/simple_db.d.ts +1 -0
  54. package/dist/lite/firestore/src/model/field_index.d.ts +2 -2
  55. package/dist/lite/firestore/src/model/target_index_matcher.d.ts +70 -0
  56. package/dist/lite/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  57. package/dist/lite/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  58. package/dist/lite/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  59. package/dist/lite/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  60. package/dist/lite/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  61. package/dist/lite/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  62. package/dist/lite/firestore/test/util/helpers.d.ts +1 -1
  63. package/dist/lite/index.browser.esm2017.js +1146 -1143
  64. package/dist/lite/index.browser.esm2017.js.map +1 -1
  65. package/dist/lite/index.browser.esm5.js +332 -331
  66. package/dist/lite/index.browser.esm5.js.map +1 -1
  67. package/dist/lite/index.node.cjs.js +36 -29
  68. package/dist/lite/index.node.cjs.js.map +1 -1
  69. package/dist/lite/index.node.mjs +36 -29
  70. package/dist/lite/index.node.mjs.map +1 -1
  71. package/dist/lite/index.rn.esm2017.js +301 -298
  72. package/dist/lite/index.rn.esm2017.js.map +1 -1
  73. package/dist/lite/internal.d.ts +2 -2
  74. package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +121 -121
  75. package/dist/lite/packages/firestore/src/api/snapshot.d.ts +1 -2
  76. package/dist/lite/packages/firestore/src/core/target.d.ts +8 -4
  77. package/dist/lite/packages/firestore/src/lite-api/query.d.ts +2 -2
  78. package/dist/lite/packages/firestore/src/local/index_manager.d.ts +52 -0
  79. package/dist/lite/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  80. package/dist/lite/packages/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  81. package/dist/lite/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  82. package/dist/lite/packages/firestore/src/local/indexeddb_schema.d.ts +35 -7
  83. package/dist/lite/packages/firestore/src/local/local_documents_view.d.ts +0 -1
  84. package/dist/lite/packages/firestore/src/local/local_serializer.d.ts +7 -2
  85. package/dist/lite/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
  86. package/dist/lite/packages/firestore/src/local/memory_persistence.d.ts +3 -2
  87. package/dist/lite/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  88. package/dist/lite/packages/firestore/src/local/persistence.d.ts +2 -2
  89. package/dist/lite/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
  90. package/dist/lite/packages/firestore/src/local/simple_db.d.ts +1 -0
  91. package/dist/lite/packages/firestore/src/model/field_index.d.ts +2 -2
  92. package/dist/lite/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
  93. package/dist/lite/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  94. package/dist/lite/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  95. package/dist/lite/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  96. package/dist/lite/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  97. package/dist/lite/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  98. package/dist/lite/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  99. package/dist/lite/packages/firestore/test/util/helpers.d.ts +1 -1
  100. package/dist/lite/private.d.ts +2 -2
  101. package/dist/packages/firestore/dist/index.esm2017.d.ts +143 -143
  102. package/dist/packages/firestore/src/api/snapshot.d.ts +1 -2
  103. package/dist/packages/firestore/src/core/target.d.ts +8 -4
  104. package/dist/packages/firestore/src/lite-api/query.d.ts +2 -2
  105. package/dist/packages/firestore/src/local/index_manager.d.ts +52 -0
  106. package/dist/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
  107. package/dist/packages/firestore/src/local/indexeddb_persistence.d.ts +4 -4
  108. package/dist/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
  109. package/dist/packages/firestore/src/local/indexeddb_schema.d.ts +35 -7
  110. package/dist/packages/firestore/src/local/local_documents_view.d.ts +0 -1
  111. package/dist/packages/firestore/src/local/local_serializer.d.ts +7 -2
  112. package/dist/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
  113. package/dist/packages/firestore/src/local/memory_persistence.d.ts +3 -2
  114. package/dist/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
  115. package/dist/packages/firestore/src/local/persistence.d.ts +2 -2
  116. package/dist/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
  117. package/dist/packages/firestore/src/local/simple_db.d.ts +1 -0
  118. package/dist/packages/firestore/src/model/field_index.d.ts +2 -2
  119. package/dist/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
  120. package/dist/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
  121. package/dist/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
  122. package/dist/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
  123. package/dist/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
  124. package/dist/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
  125. package/dist/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
  126. package/dist/packages/firestore/test/util/helpers.d.ts +1 -1
  127. package/dist/private.d.ts +178 -14
  128. 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.4cec42313";
15
+ const version$1 = "3.4.4-canary.50de44c2e";
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.4cec42313";
68
+ const version = "9.6.6-canary.50de44c2e";
69
69
 
70
70
  /**
71
71
  * @license
@@ -1778,7 +1778,10 @@ DbNamedQuery.keyPath = 'name';
1778
1778
  /** An object representing the global configuration for a field index. */
1779
1779
  class DbIndexConfiguration {
1780
1780
  constructor(
1781
- /** The index id for this entry. */
1781
+ /**
1782
+ * The index id for this entry. Undefined for indexes that are not yet
1783
+ * persisted.
1784
+ */
1782
1785
  indexId,
1783
1786
  /** The collection group this index belongs to. */
1784
1787
  collectionGroup,
@@ -1792,6 +1795,16 @@ class DbIndexConfiguration {
1792
1795
  /** Name of the IndexedDb object store. */
1793
1796
  DbIndexConfiguration.store = 'indexConfiguration';
1794
1797
  DbIndexConfiguration.keyPath = 'indexId';
1798
+ /**
1799
+ * An index that provides access to the index configurations by collection
1800
+ * group.
1801
+ *
1802
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1803
+ * not possible here as the Web client supports concurrent access to
1804
+ * persistence via multi-tab.
1805
+ */
1806
+ DbIndexConfiguration.collectionGroupIndex = 'collectionGroupIndex';
1807
+ DbIndexConfiguration.collectionGroupIndexPath = 'collectionGroup';
1795
1808
  /**
1796
1809
  * An object describing how up-to-date the index backfill is for each user and
1797
1810
  * index.
@@ -1833,8 +1846,18 @@ class DbIndexState {
1833
1846
  /** Name of the IndexedDb object store. */
1834
1847
  DbIndexState.store = 'indexState';
1835
1848
  DbIndexState.keyPath = ['indexId', 'uid'];
1849
+ /**
1850
+ * An index that provides access to documents in a collection sorted by last
1851
+ * update time. Used by the backfiller.
1852
+ *
1853
+ * PORTING NOTE: iOS and Android maintain this index in-memory, but this is
1854
+ * not possible here as the Web client supports concurrent access to
1855
+ * persistence via multi-tab.
1856
+ */
1857
+ DbIndexState.sequenceNumberIndex = 'sequenceNumberIndex';
1858
+ DbIndexState.sequenceNumberIndexPath = ['uid', 'sequenceNumber'];
1836
1859
  /** An object that stores the encoded entries for all documents and fields. */
1837
- class DbIndexEntries {
1860
+ class DbIndexEntry {
1838
1861
  constructor(
1839
1862
  /** The index id for this entry. */
1840
1863
  indexId,
@@ -1854,8 +1877,8 @@ class DbIndexEntries {
1854
1877
  }
1855
1878
  }
1856
1879
  /** Name of the IndexedDb object store. */
1857
- DbIndexEntries.store = 'indexEntries';
1858
- DbIndexEntries.keyPath = [
1880
+ DbIndexEntry.store = 'indexEntries';
1881
+ DbIndexEntry.keyPath = [
1859
1882
  'indexId',
1860
1883
  'uid',
1861
1884
  'arrayValue',
@@ -1885,18 +1908,24 @@ const V8_STORES = [...V6_STORES, DbCollectionParent.store];
1885
1908
  // V9 does not change the set of stores.
1886
1909
  // V10 does not change the set of stores.
1887
1910
  const V11_STORES = [...V8_STORES, DbBundle.store, DbNamedQuery.store];
1888
- [
1911
+ const V12_STORES = [
1889
1912
  ...V11_STORES,
1890
1913
  DbIndexConfiguration.store,
1891
1914
  DbIndexState.store,
1892
- DbIndexEntries.store
1915
+ DbIndexEntry.store
1893
1916
  ];
1894
- /**
1895
- * The list of all default IndexedDB stores used throughout the SDK. This is
1896
- * used when creating transactions so that access across all stores is done
1897
- * atomically.
1898
- */
1899
- const ALL_STORES = V11_STORES;
1917
+ /** Returns the object stores for the provided schema. */
1918
+ function getObjectStores(schemaVersion) {
1919
+ if (schemaVersion === 12) {
1920
+ return V12_STORES;
1921
+ }
1922
+ else if (schemaVersion === 11) {
1923
+ return V11_STORES;
1924
+ }
1925
+ else {
1926
+ fail();
1927
+ }
1928
+ }
1900
1929
 
1901
1930
  /**
1902
1931
  * @license
@@ -2193,6 +2222,15 @@ class SimpleDbTransaction {
2193
2222
  this.transaction.abort();
2194
2223
  }
2195
2224
  }
2225
+ maybeCommit() {
2226
+ // If the browser supports V3 IndexedDB, we invoke commit() explicitly to
2227
+ // speed up index DB processing if the event loop remains blocks.
2228
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2229
+ const maybeV3IndexedDb = this.transaction;
2230
+ if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {
2231
+ maybeV3IndexedDb.commit();
2232
+ }
2233
+ }
2196
2234
  /**
2197
2235
  * Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
2198
2236
  * operations performed on the SimpleDbStore happen within the context of this
@@ -2389,6 +2427,10 @@ class SimpleDb {
2389
2427
  this.db = await this.ensureDb(action);
2390
2428
  const transaction = SimpleDbTransaction.open(this.db, action, readonly ? 'readonly' : 'readwrite', objectStores);
2391
2429
  const transactionFnResult = transactionFn(transaction)
2430
+ .next(result => {
2431
+ transaction.maybeCommit();
2432
+ return result;
2433
+ })
2392
2434
  .catch(error => {
2393
2435
  // Abort the transaction if there was an error.
2394
2436
  transaction.abort(error);
@@ -2561,13 +2603,29 @@ class SimpleDbStore {
2561
2603
  return wrapRequest(request);
2562
2604
  }
2563
2605
  loadAll(indexOrRange, range) {
2564
- const cursor = this.cursor(this.options(indexOrRange, range));
2565
- const results = [];
2566
- return this.iterateCursor(cursor, (key, value) => {
2567
- results.push(value);
2568
- }).next(() => {
2569
- return results;
2570
- });
2606
+ const iterateOptions = this.options(indexOrRange, range);
2607
+ // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly
2608
+ // 20% faster. Unfortunately, getAll() does not support custom indices.
2609
+ if (!iterateOptions.index && typeof this.store.getAll === 'function') {
2610
+ const request = this.store.getAll(iterateOptions.range);
2611
+ return new PersistencePromise((resolve, reject) => {
2612
+ request.onerror = (event) => {
2613
+ reject(event.target.error);
2614
+ };
2615
+ request.onsuccess = (event) => {
2616
+ resolve(event.target.result);
2617
+ };
2618
+ });
2619
+ }
2620
+ else {
2621
+ const cursor = this.cursor(iterateOptions);
2622
+ const results = [];
2623
+ return this.iterateCursor(cursor, (key, value) => {
2624
+ results.push(value);
2625
+ }).next(() => {
2626
+ return results;
2627
+ });
2628
+ }
2571
2629
  }
2572
2630
  deleteAll(indexOrRange, range) {
2573
2631
  logDebug(LOG_TAG$g, 'DELETE ALL', this.store.name);
@@ -4421,12 +4479,12 @@ class FieldIndex {
4421
4479
  /** The collection ID this index applies to. */
4422
4480
  collectionGroup,
4423
4481
  /** The field segments for this index. */
4424
- segments,
4482
+ fields,
4425
4483
  /** Shows how up-to-date the index is for the current user. */
4426
4484
  indexState) {
4427
4485
  this.indexId = indexId;
4428
4486
  this.collectionGroup = collectionGroup;
4429
- this.segments = segments;
4487
+ this.fields = fields;
4430
4488
  this.indexState = indexState;
4431
4489
  }
4432
4490
  }
@@ -4536,27 +4594,29 @@ function newTarget(path, collectionGroup = null, orderBy = [], filters = [], lim
4536
4594
  function canonifyTarget(target) {
4537
4595
  const targetImpl = debugCast(target);
4538
4596
  if (targetImpl.memoizedCanonicalId === null) {
4539
- let canonicalId = targetImpl.path.canonicalString();
4597
+ let str = targetImpl.path.canonicalString();
4540
4598
  if (targetImpl.collectionGroup !== null) {
4541
- canonicalId += '|cg:' + targetImpl.collectionGroup;
4599
+ str += '|cg:' + targetImpl.collectionGroup;
4542
4600
  }
4543
- canonicalId += '|f:';
4544
- canonicalId += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4545
- canonicalId += '|ob:';
4546
- canonicalId += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4601
+ str += '|f:';
4602
+ str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
4603
+ str += '|ob:';
4604
+ str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
4547
4605
  if (!isNullOrUndefined(targetImpl.limit)) {
4548
- canonicalId += '|l:';
4549
- canonicalId += targetImpl.limit;
4606
+ str += '|l:';
4607
+ str += targetImpl.limit;
4550
4608
  }
4551
4609
  if (targetImpl.startAt) {
4552
- canonicalId += '|lb:';
4553
- canonicalId += canonifyBound(targetImpl.startAt);
4610
+ str += '|lb:';
4611
+ str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
4612
+ str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
4554
4613
  }
4555
4614
  if (targetImpl.endAt) {
4556
- canonicalId += '|ub:';
4557
- canonicalId += canonifyBound(targetImpl.endAt);
4615
+ str += '|ub:';
4616
+ str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
4617
+ str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
4558
4618
  }
4559
- targetImpl.memoizedCanonicalId = canonicalId;
4619
+ targetImpl.memoizedCanonicalId = str;
4560
4620
  }
4561
4621
  return targetImpl.memoizedCanonicalId;
4562
4622
  }
@@ -4579,10 +4639,14 @@ function stringifyTarget(target) {
4579
4639
  .join(', ')}]`;
4580
4640
  }
4581
4641
  if (target.startAt) {
4582
- str += ', startAt: ' + canonifyBound(target.startAt);
4642
+ str += ', startAt: ';
4643
+ str += target.startAt.inclusive ? 'b:' : 'a:';
4644
+ str += target.startAt.position.map(p => canonicalId(p)).join(',');
4583
4645
  }
4584
4646
  if (target.endAt) {
4585
- str += ', endAt: ' + canonifyBound(target.endAt);
4647
+ str += ', endAt: ';
4648
+ str += target.endAt.inclusive ? 'a:' : 'b:';
4649
+ str += target.endAt.position.map(p => canonicalId(p)).join(',');
4586
4650
  }
4587
4651
  return `Target(${str})`;
4588
4652
  }
@@ -4805,7 +4869,6 @@ class ArrayContainsAnyFilter extends FieldFilter {
4805
4869
  return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
4806
4870
  }
4807
4871
  }
4808
- // TODO(indexing): Change Bound.before to "inclusive"
4809
4872
  /**
4810
4873
  * Represents a bound of a query.
4811
4874
  *
@@ -4821,17 +4884,11 @@ class ArrayContainsAnyFilter extends FieldFilter {
4821
4884
  * just after the provided values.
4822
4885
  */
4823
4886
  class Bound {
4824
- constructor(position, before) {
4887
+ constructor(position, inclusive) {
4825
4888
  this.position = position;
4826
- this.before = before;
4889
+ this.inclusive = inclusive;
4827
4890
  }
4828
4891
  }
4829
- function canonifyBound(bound) {
4830
- // TODO(b/29183165): Make this collision robust.
4831
- return `${bound.before ? 'b' : 'a'}:${bound.position
4832
- .map(p => canonicalId(p))
4833
- .join(',')}`;
4834
- }
4835
4892
  /**
4836
4893
  * An ordering on a field, in some Direction. Direction defaults to ASCENDING.
4837
4894
  */
@@ -4851,11 +4908,7 @@ function stringifyOrderBy(orderBy) {
4851
4908
  function orderByEquals(left, right) {
4852
4909
  return left.dir === right.dir && left.field.isEqual(right.field);
4853
4910
  }
4854
- /**
4855
- * Returns true if a document sorts before a bound using the provided sort
4856
- * order.
4857
- */
4858
- function sortsBeforeDocument(bound, orderBy, doc) {
4911
+ function boundCompareToDocument(bound, orderBy, doc) {
4859
4912
  let comparison = 0;
4860
4913
  for (let i = 0; i < bound.position.length; i++) {
4861
4914
  const orderByComponent = orderBy[i];
@@ -4874,7 +4927,23 @@ function sortsBeforeDocument(bound, orderBy, doc) {
4874
4927
  break;
4875
4928
  }
4876
4929
  }
4877
- return bound.before ? comparison <= 0 : comparison < 0;
4930
+ return comparison;
4931
+ }
4932
+ /**
4933
+ * Returns true if a document sorts after a bound using the provided sort
4934
+ * order.
4935
+ */
4936
+ function boundSortsAfterDocument(bound, orderBy, doc) {
4937
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4938
+ return bound.inclusive ? comparison >= 0 : comparison > 0;
4939
+ }
4940
+ /**
4941
+ * Returns true if a document sorts before a bound using the provided sort
4942
+ * order.
4943
+ */
4944
+ function boundSortsBeforeDocument(bound, orderBy, doc) {
4945
+ const comparison = boundCompareToDocument(bound, orderBy, doc);
4946
+ return bound.inclusive ? comparison <= 0 : comparison < 0;
4878
4947
  }
4879
4948
  function boundEquals(left, right) {
4880
4949
  if (left === null) {
@@ -4883,7 +4952,7 @@ function boundEquals(left, right) {
4883
4952
  else if (right === null) {
4884
4953
  return false;
4885
4954
  }
4886
- if (left.before !== right.before ||
4955
+ if (left.inclusive !== right.inclusive ||
4887
4956
  left.position.length !== right.position.length) {
4888
4957
  return false;
4889
4958
  }
@@ -5087,10 +5156,10 @@ function queryToTarget(query) {
5087
5156
  }
5088
5157
  // We need to swap the cursors to match the now-flipped query ordering.
5089
5158
  const startAt = queryImpl.endAt
5090
- ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.before)
5159
+ ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
5091
5160
  : null;
5092
5161
  const endAt = queryImpl.startAt
5093
- ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.before)
5162
+ ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
5094
5163
  : null;
5095
5164
  // Now return as a LimitType.First query.
5096
5165
  queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
@@ -5178,11 +5247,11 @@ function queryMatchesFilters(query, doc) {
5178
5247
  /** Makes sure a document is within the bounds, if provided. */
5179
5248
  function queryMatchesBounds(query, doc) {
5180
5249
  if (query.startAt &&
5181
- !sortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5250
+ !boundSortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
5182
5251
  return false;
5183
5252
  }
5184
5253
  if (query.endAt &&
5185
- sortsBeforeDocument(query.endAt, queryOrderBy(query), doc)) {
5254
+ !boundSortsAfterDocument(query.endAt, queryOrderBy(query), doc)) {
5186
5255
  return false;
5187
5256
  }
5188
5257
  return true;
@@ -8061,10 +8130,10 @@ function toQueryTarget(serializer, target) {
8061
8130
  result.structuredQuery.limit = limit;
8062
8131
  }
8063
8132
  if (target.startAt) {
8064
- result.structuredQuery.startAt = toCursor(target.startAt);
8133
+ result.structuredQuery.startAt = toStartAtCursor(target.startAt);
8065
8134
  }
8066
8135
  if (target.endAt) {
8067
- result.structuredQuery.endAt = toCursor(target.endAt);
8136
+ result.structuredQuery.endAt = toEndAtCursor(target.endAt);
8068
8137
  }
8069
8138
  return result;
8070
8139
  }
@@ -8097,11 +8166,11 @@ function convertQueryTargetToQuery(target) {
8097
8166
  }
8098
8167
  let startAt = null;
8099
8168
  if (query.startAt) {
8100
- startAt = fromCursor(query.startAt);
8169
+ startAt = fromStartAtCursor(query.startAt);
8101
8170
  }
8102
8171
  let endAt = null;
8103
8172
  if (query.endAt) {
8104
- endAt = fromCursor(query.endAt);
8173
+ endAt = fromEndAtCursor(query.endAt);
8105
8174
  }
8106
8175
  return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
8107
8176
  }
@@ -8192,16 +8261,27 @@ function toOrder(orderBys) {
8192
8261
  function fromOrder(orderBys) {
8193
8262
  return orderBys.map(order => fromPropertyOrder(order));
8194
8263
  }
8195
- function toCursor(cursor) {
8264
+ function toStartAtCursor(cursor) {
8196
8265
  return {
8197
- before: cursor.before,
8266
+ before: cursor.inclusive,
8198
8267
  values: cursor.position
8199
8268
  };
8200
8269
  }
8201
- function fromCursor(cursor) {
8202
- const before = !!cursor.before;
8270
+ function toEndAtCursor(cursor) {
8271
+ return {
8272
+ before: !cursor.inclusive,
8273
+ values: cursor.position
8274
+ };
8275
+ }
8276
+ function fromStartAtCursor(cursor) {
8277
+ const inclusive = !!cursor.before;
8278
+ const position = cursor.values || [];
8279
+ return new Bound(position, inclusive);
8280
+ }
8281
+ function fromEndAtCursor(cursor) {
8282
+ const inclusive = !cursor.before;
8203
8283
  const position = cursor.values || [];
8204
- return new Bound(position, before);
8284
+ return new Bound(position, inclusive);
8205
8285
  }
8206
8286
  // visible for testing
8207
8287
  function toDirection(dir) {
@@ -8665,6 +8745,19 @@ function fromBundleMetadata(metadata) {
8665
8745
  version: metadata.version,
8666
8746
  createTime: fromVersion(metadata.createTime)
8667
8747
  };
8748
+ }
8749
+ function toDbIndexConfiguration(index) {
8750
+ return new DbIndexConfiguration(index.indexId, index.collectionGroup, index.fields.map(s => [s.fieldPath.canonicalString(), s.kind]));
8751
+ }
8752
+ function fromDbIndexConfiguration(index, state) {
8753
+ const decodedState = state
8754
+ ? new IndexState(state.sequenceNumber, new IndexOffset(fromDbTimestamp(state.readTime), new DocumentKey(decodeResourcePath(state.documentKey)), state.largestBatchId))
8755
+ : IndexState.empty();
8756
+ const decodedSegments = index.fields.map(([fieldPath, kind]) => new IndexSegment(FieldPath$1.fromServerFormat(fieldPath), kind));
8757
+ return new FieldIndex(index.indexId, index.collectionGroup, decodedSegments, decodedState);
8758
+ }
8759
+ function toDbIndexState(indexId, user, sequenceNumber, offset) {
8760
+ return new DbIndexState(indexId, user.uid || '', sequenceNumber, toDbTimestamp(offset.readTime), encodeResourcePath(offset.documentKey.path), offset.largestBatchId);
8668
8761
  }
8669
8762
 
8670
8763
  /**
@@ -8754,6 +8847,38 @@ class MemoryIndexManager {
8754
8847
  getCollectionParents(transaction, collectionId) {
8755
8848
  return PersistencePromise.resolve(this.collectionParentIndex.getEntries(collectionId));
8756
8849
  }
8850
+ addFieldIndex(transaction, index) {
8851
+ // Field indices are not supported with memory persistence.
8852
+ return PersistencePromise.resolve();
8853
+ }
8854
+ deleteFieldIndex(transaction, index) {
8855
+ // Field indices are not supported with memory persistence.
8856
+ return PersistencePromise.resolve();
8857
+ }
8858
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
8859
+ // Field indices are not supported with memory persistence.
8860
+ return PersistencePromise.resolve(documentKeySet());
8861
+ }
8862
+ getFieldIndex(transaction, target) {
8863
+ // Field indices are not supported with memory persistence.
8864
+ return PersistencePromise.resolve(null);
8865
+ }
8866
+ getFieldIndexes(transaction, collectionGroup) {
8867
+ // Field indices are not supported with memory persistence.
8868
+ return PersistencePromise.resolve([]);
8869
+ }
8870
+ getNextCollectionGroupToUpdate(transaction) {
8871
+ // Field indices are not supported with memory persistence.
8872
+ return PersistencePromise.resolve(null);
8873
+ }
8874
+ updateCollectionGroup(transaction, collectionGroup, offset) {
8875
+ // Field indices are not supported with memory persistence.
8876
+ return PersistencePromise.resolve();
8877
+ }
8878
+ updateIndexEntries(transaction, documents) {
8879
+ // Field indices are not supported with memory persistence.
8880
+ return PersistencePromise.resolve();
8881
+ }
8757
8882
  }
8758
8883
  /**
8759
8884
  * Internal implementation of the collection-parent index exposed by MemoryIndexManager.
@@ -8805,17 +8930,22 @@ class MemoryCollectionParentIndex {
8805
8930
  */
8806
8931
  /**
8807
8932
  * A persisted implementation of IndexManager.
8933
+ *
8934
+ * PORTING NOTE: Unlike iOS and Android, the Web SDK does not memoize index
8935
+ * data as it supports multi-tab access.
8808
8936
  */
8809
8937
  class IndexedDbIndexManager {
8810
- constructor() {
8938
+ constructor(user) {
8939
+ this.user = user;
8811
8940
  /**
8812
8941
  * An in-memory copy of the index entries we've already written since the SDK
8813
8942
  * launched. Used to avoid re-writing the same entry repeatedly.
8814
8943
  *
8815
- * This is *NOT* a complete cache of what's in persistence and so can never be used to
8816
- * satisfy reads.
8944
+ * This is *NOT* a complete cache of what's in persistence and so can never be
8945
+ * used to satisfy reads.
8817
8946
  */
8818
8947
  this.collectionParentsCache = new MemoryCollectionParentIndex();
8948
+ this.uid = user.uid || '';
8819
8949
  }
8820
8950
  /**
8821
8951
  * Adds a new entry to the collection parent index.
@@ -8862,6 +8992,85 @@ class IndexedDbIndexManager {
8862
8992
  return parentPaths;
8863
8993
  });
8864
8994
  }
8995
+ addFieldIndex(transaction, index) {
8996
+ // TODO(indexing): Verify that the auto-incrementing index ID works in
8997
+ // Safari & Firefox.
8998
+ const indexes = indexConfigurationStore(transaction);
8999
+ const dbIndex = toDbIndexConfiguration(index);
9000
+ delete dbIndex.indexId; // `indexId` is auto-populated by IndexedDb
9001
+ return indexes.add(dbIndex).next();
9002
+ }
9003
+ deleteFieldIndex(transaction, index) {
9004
+ const indexes = indexConfigurationStore(transaction);
9005
+ const states = indexStateStore(transaction);
9006
+ const entries = indexEntriesStore(transaction);
9007
+ return indexes
9008
+ .delete(index.indexId)
9009
+ .next(() => states.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9010
+ /*lowerOpen=*/ false,
9011
+ /*upperOpen=*/ true)))
9012
+ .next(() => entries.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
9013
+ /*lowerOpen=*/ false,
9014
+ /*upperOpen=*/ true)));
9015
+ }
9016
+ getDocumentsMatchingTarget(transaction, fieldIndex, target) {
9017
+ // TODO(indexing): Implement
9018
+ return PersistencePromise.resolve(documentKeySet());
9019
+ }
9020
+ getFieldIndex(transaction, target) {
9021
+ // TODO(indexing): Implement
9022
+ return PersistencePromise.resolve(null);
9023
+ }
9024
+ getFieldIndexes(transaction, collectionGroup) {
9025
+ const indexes = indexConfigurationStore(transaction);
9026
+ const states = indexStateStore(transaction);
9027
+ return (collectionGroup
9028
+ ? indexes.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9029
+ : indexes.loadAll()).next(indexConfigs => {
9030
+ const result = [];
9031
+ return PersistencePromise.forEach(indexConfigs, (indexConfig) => {
9032
+ return states
9033
+ .get([indexConfig.indexId, this.uid])
9034
+ .next(indexState => {
9035
+ result.push(fromDbIndexConfiguration(indexConfig, indexState));
9036
+ });
9037
+ }).next(() => result);
9038
+ });
9039
+ }
9040
+ getNextCollectionGroupToUpdate(transaction) {
9041
+ return this.getFieldIndexes(transaction).next(indexes => {
9042
+ if (indexes.length === 0) {
9043
+ return null;
9044
+ }
9045
+ indexes.sort((l, r) => l.indexState.sequenceNumber - r.indexState.sequenceNumber);
9046
+ return indexes[0].collectionGroup;
9047
+ });
9048
+ }
9049
+ updateCollectionGroup(transaction, collectionGroup, offset) {
9050
+ const indexes = indexConfigurationStore(transaction);
9051
+ const states = indexStateStore(transaction);
9052
+ return this.getNextSequenceNumber(transaction).next(nextSequenceNumber => indexes
9053
+ .loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
9054
+ .next(configs => PersistencePromise.forEach(configs, (config) => states.put(toDbIndexState(config.indexId, this.user, nextSequenceNumber, offset)))));
9055
+ }
9056
+ updateIndexEntries(transaction, documents) {
9057
+ // TODO(indexing): Implement
9058
+ return PersistencePromise.resolve();
9059
+ }
9060
+ getNextSequenceNumber(transaction) {
9061
+ let nextSequenceNumber = 1;
9062
+ const states = indexStateStore(transaction);
9063
+ return states
9064
+ .iterate({
9065
+ index: DbIndexState.sequenceNumberIndex,
9066
+ reverse: true,
9067
+ range: IDBKeyRange.upperBound([this.uid, Number.MAX_SAFE_INTEGER])
9068
+ }, (_, state, controller) => {
9069
+ controller.done();
9070
+ nextSequenceNumber = state.sequenceNumber + 1;
9071
+ })
9072
+ .next(() => nextSequenceNumber);
9073
+ }
8865
9074
  }
8866
9075
  /**
8867
9076
  * Helper to get a typed SimpleDbStore for the collectionParents
@@ -8869,6 +9078,24 @@ class IndexedDbIndexManager {
8869
9078
  */
8870
9079
  function collectionParentsStore(txn) {
8871
9080
  return getStore(txn, DbCollectionParent.store);
9081
+ }
9082
+ /**
9083
+ * Helper to get a typed SimpleDbStore for the index entry object store.
9084
+ */
9085
+ function indexEntriesStore(txn) {
9086
+ return getStore(txn, DbIndexEntry.store);
9087
+ }
9088
+ /**
9089
+ * Helper to get a typed SimpleDbStore for the index configuration object store.
9090
+ */
9091
+ function indexConfigurationStore(txn) {
9092
+ return getStore(txn, DbIndexConfiguration.store);
9093
+ }
9094
+ /**
9095
+ * Helper to get a typed SimpleDbStore for the index state object store.
9096
+ */
9097
+ function indexStateStore(txn) {
9098
+ return getStore(txn, DbIndexState.store);
8872
9099
  }
8873
9100
 
8874
9101
  /**
@@ -10338,12 +10565,10 @@ class RemoteDocumentChangeBuffer {
10338
10565
  * `newIndexedDbRemoteDocumentCache()`.
10339
10566
  */
10340
10567
  class IndexedDbRemoteDocumentCacheImpl {
10341
- /**
10342
- * @param serializer - The document serializer.
10343
- * @param indexManager - The query indexes that need to be maintained.
10344
- */
10345
- constructor(serializer, indexManager) {
10568
+ constructor(serializer) {
10346
10569
  this.serializer = serializer;
10570
+ }
10571
+ setIndexManager(indexManager) {
10347
10572
  this.indexManager = indexManager;
10348
10573
  }
10349
10574
  /**
@@ -10465,21 +10690,21 @@ class IndexedDbRemoteDocumentCacheImpl {
10465
10690
  }
10466
10691
  });
10467
10692
  }
10468
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
10693
+ getAll(transaction, collection, sinceReadTime) {
10469
10694
  let results = mutableDocumentMap();
10470
- const immediateChildrenPathLength = query.path.length + 1;
10695
+ const immediateChildrenPathLength = collection.length + 1;
10471
10696
  const iterationOptions = {};
10472
10697
  if (sinceReadTime.isEqual(SnapshotVersion.min())) {
10473
10698
  // Documents are ordered by key, so we can use a prefix scan to narrow
10474
10699
  // down the documents we need to match the query against.
10475
- const startKey = query.path.toArray();
10700
+ const startKey = collection.toArray();
10476
10701
  iterationOptions.range = IDBKeyRange.lowerBound(startKey);
10477
10702
  }
10478
10703
  else {
10479
10704
  // Execute an index-free query and filter by read time. This is safe
10480
10705
  // since all document changes to queries that have a
10481
10706
  // lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read time set.
10482
- const collectionKey = query.path.toArray();
10707
+ const collectionKey = collection.toArray();
10483
10708
  const readTimeKey = toDbTimestampKey(sinceReadTime);
10484
10709
  iterationOptions.range = IDBKeyRange.lowerBound([collectionKey, readTimeKey],
10485
10710
  /* open= */ true);
@@ -10496,12 +10721,12 @@ class IndexedDbRemoteDocumentCacheImpl {
10496
10721
  return;
10497
10722
  }
10498
10723
  const document = this.maybeDecodeDocument(DocumentKey.fromSegments(key), dbRemoteDoc);
10499
- if (!query.path.isPrefixOf(document.key.path)) {
10500
- control.done();
10501
- }
10502
- else if (queryMatches(query, document)) {
10724
+ if (collection.isPrefixOf(document.key.path)) {
10503
10725
  results = results.insert(document.key, document);
10504
10726
  }
10727
+ else {
10728
+ control.done();
10729
+ }
10505
10730
  })
10506
10731
  .next(() => results);
10507
10732
  }
@@ -10539,14 +10764,9 @@ class IndexedDbRemoteDocumentCacheImpl {
10539
10764
  return MutableDocument.newInvalidDocument(documentKey);
10540
10765
  }
10541
10766
  }
10542
- /**
10543
- * Creates a new IndexedDbRemoteDocumentCache.
10544
- *
10545
- * @param serializer - The document serializer.
10546
- * @param indexManager - The query indexes that need to be maintained.
10547
- */
10548
- function newIndexedDbRemoteDocumentCache(serializer, indexManager) {
10549
- return new IndexedDbRemoteDocumentCacheImpl(serializer, indexManager);
10767
+ /** Creates a new IndexedDbRemoteDocumentCache. */
10768
+ function newIndexedDbRemoteDocumentCache(serializer) {
10769
+ return new IndexedDbRemoteDocumentCacheImpl(serializer);
10550
10770
  }
10551
10771
  /**
10552
10772
  * Returns the set of documents that have changed since the specified read
@@ -10992,14 +11212,17 @@ function createNamedQueriesStore(db) {
10992
11212
  });
10993
11213
  }
10994
11214
  function createFieldIndex(db) {
10995
- db.createObjectStore(DbIndexConfiguration.store, {
10996
- keyPath: DbIndexConfiguration.keyPath
11215
+ const indexConfiguratioStore = db.createObjectStore(DbIndexConfiguration.store, {
11216
+ keyPath: DbIndexConfiguration.keyPath,
11217
+ autoIncrement: true
10997
11218
  });
10998
- db.createObjectStore(DbIndexState.store, {
11219
+ indexConfiguratioStore.createIndex(DbIndexConfiguration.collectionGroupIndex, DbIndexConfiguration.collectionGroupIndexPath, { unique: false });
11220
+ const indexStateStore = db.createObjectStore(DbIndexState.store, {
10999
11221
  keyPath: DbIndexState.keyPath
11000
11222
  });
11001
- db.createObjectStore(DbIndexEntries.store, {
11002
- keyPath: DbIndexEntries.keyPath
11223
+ indexStateStore.createIndex(DbIndexState.sequenceNumberIndex, DbIndexState.sequenceNumberIndexPath, { unique: false });
11224
+ db.createObjectStore(DbIndexEntry.store, {
11225
+ keyPath: DbIndexEntry.keyPath
11003
11226
  });
11004
11227
  }
11005
11228
 
@@ -11112,7 +11335,7 @@ class IndexedDbPersistence {
11112
11335
  * If set to true, forcefully obtains database access. Existing tabs will
11113
11336
  * no longer be able to access IndexedDB.
11114
11337
  */
11115
- forceOwningTab) {
11338
+ forceOwningTab, schemaVersion = SCHEMA_VERSION) {
11116
11339
  this.allowTabSynchronization = allowTabSynchronization;
11117
11340
  this.persistenceKey = persistenceKey;
11118
11341
  this.clientId = clientId;
@@ -11121,6 +11344,7 @@ class IndexedDbPersistence {
11121
11344
  this.document = document;
11122
11345
  this.sequenceNumberSyncer = sequenceNumberSyncer;
11123
11346
  this.forceOwningTab = forceOwningTab;
11347
+ this.schemaVersion = schemaVersion;
11124
11348
  this.listenSequence = null;
11125
11349
  this._started = false;
11126
11350
  this.isPrimary = false;
@@ -11142,10 +11366,9 @@ class IndexedDbPersistence {
11142
11366
  this.referenceDelegate = new IndexedDbLruDelegateImpl(this, lruParams);
11143
11367
  this.dbName = persistenceKey + MAIN_DATABASE;
11144
11368
  this.serializer = new LocalSerializer(serializer);
11145
- this.simpleDb = new SimpleDb(this.dbName, SCHEMA_VERSION, new SchemaConverter(this.serializer));
11369
+ this.simpleDb = new SimpleDb(this.dbName, this.schemaVersion, new SchemaConverter(this.serializer));
11146
11370
  this.targetCache = new IndexedDbTargetCache(this.referenceDelegate, this.serializer);
11147
- this.indexManager = new IndexedDbIndexManager();
11148
- this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer, this.indexManager);
11371
+ this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer);
11149
11372
  this.bundleCache = new IndexedDbBundleCache();
11150
11373
  if (this.window && this.window.localStorage) {
11151
11374
  this.webStorage = this.window.localStorage;
@@ -11481,8 +11704,8 @@ class IndexedDbPersistence {
11481
11704
  get started() {
11482
11705
  return this._started;
11483
11706
  }
11484
- getMutationQueue(user) {
11485
- return IndexedDbMutationQueue.forUser(user, this.serializer, this.indexManager, this.referenceDelegate);
11707
+ getMutationQueue(user, indexManager) {
11708
+ return IndexedDbMutationQueue.forUser(user, this.serializer, indexManager, this.referenceDelegate);
11486
11709
  }
11487
11710
  getTargetCache() {
11488
11711
  return this.targetCache;
@@ -11490,8 +11713,8 @@ class IndexedDbPersistence {
11490
11713
  getRemoteDocumentCache() {
11491
11714
  return this.remoteDocumentCache;
11492
11715
  }
11493
- getIndexManager() {
11494
- return this.indexManager;
11716
+ getIndexManager(user) {
11717
+ return new IndexedDbIndexManager(user);
11495
11718
  }
11496
11719
  getBundleCache() {
11497
11720
  return this.bundleCache;
@@ -11499,11 +11722,12 @@ class IndexedDbPersistence {
11499
11722
  runTransaction(action, mode, transactionOperation) {
11500
11723
  logDebug(LOG_TAG$d, 'Starting transaction:', action);
11501
11724
  const simpleDbMode = mode === 'readonly' ? 'readonly' : 'readwrite';
11725
+ const objectStores = getObjectStores(this.schemaVersion);
11502
11726
  let persistenceTransaction;
11503
11727
  // Do all transactions as readwrite against all object stores, since we
11504
11728
  // are the only reader/writer.
11505
11729
  return this.simpleDb
11506
- .runTransaction(action, simpleDbMode, ALL_STORES, simpleDbTxn => {
11730
+ .runTransaction(action, simpleDbMode, objectStores, simpleDbTxn => {
11507
11731
  persistenceTransaction = new IndexedDbTransaction(simpleDbTxn, this.listenSequence
11508
11732
  ? this.listenSequence.next()
11509
11733
  : ListenSequence.INVALID);
@@ -11875,39 +12099,28 @@ class LocalDocumentsView {
11875
12099
  getDocumentsMatchingCollectionQuery(transaction, query, sinceReadTime) {
11876
12100
  // Query the remote documents and overlay mutations.
11877
12101
  let results;
11878
- let mutationBatches;
11879
12102
  return this.remoteDocumentCache
11880
- .getDocumentsMatchingQuery(transaction, query, sinceReadTime)
12103
+ .getAll(transaction, query.path, sinceReadTime)
11881
12104
  .next(queryResults => {
11882
12105
  results = queryResults;
11883
12106
  return this.mutationQueue.getAllMutationBatchesAffectingQuery(transaction, query);
11884
12107
  })
11885
- .next(matchingMutationBatches => {
11886
- mutationBatches = matchingMutationBatches;
11887
- // It is possible that a PatchMutation can make a document match a query, even if
11888
- // the version in the RemoteDocumentCache is not a match yet (waiting for server
11889
- // to ack). To handle this, we find all document keys affected by the PatchMutations
11890
- // that are not in `result` yet, and back fill them via `remoteDocumentCache.getEntries`,
11891
- // otherwise those `PatchMutations` will be ignored because no base document can be found,
11892
- // and lead to missing result for the query.
11893
- return this.addMissingBaseDocuments(transaction, mutationBatches, results).next(mergedDocuments => {
11894
- results = mergedDocuments;
11895
- for (const batch of mutationBatches) {
11896
- for (const mutation of batch.mutations) {
11897
- const key = mutation.key;
11898
- let document = results.get(key);
11899
- if (document == null) {
11900
- // Create invalid document to apply mutations on top of
11901
- document = MutableDocument.newInvalidDocument(key);
11902
- results = results.insert(key, document);
11903
- }
11904
- mutationApplyToLocalView(mutation, document, batch.localWriteTime);
11905
- if (!document.isFoundDocument()) {
11906
- results = results.remove(key);
11907
- }
12108
+ .next(mutationBatches => {
12109
+ for (const batch of mutationBatches) {
12110
+ for (const mutation of batch.mutations) {
12111
+ const key = mutation.key;
12112
+ let document = results.get(key);
12113
+ if (document == null) {
12114
+ // Create invalid document to apply mutations on top of
12115
+ document = MutableDocument.newInvalidDocument(key);
12116
+ results = results.insert(key, document);
12117
+ }
12118
+ mutationApplyToLocalView(mutation, document, batch.localWriteTime);
12119
+ if (!document.isFoundDocument()) {
12120
+ results = results.remove(key);
11908
12121
  }
11909
12122
  }
11910
- });
12123
+ }
11911
12124
  })
11912
12125
  .next(() => {
11913
12126
  // Finally, filter out any documents that don't actually match
@@ -11920,29 +12133,6 @@ class LocalDocumentsView {
11920
12133
  return results;
11921
12134
  });
11922
12135
  }
11923
- addMissingBaseDocuments(transaction, matchingMutationBatches, existingDocuments) {
11924
- let missingBaseDocEntriesForPatching = documentKeySet();
11925
- for (const batch of matchingMutationBatches) {
11926
- for (const mutation of batch.mutations) {
11927
- if (mutation instanceof PatchMutation &&
11928
- existingDocuments.get(mutation.key) === null) {
11929
- missingBaseDocEntriesForPatching =
11930
- missingBaseDocEntriesForPatching.add(mutation.key);
11931
- }
11932
- }
11933
- }
11934
- let mergedDocuments = existingDocuments;
11935
- return this.remoteDocumentCache
11936
- .getEntries(transaction, missingBaseDocEntriesForPatching)
11937
- .next(missingBaseDocs => {
11938
- missingBaseDocs.forEach((key, doc) => {
11939
- if (doc.isFoundDocument()) {
11940
- mergedDocuments = mergedDocuments.insert(key, doc);
11941
- }
11942
- });
11943
- return mergedDocuments;
11944
- });
11945
- }
11946
12136
  }
11947
12137
 
11948
12138
  /**
@@ -12001,11 +12191,18 @@ class LocalStoreImpl {
12001
12191
  * PORTING NOTE: This is only used for multi-tab synchronization.
12002
12192
  */
12003
12193
  this.lastDocumentChangeReadTime = SnapshotVersion.min();
12004
- this.mutationQueue = persistence.getMutationQueue(initialUser);
12005
12194
  this.remoteDocuments = persistence.getRemoteDocumentCache();
12006
12195
  this.targetCache = persistence.getTargetCache();
12007
- this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.persistence.getIndexManager());
12008
12196
  this.bundleCache = persistence.getBundleCache();
12197
+ this.initializeUserComponents(initialUser);
12198
+ }
12199
+ initializeUserComponents(user) {
12200
+ // TODO(indexing): Add spec tests that test these components change after a
12201
+ // user change
12202
+ this.indexManager = this.persistence.getIndexManager(user);
12203
+ this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
12204
+ this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
12205
+ this.remoteDocuments.setIndexManager(this.indexManager);
12009
12206
  this.queryEngine.setLocalDocumentsView(this.localDocuments);
12010
12207
  }
12011
12208
  collectGarbage(garbageCollector) {
@@ -12027,8 +12224,6 @@ persistence, queryEngine, initialUser, serializer) {
12027
12224
  // change.
12028
12225
  async function localStoreHandleUserChange(localStore, user) {
12029
12226
  const localStoreImpl = debugCast(localStore);
12030
- let newMutationQueue = localStoreImpl.mutationQueue;
12031
- let newLocalDocuments = localStoreImpl.localDocuments;
12032
12227
  const result = await localStoreImpl.persistence.runTransaction('Handle user change', 'readonly', txn => {
12033
12228
  // Swap out the mutation queue, grabbing the pending mutation batches
12034
12229
  // before and after.
@@ -12037,11 +12232,8 @@ async function localStoreHandleUserChange(localStore, user) {
12037
12232
  .getAllMutationBatches(txn)
12038
12233
  .next(promisedOldBatches => {
12039
12234
  oldBatches = promisedOldBatches;
12040
- newMutationQueue = localStoreImpl.persistence.getMutationQueue(user);
12041
- // Recreate our LocalDocumentsView using the new
12042
- // MutationQueue.
12043
- newLocalDocuments = new LocalDocumentsView(localStoreImpl.remoteDocuments, newMutationQueue, localStoreImpl.persistence.getIndexManager());
12044
- return newMutationQueue.getAllMutationBatches(txn);
12235
+ localStoreImpl.initializeUserComponents(user);
12236
+ return localStoreImpl.mutationQueue.getAllMutationBatches(txn);
12045
12237
  })
12046
12238
  .next(newBatches => {
12047
12239
  const removedBatchIds = [];
@@ -12062,7 +12254,7 @@ async function localStoreHandleUserChange(localStore, user) {
12062
12254
  }
12063
12255
  // Return the set of all (potentially) changed documents and the list
12064
12256
  // of mutation batch IDs that were affected by change.
12065
- return newLocalDocuments
12257
+ return localStoreImpl.localDocuments
12066
12258
  .getDocuments(txn, changedKeys)
12067
12259
  .next(affectedDocuments => {
12068
12260
  return {
@@ -12073,9 +12265,6 @@ async function localStoreHandleUserChange(localStore, user) {
12073
12265
  });
12074
12266
  });
12075
12267
  });
12076
- localStoreImpl.mutationQueue = newMutationQueue;
12077
- localStoreImpl.localDocuments = newLocalDocuments;
12078
- localStoreImpl.queryEngine.setLocalDocumentsView(localStoreImpl.localDocuments);
12079
12268
  return result;
12080
12269
  }
12081
12270
  /* Accepts locally generated Mutations and commit them to storage. */
@@ -13141,14 +13330,16 @@ class MemoryRemoteDocumentCacheImpl {
13141
13330
  * expected to just return 0 to avoid unnecessarily doing the work of
13142
13331
  * calculating the size.
13143
13332
  */
13144
- constructor(indexManager, sizer) {
13145
- this.indexManager = indexManager;
13333
+ constructor(sizer) {
13146
13334
  this.sizer = sizer;
13147
13335
  /** Underlying cache of documents and their read times. */
13148
13336
  this.docs = documentEntryMap();
13149
13337
  /** Size of all cached documents. */
13150
13338
  this.size = 0;
13151
13339
  }
13340
+ setIndexManager(indexManager) {
13341
+ this.indexManager = indexManager;
13342
+ }
13152
13343
  /**
13153
13344
  * Adds the supplied entry to the cache and updates the cache size as appropriate.
13154
13345
  *
@@ -13196,21 +13387,22 @@ class MemoryRemoteDocumentCacheImpl {
13196
13387
  });
13197
13388
  return PersistencePromise.resolve(results);
13198
13389
  }
13199
- getDocumentsMatchingQuery(transaction, query, sinceReadTime) {
13390
+ getAll(transaction, collectionPath, sinceReadTime) {
13200
13391
  let results = mutableDocumentMap();
13201
13392
  // Documents are ordered by key, so we can use a prefix scan to narrow down
13202
13393
  // the documents we need to match the query against.
13203
- const prefix = new DocumentKey(query.path.child(''));
13394
+ const prefix = new DocumentKey(collectionPath.child(''));
13204
13395
  const iterator = this.docs.getIteratorFrom(prefix);
13205
13396
  while (iterator.hasNext()) {
13206
13397
  const { key, value: { document } } = iterator.getNext();
13207
- if (!query.path.isPrefixOf(key.path)) {
13398
+ if (!collectionPath.isPrefixOf(key.path)) {
13208
13399
  break;
13209
13400
  }
13210
- if (document.readTime.compareTo(sinceReadTime) <= 0) {
13401
+ if (key.path.length > collectionPath.length + 1) {
13402
+ // Exclude entries from subcollections.
13211
13403
  continue;
13212
13404
  }
13213
- if (!queryMatches(query, document)) {
13405
+ if (document.readTime.compareTo(sinceReadTime) <= 0) {
13214
13406
  continue;
13215
13407
  }
13216
13408
  results = results.insert(document.key, document.mutableCopy());
@@ -13232,13 +13424,12 @@ class MemoryRemoteDocumentCacheImpl {
13232
13424
  /**
13233
13425
  * Creates a new memory-only RemoteDocumentCache.
13234
13426
  *
13235
- * @param indexManager - A class that manages collection group indices.
13236
13427
  * @param sizer - Used to assess the size of a document. For eager GC, this is
13237
13428
  * expected to just return 0 to avoid unnecessarily doing the work of
13238
13429
  * calculating the size.
13239
13430
  */
13240
- function newMemoryRemoteDocumentCache(indexManager, sizer) {
13241
- return new MemoryRemoteDocumentCacheImpl(indexManager, sizer);
13431
+ function newMemoryRemoteDocumentCache(sizer) {
13432
+ return new MemoryRemoteDocumentCacheImpl(sizer);
13242
13433
  }
13243
13434
  /**
13244
13435
  * Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
@@ -13439,7 +13630,7 @@ class MemoryPersistence {
13439
13630
  this.targetCache = new MemoryTargetCache(this);
13440
13631
  const sizer = (doc) => this.referenceDelegate.documentSize(doc);
13441
13632
  this.indexManager = new MemoryIndexManager();
13442
- this.remoteDocumentCache = newMemoryRemoteDocumentCache(this.indexManager, sizer);
13633
+ this.remoteDocumentCache = newMemoryRemoteDocumentCache(sizer);
13443
13634
  this.serializer = new LocalSerializer(serializer);
13444
13635
  this.bundleCache = new MemoryBundleCache(this.serializer);
13445
13636
  }
@@ -13460,13 +13651,15 @@ class MemoryPersistence {
13460
13651
  setNetworkEnabled() {
13461
13652
  // No op.
13462
13653
  }
13463
- getIndexManager() {
13654
+ getIndexManager(user) {
13655
+ // We do not currently support indices for memory persistence, so we can
13656
+ // return the same shared instance of the memory index manager.
13464
13657
  return this.indexManager;
13465
13658
  }
13466
- getMutationQueue(user) {
13659
+ getMutationQueue(user, indexManager) {
13467
13660
  let queue = this.mutationQueues[user.toKey()];
13468
13661
  if (!queue) {
13469
- queue = new MemoryMutationQueue(this.indexManager, this.referenceDelegate);
13662
+ queue = new MemoryMutationQueue(indexManager, this.referenceDelegate);
13470
13663
  this.mutationQueues[user.toKey()] = queue;
13471
13664
  }
13472
13665
  return queue;
@@ -20429,12 +20622,12 @@ async function syncEngineListen(syncEngine, query) {
20429
20622
  }
20430
20623
  else {
20431
20624
  const targetData = await localStoreAllocateTarget(syncEngineImpl.localStore, queryToTarget(query));
20432
- const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
20433
- targetId = targetData.targetId;
20434
- viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20435
20625
  if (syncEngineImpl.isPrimaryClient) {
20436
20626
  remoteStoreListen(syncEngineImpl.remoteStore, targetData);
20437
20627
  }
20628
+ const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
20629
+ targetId = targetData.targetId;
20630
+ viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
20438
20631
  }
20439
20632
  return viewSnapshot;
20440
20633
  }
@@ -24942,8 +25135,7 @@ class DocumentSnapshot extends DocumentSnapshot$1 {
24942
25135
  this.metadata = metadata;
24943
25136
  }
24944
25137
  /**
24945
- * Property of the `DocumentSnapshot` that signals whether or not the data
24946
- * exists. True if the document exists.
25138
+ * Returns whether or not the data exists. True if the document exists.
24947
25139
  */
24948
25140
  exists() {
24949
25141
  return super.exists();
@@ -25317,51 +25509,53 @@ function limitToLast(limit) {
25317
25509
  return new QueryLimitConstraint('limitToLast', limit, "L" /* Last */);
25318
25510
  }
25319
25511
  class QueryStartAtConstraint extends QueryConstraint {
25320
- constructor(type, _docOrFields, _before) {
25512
+ constructor(type, _docOrFields, _inclusive) {
25321
25513
  super();
25322
25514
  this.type = type;
25323
25515
  this._docOrFields = _docOrFields;
25324
- this._before = _before;
25516
+ this._inclusive = _inclusive;
25325
25517
  }
25326
25518
  _apply(query) {
25327
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25519
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25328
25520
  return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
25329
25521
  }
25330
25522
  }
25331
25523
  function startAt(...docOrFields) {
25332
- return new QueryStartAtConstraint('startAt', docOrFields, /*before=*/ true);
25524
+ return new QueryStartAtConstraint('startAt', docOrFields,
25525
+ /*inclusive=*/ true);
25333
25526
  }
25334
25527
  function startAfter(...docOrFields) {
25335
25528
  return new QueryStartAtConstraint('startAfter', docOrFields,
25336
- /*before=*/ false);
25529
+ /*inclusive=*/ false);
25337
25530
  }
25338
25531
  class QueryEndAtConstraint extends QueryConstraint {
25339
- constructor(type, _docOrFields, _before) {
25532
+ constructor(type, _docOrFields, _inclusive) {
25340
25533
  super();
25341
25534
  this.type = type;
25342
25535
  this._docOrFields = _docOrFields;
25343
- this._before = _before;
25536
+ this._inclusive = _inclusive;
25344
25537
  }
25345
25538
  _apply(query) {
25346
- const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._before);
25539
+ const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
25347
25540
  return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
25348
25541
  }
25349
25542
  }
25350
25543
  function endBefore(...docOrFields) {
25351
- return new QueryEndAtConstraint('endBefore', docOrFields, /*before=*/ true);
25544
+ return new QueryEndAtConstraint('endBefore', docOrFields,
25545
+ /*inclusive=*/ false);
25352
25546
  }
25353
25547
  function endAt(...docOrFields) {
25354
- return new QueryEndAtConstraint('endAt', docOrFields, /*before=*/ false);
25548
+ return new QueryEndAtConstraint('endAt', docOrFields, /*inclusive=*/ true);
25355
25549
  }
25356
25550
  /** Helper function to create a bound from a document or fields */
25357
- function newQueryBoundFromDocOrFields(query, methodName, docOrFields, before) {
25551
+ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
25358
25552
  docOrFields[0] = util$1.getModularInstance(docOrFields[0]);
25359
25553
  if (docOrFields[0] instanceof DocumentSnapshot$1) {
25360
- return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, before);
25554
+ return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive);
25361
25555
  }
25362
25556
  else {
25363
25557
  const reader = newUserDataReader(query.firestore);
25364
- return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, before);
25558
+ return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive);
25365
25559
  }
25366
25560
  }
25367
25561
  function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
@@ -25419,7 +25613,7 @@ function newQueryOrderBy(query, fieldPath, direction) {
25419
25613
  * of the query or if any of the fields in the order by are an uncommitted
25420
25614
  * server timestamp.
25421
25615
  */
25422
- function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25616
+ function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) {
25423
25617
  if (!doc) {
25424
25618
  throw new FirestoreError(Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` +
25425
25619
  `${methodName}().`);
@@ -25456,12 +25650,12 @@ function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
25456
25650
  }
25457
25651
  }
25458
25652
  }
25459
- return new Bound(components, before);
25653
+ return new Bound(components, inclusive);
25460
25654
  }
25461
25655
  /**
25462
25656
  * Converts a list of field values to a `Bound` for the given query.
25463
25657
  */
25464
- function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, before) {
25658
+ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) {
25465
25659
  // Use explicit order by's because it has to match the query the user made
25466
25660
  const orderBy = query.explicitOrderBy;
25467
25661
  if (values.length > orderBy.length) {
@@ -25498,7 +25692,7 @@ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, valu
25498
25692
  components.push(wrapped);
25499
25693
  }
25500
25694
  }
25501
- return new Bound(components, before);
25695
+ return new Bound(components, inclusive);
25502
25696
  }
25503
25697
  /**
25504
25698
  * Parses the given `documentIdValue` into a `ReferenceValue`, throwing