@firebase/firestore 3.4.8-canary.7b58dabdf → 3.4.8-canary.874cdbbcc

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 (113) hide show
  1. package/dist/firestore/lite/index.d.ts +1 -0
  2. package/dist/firestore/src/api/transaction.d.ts +2 -1
  3. package/dist/firestore/src/api/transaction_options.d.ts +17 -0
  4. package/dist/firestore/src/api.d.ts +1 -0
  5. package/dist/firestore/src/core/firestore_client.d.ts +2 -1
  6. package/dist/firestore/src/core/query.d.ts +2 -4
  7. package/dist/firestore/src/core/target.d.ts +4 -4
  8. package/dist/firestore/src/core/transaction_options.d.ts +25 -0
  9. package/dist/firestore/src/core/transaction_runner.d.ts +3 -2
  10. package/dist/firestore/src/lite-api/transaction.d.ts +2 -1
  11. package/dist/firestore/src/lite-api/transaction_options.d.ts +23 -0
  12. package/dist/firestore/src/local/index_manager.d.ts +5 -0
  13. package/dist/firestore/src/local/indexeddb_index_manager.d.ts +1 -5
  14. package/dist/firestore/src/local/indexeddb_schema.d.ts +1 -0
  15. package/dist/firestore/src/local/local_documents_view.d.ts +1 -1
  16. package/dist/firestore/src/local/memory_index_manager.d.ts +1 -0
  17. package/dist/firestore/src/local/query_engine.d.ts +44 -5
  18. package/dist/firestore/src/model/collections.d.ts +1 -1
  19. package/dist/firestore/src/model/values.d.ts +14 -2
  20. package/dist/firestore/src/util/misc.d.ts +3 -0
  21. package/dist/firestore/test/unit/local/counting_query_engine.d.ts +2 -1
  22. package/dist/index.d.ts +24 -1
  23. package/dist/index.esm2017.js +2881 -2791
  24. package/dist/index.esm2017.js.map +1 -1
  25. package/dist/index.esm5.js +3098 -3014
  26. package/dist/index.esm5.js.map +1 -1
  27. package/dist/index.node.cjs.js +210 -114
  28. package/dist/index.node.cjs.js.map +1 -1
  29. package/dist/index.node.mjs +210 -114
  30. package/dist/index.node.mjs.map +1 -1
  31. package/dist/index.rn.js +2948 -2858
  32. package/dist/index.rn.js.map +1 -1
  33. package/dist/internal.d.ts +30 -1
  34. package/dist/lite/firestore/lite/index.d.ts +1 -0
  35. package/dist/lite/firestore/src/api/transaction.d.ts +2 -1
  36. package/dist/lite/firestore/src/api/transaction_options.d.ts +17 -0
  37. package/dist/lite/firestore/src/api.d.ts +1 -0
  38. package/dist/lite/firestore/src/core/firestore_client.d.ts +2 -1
  39. package/dist/lite/firestore/src/core/query.d.ts +2 -4
  40. package/dist/lite/firestore/src/core/target.d.ts +4 -4
  41. package/dist/lite/firestore/src/core/transaction_options.d.ts +25 -0
  42. package/dist/lite/firestore/src/core/transaction_runner.d.ts +3 -2
  43. package/dist/lite/firestore/src/lite-api/transaction.d.ts +2 -1
  44. package/dist/lite/firestore/src/lite-api/transaction_options.d.ts +23 -0
  45. package/dist/lite/firestore/src/local/index_manager.d.ts +5 -0
  46. package/dist/lite/firestore/src/local/indexeddb_index_manager.d.ts +1 -5
  47. package/dist/lite/firestore/src/local/indexeddb_schema.d.ts +1 -0
  48. package/dist/lite/firestore/src/local/local_documents_view.d.ts +1 -1
  49. package/dist/lite/firestore/src/local/memory_index_manager.d.ts +1 -0
  50. package/dist/lite/firestore/src/local/query_engine.d.ts +44 -5
  51. package/dist/lite/firestore/src/model/collections.d.ts +1 -1
  52. package/dist/lite/firestore/src/model/values.d.ts +14 -2
  53. package/dist/lite/firestore/src/util/misc.d.ts +3 -0
  54. package/dist/lite/firestore/test/unit/local/counting_query_engine.d.ts +2 -1
  55. package/dist/lite/index.browser.esm2017.js +279 -250
  56. package/dist/lite/index.browser.esm2017.js.map +1 -1
  57. package/dist/lite/index.browser.esm5.js +293 -285
  58. package/dist/lite/index.browser.esm5.js.map +1 -1
  59. package/dist/lite/index.d.ts +24 -1
  60. package/dist/lite/index.node.cjs.js +56 -15
  61. package/dist/lite/index.node.cjs.js.map +1 -1
  62. package/dist/lite/index.node.mjs +56 -15
  63. package/dist/lite/index.node.mjs.map +1 -1
  64. package/dist/lite/index.rn.esm2017.js +1227 -1198
  65. package/dist/lite/index.rn.esm2017.js.map +1 -1
  66. package/dist/lite/internal.d.ts +25 -1
  67. package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +13 -13
  68. package/dist/lite/packages/firestore/lite/index.d.ts +1 -0
  69. package/dist/lite/packages/firestore/src/api/transaction.d.ts +2 -1
  70. package/dist/lite/packages/firestore/src/api/transaction_options.d.ts +17 -0
  71. package/dist/lite/packages/firestore/src/api.d.ts +1 -0
  72. package/dist/lite/packages/firestore/src/core/firestore_client.d.ts +2 -1
  73. package/dist/lite/packages/firestore/src/core/query.d.ts +2 -4
  74. package/dist/lite/packages/firestore/src/core/target.d.ts +4 -4
  75. package/dist/lite/packages/firestore/src/core/transaction_options.d.ts +25 -0
  76. package/dist/lite/packages/firestore/src/core/transaction_runner.d.ts +3 -2
  77. package/dist/lite/packages/firestore/src/lite-api/transaction.d.ts +2 -1
  78. package/dist/lite/packages/firestore/src/lite-api/transaction_options.d.ts +23 -0
  79. package/dist/lite/packages/firestore/src/local/index_manager.d.ts +5 -0
  80. package/dist/lite/packages/firestore/src/local/indexeddb_index_manager.d.ts +1 -5
  81. package/dist/lite/packages/firestore/src/local/indexeddb_schema.d.ts +1 -0
  82. package/dist/lite/packages/firestore/src/local/local_documents_view.d.ts +1 -1
  83. package/dist/lite/packages/firestore/src/local/memory_index_manager.d.ts +1 -0
  84. package/dist/lite/packages/firestore/src/local/query_engine.d.ts +44 -5
  85. package/dist/lite/packages/firestore/src/model/collections.d.ts +1 -1
  86. package/dist/lite/packages/firestore/src/model/values.d.ts +14 -2
  87. package/dist/lite/packages/firestore/src/util/misc.d.ts +3 -0
  88. package/dist/lite/packages/firestore/test/unit/local/counting_query_engine.d.ts +2 -1
  89. package/dist/lite/private.d.ts +25 -1
  90. package/dist/packages/firestore/dist/index.esm2017.d.ts +157 -156
  91. package/dist/packages/firestore/lite/index.d.ts +1 -0
  92. package/dist/packages/firestore/src/api/transaction.d.ts +2 -1
  93. package/dist/packages/firestore/src/api/transaction_options.d.ts +17 -0
  94. package/dist/packages/firestore/src/api.d.ts +1 -0
  95. package/dist/packages/firestore/src/core/firestore_client.d.ts +2 -1
  96. package/dist/packages/firestore/src/core/query.d.ts +2 -4
  97. package/dist/packages/firestore/src/core/target.d.ts +4 -4
  98. package/dist/packages/firestore/src/core/transaction_options.d.ts +25 -0
  99. package/dist/packages/firestore/src/core/transaction_runner.d.ts +3 -2
  100. package/dist/packages/firestore/src/lite-api/transaction.d.ts +2 -1
  101. package/dist/packages/firestore/src/lite-api/transaction_options.d.ts +23 -0
  102. package/dist/packages/firestore/src/local/index_manager.d.ts +5 -0
  103. package/dist/packages/firestore/src/local/indexeddb_index_manager.d.ts +1 -5
  104. package/dist/packages/firestore/src/local/indexeddb_schema.d.ts +1 -0
  105. package/dist/packages/firestore/src/local/local_documents_view.d.ts +1 -1
  106. package/dist/packages/firestore/src/local/memory_index_manager.d.ts +1 -0
  107. package/dist/packages/firestore/src/local/query_engine.d.ts +44 -5
  108. package/dist/packages/firestore/src/model/collections.d.ts +1 -1
  109. package/dist/packages/firestore/src/model/values.d.ts +14 -2
  110. package/dist/packages/firestore/src/util/misc.d.ts +3 -0
  111. package/dist/packages/firestore/test/unit/local/counting_query_engine.d.ts +2 -1
  112. package/dist/private.d.ts +30 -1
  113. package/package.json +10 -10
@@ -8,7 +8,7 @@ import * as grpc from '@grpc/grpc-js';
8
8
  import * as protoLoader from '@grpc/proto-loader';
9
9
 
10
10
  const name = "@firebase/firestore";
11
- const version$1 = "3.4.8-canary.7b58dabdf";
11
+ const version$1 = "3.4.8-canary.874cdbbcc";
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.11-canary.7b58dabdf";
64
+ const version = "9.7.0-canary.874cdbbcc";
65
65
 
66
66
  /**
67
67
  * @license
@@ -3321,7 +3321,7 @@ function typeOrder(value) {
3321
3321
  return 4 /* ServerTimestampValue */;
3322
3322
  }
3323
3323
  else if (isMaxValue(value)) {
3324
- return 9 /* ArrayValue */;
3324
+ return 9007199254740991 /* MaxValue */;
3325
3325
  }
3326
3326
  return 10 /* ObjectValue */;
3327
3327
  }
@@ -3533,6 +3533,15 @@ function compareArrays(left, right) {
3533
3533
  return primitiveComparator(leftArray.length, rightArray.length);
3534
3534
  }
3535
3535
  function compareMaps(left, right) {
3536
+ if (left === MAX_VALUE.mapValue && right === MAX_VALUE.mapValue) {
3537
+ return 0;
3538
+ }
3539
+ else if (left === MAX_VALUE.mapValue) {
3540
+ return 1;
3541
+ }
3542
+ else if (right === MAX_VALUE.mapValue) {
3543
+ return -1;
3544
+ }
3536
3545
  const leftMap = left.fields || {};
3537
3546
  const leftKeys = Object.keys(leftMap);
3538
3547
  const rightMap = right.fields || {};
@@ -3780,27 +3789,31 @@ function valuesGetUpperBound(value) {
3780
3789
  return fail();
3781
3790
  }
3782
3791
  }
3783
- function valuesMax(left, right) {
3784
- if (left === undefined) {
3785
- return right;
3792
+ function lowerBoundCompare(left, right) {
3793
+ const cmp = valueCompare(left.value, right.value);
3794
+ if (cmp !== 0) {
3795
+ return cmp;
3786
3796
  }
3787
- else if (right === undefined) {
3788
- return left;
3797
+ if (left.inclusive && !right.inclusive) {
3798
+ return -1;
3789
3799
  }
3790
- else {
3791
- return valueCompare(left, right) > 0 ? left : right;
3800
+ else if (!left.inclusive && right.inclusive) {
3801
+ return 1;
3792
3802
  }
3803
+ return 0;
3793
3804
  }
3794
- function valuesMin(left, right) {
3795
- if (left === undefined) {
3796
- return right;
3805
+ function upperBoundCompare(left, right) {
3806
+ const cmp = valueCompare(left.value, right.value);
3807
+ if (cmp !== 0) {
3808
+ return cmp;
3797
3809
  }
3798
- else if (right === undefined) {
3799
- return left;
3810
+ if (left.inclusive && !right.inclusive) {
3811
+ return 1;
3800
3812
  }
3801
- else {
3802
- return valueCompare(left, right) < 0 ? left : right;
3813
+ else if (!left.inclusive && right.inclusive) {
3814
+ return -1;
3803
3815
  }
3816
+ return 0;
3804
3817
  }
3805
3818
 
3806
3819
  /**
@@ -5184,7 +5197,7 @@ function targetGetNotInValues(target, fieldIndex) {
5184
5197
  }
5185
5198
  /**
5186
5199
  * Returns a lower bound of field values that can be used as a starting point to
5187
- * scan the index defined by `fieldIndex`. Returns `null` if no lower bound
5200
+ * scan the index defined by `fieldIndex`. Returns `MIN_VALUE` if no lower bound
5188
5201
  * exists.
5189
5202
  */
5190
5203
  function targetGetLowerBound(target, fieldIndex) {
@@ -5196,10 +5209,6 @@ function targetGetLowerBound(target, fieldIndex) {
5196
5209
  const segmentBound = segment.kind === 0 /* ASCENDING */
5197
5210
  ? targetGetAscendingBound(target, segment.fieldPath, target.startAt)
5198
5211
  : targetGetDescendingBound(target, segment.fieldPath, target.startAt);
5199
- if (!segmentBound.value) {
5200
- // No lower bound exists
5201
- return null;
5202
- }
5203
5212
  values.push(segmentBound.value);
5204
5213
  inclusive && (inclusive = segmentBound.inclusive);
5205
5214
  }
@@ -5207,7 +5216,7 @@ function targetGetLowerBound(target, fieldIndex) {
5207
5216
  }
5208
5217
  /**
5209
5218
  * Returns an upper bound of field values that can be used as an ending point
5210
- * when scanning the index defined by `fieldIndex`. Returns `null` if no
5219
+ * when scanning the index defined by `fieldIndex`. Returns `MAX_VALUE` if no
5211
5220
  * upper bound exists.
5212
5221
  */
5213
5222
  function targetGetUpperBound(target, fieldIndex) {
@@ -5219,10 +5228,6 @@ function targetGetUpperBound(target, fieldIndex) {
5219
5228
  const segmentBound = segment.kind === 0 /* ASCENDING */
5220
5229
  ? targetGetDescendingBound(target, segment.fieldPath, target.endAt)
5221
5230
  : targetGetAscendingBound(target, segment.fieldPath, target.endAt);
5222
- if (!segmentBound.value) {
5223
- // No upper bound exists
5224
- return null;
5225
- }
5226
5231
  values.push(segmentBound.value);
5227
5232
  inclusive && (inclusive = segmentBound.inclusive);
5228
5233
  }
@@ -5233,11 +5238,11 @@ function targetGetUpperBound(target, fieldIndex) {
5233
5238
  * the provided `fieldPath` (or the upper bound for an descending segment).
5234
5239
  */
5235
5240
  function targetGetAscendingBound(target, fieldPath, bound) {
5236
- let value = undefined;
5241
+ let value = MIN_VALUE;
5237
5242
  let inclusive = true;
5238
5243
  // Process all filters to find a value for the current field segment
5239
5244
  for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
5240
- let filterValue = undefined;
5245
+ let filterValue = MIN_VALUE;
5241
5246
  let filterInclusive = true;
5242
5247
  switch (fieldFilter.op) {
5243
5248
  case "<" /* LESS_THAN */:
@@ -5259,7 +5264,7 @@ function targetGetAscendingBound(target, fieldPath, bound) {
5259
5264
  break;
5260
5265
  // Remaining filters cannot be used as lower bounds.
5261
5266
  }
5262
- if (valuesMax(value, filterValue) === filterValue) {
5267
+ if (lowerBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) < 0) {
5263
5268
  value = filterValue;
5264
5269
  inclusive = filterInclusive;
5265
5270
  }
@@ -5271,7 +5276,7 @@ function targetGetAscendingBound(target, fieldPath, bound) {
5271
5276
  const orderBy = target.orderBy[i];
5272
5277
  if (orderBy.field.isEqual(fieldPath)) {
5273
5278
  const cursorValue = bound.position[i];
5274
- if (valuesMax(value, cursorValue) === cursorValue) {
5279
+ if (lowerBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) < 0) {
5275
5280
  value = cursorValue;
5276
5281
  inclusive = bound.inclusive;
5277
5282
  }
@@ -5286,11 +5291,11 @@ function targetGetAscendingBound(target, fieldPath, bound) {
5286
5291
  * the provided `fieldPath` (or the lower bound for a descending segment).
5287
5292
  */
5288
5293
  function targetGetDescendingBound(target, fieldPath, bound) {
5289
- let value = undefined;
5294
+ let value = MAX_VALUE;
5290
5295
  let inclusive = true;
5291
5296
  // Process all filters to find a value for the current field segment
5292
5297
  for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
5293
- let filterValue = undefined;
5298
+ let filterValue = MAX_VALUE;
5294
5299
  let filterInclusive = true;
5295
5300
  switch (fieldFilter.op) {
5296
5301
  case ">=" /* GREATER_THAN_OR_EQUAL */:
@@ -5313,7 +5318,7 @@ function targetGetDescendingBound(target, fieldPath, bound) {
5313
5318
  break;
5314
5319
  // Remaining filters cannot be used as upper bounds.
5315
5320
  }
5316
- if (valuesMin(value, filterValue) === filterValue) {
5321
+ if (upperBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) > 0) {
5317
5322
  value = filterValue;
5318
5323
  inclusive = filterInclusive;
5319
5324
  }
@@ -5325,7 +5330,7 @@ function targetGetDescendingBound(target, fieldPath, bound) {
5325
5330
  const orderBy = target.orderBy[i];
5326
5331
  if (orderBy.field.isEqual(fieldPath)) {
5327
5332
  const cursorValue = bound.position[i];
5328
- if (valuesMin(value, cursorValue) === cursorValue) {
5333
+ if (upperBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) > 0) {
5329
5334
  value = cursorValue;
5330
5335
  inclusive = bound.inclusive;
5331
5336
  }
@@ -5714,7 +5719,7 @@ function asCollectionQueryAtPath(query, path) {
5714
5719
  * Returns true if this query does not specify any query constraints that
5715
5720
  * could remove results.
5716
5721
  */
5717
- function matchesAllDocuments(query) {
5722
+ function queryMatchesAllDocuments(query) {
5718
5723
  return (query.filters.length === 0 &&
5719
5724
  query.limit === null &&
5720
5725
  query.startAt == null &&
@@ -5723,12 +5728,6 @@ function matchesAllDocuments(query) {
5723
5728
  (query.explicitOrderBy.length === 1 &&
5724
5729
  query.explicitOrderBy[0].field.isKeyField())));
5725
5730
  }
5726
- function hasLimitToFirst(query) {
5727
- return !isNullOrUndefined(query.limit) && query.limitType === "F" /* First */;
5728
- }
5729
- function hasLimitToLast(query) {
5730
- return !isNullOrUndefined(query.limit) && query.limitType === "L" /* Last */;
5731
- }
5732
5731
  function getFirstOrderByField(query) {
5733
5732
  return query.explicitOrderBy.length > 0
5734
5733
  ? query.explicitOrderBy[0].field
@@ -5838,10 +5837,10 @@ function queryToTarget(query) {
5838
5837
  }
5839
5838
  // We need to swap the cursors to match the now-flipped query ordering.
5840
5839
  const startAt = queryImpl.endAt
5841
- ? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
5840
+ ? new Bound(queryImpl.endAt.position, queryImpl.endAt.inclusive)
5842
5841
  : null;
5843
5842
  const endAt = queryImpl.startAt
5844
- ? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
5843
+ ? new Bound(queryImpl.startAt.position, queryImpl.startAt.inclusive)
5845
5844
  : null;
5846
5845
  // Now return as a LimitType.First query.
5847
5846
  queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
@@ -6112,8 +6111,12 @@ function mutableDocumentMap() {
6112
6111
  return EMPTY_MUTABLE_DOCUMENT_MAP;
6113
6112
  }
6114
6113
  const EMPTY_DOCUMENT_MAP = new SortedMap(DocumentKey.comparator);
6115
- function documentMap() {
6116
- return EMPTY_DOCUMENT_MAP;
6114
+ function documentMap(...docs) {
6115
+ let map = EMPTY_DOCUMENT_MAP;
6116
+ for (const doc of docs) {
6117
+ map = map.insert(doc.key, doc);
6118
+ }
6119
+ return map;
6117
6120
  }
6118
6121
  function newOverlayMap() {
6119
6122
  return new ObjectMap(key => key.toString(), (l, r) => l.isEqual(r));
@@ -10018,6 +10021,9 @@ class MemoryIndexManager {
10018
10021
  // Field indices are not supported with memory persistence.
10019
10022
  return PersistencePromise.resolve(null);
10020
10023
  }
10024
+ getMinOffset(transaction, target) {
10025
+ return PersistencePromise.resolve(IndexOffset.min());
10026
+ }
10021
10027
  updateCollectionGroup(transaction, collectionGroup, offset) {
10022
10028
  // Field indices are not supported with memory persistence.
10023
10029
  return PersistencePromise.resolve();
@@ -10193,7 +10199,7 @@ class IndexedDbIndexManager {
10193
10199
  const lowerBoundEncoded = this.encodeBound(index, subTarget, lowerBound);
10194
10200
  const upperBoundEncoded = this.encodeBound(index, subTarget, upperBound);
10195
10201
  const notInEncoded = this.encodeValues(index, subTarget, notInValues);
10196
- const indexRanges = this.generateIndexRanges(index.indexId, arrayValues, lowerBoundEncoded, !!lowerBound && lowerBound.inclusive, upperBoundEncoded, !!upperBound && upperBound.inclusive, notInEncoded);
10202
+ const indexRanges = this.generateIndexRanges(index.indexId, arrayValues, lowerBoundEncoded, lowerBound.inclusive, upperBoundEncoded, upperBound.inclusive, notInEncoded);
10197
10203
  return PersistencePromise.forEach(indexRanges, (indexRange) => {
10198
10204
  return indexEntries
10199
10205
  .loadFirst(indexRange, target.limit)
@@ -10231,22 +10237,18 @@ class IndexedDbIndexManager {
10231
10237
  // index range per value in an ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filter
10232
10238
  // combined with the values from the query bounds.
10233
10239
  const totalScans = (arrayValues != null ? arrayValues.length : 1) *
10234
- Math.max(lowerBounds != null ? lowerBounds.length : 1, upperBounds != null ? upperBounds.length : 1);
10240
+ Math.max(lowerBounds.length, upperBounds.length);
10235
10241
  const scansPerArrayElement = totalScans / (arrayValues != null ? arrayValues.length : 1);
10236
10242
  const indexRanges = [];
10237
10243
  for (let i = 0; i < totalScans; ++i) {
10238
10244
  const arrayValue = arrayValues
10239
10245
  ? this.encodeSingleElement(arrayValues[i / scansPerArrayElement])
10240
10246
  : EMPTY_VALUE;
10241
- const lowerBound = lowerBounds
10242
- ? this.generateLowerBound(indexId, arrayValue, lowerBounds[i % scansPerArrayElement], lowerBoundInclusive)
10243
- : this.generateEmptyBound(indexId);
10244
- const upperBound = upperBounds
10245
- ? this.generateUpperBound(indexId, arrayValue, upperBounds[i % scansPerArrayElement], upperBoundInclusive)
10246
- : this.generateEmptyBound(indexId + 1);
10247
- indexRanges.push(...this.createRange(lowerBound, upperBound, notInValues.map((notIn // make non-nullable
10248
- ) => this.generateLowerBound(indexId, arrayValue, notIn,
10249
- /* inclusive= */ true))));
10247
+ const lowerBound = this.generateLowerBound(indexId, arrayValue, lowerBounds[i % scansPerArrayElement], lowerBoundInclusive);
10248
+ const upperBound = this.generateUpperBound(indexId, arrayValue, upperBounds[i % scansPerArrayElement], upperBoundInclusive);
10249
+ const notInBound = notInValues.map(notIn => this.generateLowerBound(indexId, arrayValue, notIn,
10250
+ /* inclusive= */ true));
10251
+ indexRanges.push(...this.createRange(lowerBound, upperBound, notInBound));
10250
10252
  }
10251
10253
  return indexRanges;
10252
10254
  }
@@ -10260,13 +10262,6 @@ class IndexedDbIndexManager {
10260
10262
  const entry = new IndexEntry(indexId, DocumentKey.empty(), arrayValue, directionalValue);
10261
10263
  return inclusive ? entry.successor() : entry;
10262
10264
  }
10263
- /**
10264
- * Generates an empty bound that scopes the index scan to the current index
10265
- * and user.
10266
- */
10267
- generateEmptyBound(indexId) {
10268
- return new IndexEntry(indexId, DocumentKey.empty(), EMPTY_VALUE, EMPTY_VALUE);
10269
- }
10270
10265
  getFieldIndex(transaction, target) {
10271
10266
  const targetIndexMatcher = new TargetIndexMatcher(target);
10272
10267
  const collectionGroup = target.collectionGroup != null
@@ -10286,15 +10281,18 @@ class IndexedDbIndexManager {
10286
10281
  });
10287
10282
  }
10288
10283
  getIndexType(transaction, target) {
10289
- // TODO(orqueries): We should look at the subtargets here
10290
- return this.getFieldIndex(transaction, target).next(index => {
10291
- if (!index) {
10292
- return 0 /* NONE */;
10293
- }
10294
- return index.fields.length < targetGetSegmentCount(target)
10295
- ? 1 /* PARTIAL */
10296
- : 2 /* FULL */;
10297
- });
10284
+ let indexType = 2 /* FULL */;
10285
+ return PersistencePromise.forEach(this.getSubTargets(target), (target) => {
10286
+ return this.getFieldIndex(transaction, target).next(index => {
10287
+ if (!index) {
10288
+ indexType = 0 /* NONE */;
10289
+ }
10290
+ else if (indexType !== 0 /* NONE */ &&
10291
+ index.fields.length < targetGetSegmentCount(target)) {
10292
+ indexType = 1 /* PARTIAL */;
10293
+ }
10294
+ });
10295
+ }).next(() => indexType);
10298
10296
  }
10299
10297
  /**
10300
10298
  * Returns the byte encoded form of the directional values in the field index.
@@ -10358,9 +10356,6 @@ class IndexedDbIndexManager {
10358
10356
  * queries, a list of possible values is returned.
10359
10357
  */
10360
10358
  encodeBound(fieldIndex, target, bound) {
10361
- if (bound == null) {
10362
- return null;
10363
- }
10364
10359
  return this.encodeValues(fieldIndex, target, bound.position);
10365
10360
  }
10366
10361
  /** Returns the byte representation for the provided encoders. */
@@ -10555,7 +10550,7 @@ class IndexedDbIndexManager {
10555
10550
  * '[foo > 2 && foo != 3]` becomes `[foo > 2 && < 3, foo > 3]`.
10556
10551
  */
10557
10552
  createRange(lower, upper, notInValues) {
10558
- // The notIb values need to be sorted and unique so that we can return a
10553
+ // The notIn values need to be sorted and unique so that we can return a
10559
10554
  // sorted set of non-overlapping ranges.
10560
10555
  notInValues = notInValues
10561
10556
  .sort((l, r) => indexEntryComparator(l, r))
@@ -10601,6 +10596,20 @@ class IndexedDbIndexManager {
10601
10596
  }
10602
10597
  return ranges;
10603
10598
  }
10599
+ getMinOffset(transaction, target) {
10600
+ let offset;
10601
+ return PersistencePromise.forEach(this.getSubTargets(target), (target) => {
10602
+ return this.getFieldIndex(transaction, target).next(index => {
10603
+ if (!index) {
10604
+ offset = IndexOffset.min();
10605
+ }
10606
+ else if (!offset ||
10607
+ indexOffsetComparator(index.indexState.offset, offset) < 0) {
10608
+ offset = index.indexState.offset;
10609
+ }
10610
+ });
10611
+ }).next(() => offset);
10612
+ }
10604
10613
  }
10605
10614
  /**
10606
10615
  * Helper to get a typed SimpleDbStore for the collectionParents
@@ -13771,7 +13780,7 @@ class LocalStoreImpl {
13771
13780
  this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
13772
13781
  this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
13773
13782
  this.remoteDocuments.setIndexManager(this.indexManager);
13774
- this.queryEngine.setLocalDocumentsView(this.localDocuments);
13783
+ this.queryEngine.initialize(this.localDocuments, this.indexManager);
13775
13784
  }
13776
13785
  collectGarbage(garbageCollector) {
13777
13786
  return this.persistence.runTransaction('Collect garbage', 'readwrite-primary', txn => garbageCollector.collect(txn, this.targetDataByTarget));
@@ -15513,10 +15522,30 @@ class MemoryEagerDelegate {
15513
15522
  * limitations under the License.
15514
15523
  */
15515
15524
  /**
15516
- * A query engine that takes advantage of the target document mapping in the
15517
- * QueryCache. Query execution is optimized by only reading the documents that
15518
- * previously matched a query plus any documents that were edited after the
15519
- * query was last listened to.
15525
+ * The Firestore query engine.
15526
+ *
15527
+ * Firestore queries can be executed in three modes. The Query Engine determines
15528
+ * what mode to use based on what data is persisted. The mode only determines
15529
+ * the runtime complexity of the query - the result set is equivalent across all
15530
+ * implementations.
15531
+ *
15532
+ * The Query engine will use indexed-based execution if a user has configured
15533
+ * any index that can be used to execute query (via `setIndexConfiguration()`).
15534
+ * Otherwise, the engine will try to optimize the query by re-using a previously
15535
+ * persisted query result. If that is not possible, the query will be executed
15536
+ * via a full collection scan.
15537
+ *
15538
+ * Index-based execution is the default when available. The query engine
15539
+ * supports partial indexed execution and merges the result from the index
15540
+ * lookup with documents that have not yet been indexed. The index evaluation
15541
+ * matches the backend's format and as such, the SDK can use indexing for all
15542
+ * queries that the backend supports.
15543
+ *
15544
+ * If no index exists, the query engine tries to take advantage of the target
15545
+ * document mapping in the TargetCache. These mappings exists for all queries
15546
+ * that have been synced with the backend at least once and allow the query
15547
+ * engine to only read documents that previously matched a query plus any
15548
+ * documents that were edited after the query was last listened to.
15520
15549
  *
15521
15550
  * There are some cases when this optimization is not guaranteed to produce
15522
15551
  * the same results as full collection scans. In these cases, query
@@ -15531,16 +15560,41 @@ class MemoryEagerDelegate {
15531
15560
  * - Queries that have never been CURRENT or free of limbo documents.
15532
15561
  */
15533
15562
  class QueryEngine {
15563
+ constructor() {
15564
+ this.initialized = false;
15565
+ }
15534
15566
  /** Sets the document view to query against. */
15535
- setLocalDocumentsView(localDocuments) {
15567
+ initialize(localDocuments, indexManager) {
15536
15568
  this.localDocumentsView = localDocuments;
15569
+ this.indexManager = indexManager;
15570
+ this.initialized = true;
15537
15571
  }
15538
15572
  /** Returns all local documents matching the specified query. */
15539
15573
  getDocumentsMatchingQuery(transaction, query, lastLimboFreeSnapshotVersion, remoteKeys) {
15540
- // Queries that match all documents don't benefit from using
15541
- // key-based lookups. It is more efficient to scan all documents in a
15542
- // collection, rather than to perform individual lookups.
15543
- if (matchesAllDocuments(query)) {
15574
+ return this.performQueryUsingIndex(transaction, query)
15575
+ .next(result => result
15576
+ ? result
15577
+ : this.performQueryUsingRemoteKeys(transaction, query, remoteKeys, lastLimboFreeSnapshotVersion))
15578
+ .next(result => result ? result : this.executeFullCollectionScan(transaction, query));
15579
+ }
15580
+ /**
15581
+ * Performs an indexed query that evaluates the query based on a collection's
15582
+ * persisted index values. Returns `null` if an index is not available.
15583
+ */
15584
+ performQueryUsingIndex(transaction, query) {
15585
+ {
15586
+ return PersistencePromise.resolve(null);
15587
+ }
15588
+ }
15589
+ /**
15590
+ * Performs a query based on the target's persisted query mapping. Returns
15591
+ * `null` if the mapping is not available or cannot be used.
15592
+ */
15593
+ performQueryUsingRemoteKeys(transaction, query, remoteKeys, lastLimboFreeSnapshotVersion) {
15594
+ if (queryMatchesAllDocuments(query)) {
15595
+ // Queries that match all documents don't benefit from using
15596
+ // key-based lookups. It is more efficient to scan all documents in a
15597
+ // collection, rather than to perform individual lookups.
15544
15598
  return this.executeFullCollectionScan(transaction, query);
15545
15599
  }
15546
15600
  // Queries that have never seen a snapshot without limbo free documents
@@ -15550,8 +15604,7 @@ class QueryEngine {
15550
15604
  }
15551
15605
  return this.localDocumentsView.getDocuments(transaction, remoteKeys).next(documents => {
15552
15606
  const previousResults = this.applyQuery(query, documents);
15553
- if ((hasLimitToFirst(query) || hasLimitToLast(query)) &&
15554
- this.needsRefill(query.limitType, previousResults, remoteKeys, lastLimboFreeSnapshotVersion)) {
15607
+ if (this.needsRefill(query, previousResults, remoteKeys, lastLimboFreeSnapshotVersion)) {
15555
15608
  return this.executeFullCollectionScan(transaction, query);
15556
15609
  }
15557
15610
  if (getLogLevel() <= LogLevel.DEBUG) {
@@ -15559,15 +15612,7 @@ class QueryEngine {
15559
15612
  }
15560
15613
  // Retrieve all results for documents that were updated since the last
15561
15614
  // limbo-document free remote snapshot.
15562
- return this.localDocumentsView.getDocumentsMatchingQuery(transaction, query, newIndexOffsetSuccessorFromReadTime(lastLimboFreeSnapshotVersion, INITIAL_LARGEST_BATCH_ID)).next(updatedResults => {
15563
- // We merge `previousResults` into `updateResults`, since
15564
- // `updateResults` is already a DocumentMap. If a document is
15565
- // contained in both lists, then its contents are the same.
15566
- previousResults.forEach(doc => {
15567
- updatedResults = updatedResults.insert(doc.key, doc);
15568
- });
15569
- return updatedResults;
15570
- });
15615
+ return this.appendRemainingResults(transaction, previousResults, query, newIndexOffsetSuccessorFromReadTime(lastLimboFreeSnapshotVersion, INITIAL_LARGEST_BATCH_ID));
15571
15616
  });
15572
15617
  }
15573
15618
  /** Applies the query filter and sorting to the provided documents. */
@@ -15586,6 +15631,7 @@ class QueryEngine {
15586
15631
  * Determines if a limit query needs to be refilled from cache, making it
15587
15632
  * ineligible for index-free execution.
15588
15633
  *
15634
+ * @param query The query.
15589
15635
  * @param sortedPreviousResults - The documents that matched the query when it
15590
15636
  * was last synchronized, sorted by the query's comparator.
15591
15637
  * @param remoteKeys - The document keys that matched the query at the last
@@ -15593,10 +15639,14 @@ class QueryEngine {
15593
15639
  * @param limboFreeSnapshotVersion - The version of the snapshot when the
15594
15640
  * query was last synchronized.
15595
15641
  */
15596
- needsRefill(limitType, sortedPreviousResults, remoteKeys, limboFreeSnapshotVersion) {
15597
- // The query needs to be refilled if a previously matching document no
15598
- // longer matches.
15642
+ needsRefill(query, sortedPreviousResults, remoteKeys, limboFreeSnapshotVersion) {
15643
+ if (query.limit === null) {
15644
+ // Queries without limits do not need to be refilled.
15645
+ return false;
15646
+ }
15599
15647
  if (remoteKeys.size !== sortedPreviousResults.size) {
15648
+ // The query needs to be refilled if a previously matching document no
15649
+ // longer matches.
15600
15650
  return true;
15601
15651
  }
15602
15652
  // Limit queries are not eligible for index-free query execution if there is
@@ -15607,7 +15657,7 @@ class QueryEngine {
15607
15657
  // the boundary of the limit itself did not change and documents from cache
15608
15658
  // will continue to be "rejected" by this boundary. Therefore, we can ignore
15609
15659
  // any modifications that don't affect the last document.
15610
- const docAtLimitEdge = limitType === "F" /* First */
15660
+ const docAtLimitEdge = query.limitType === "F" /* First */
15611
15661
  ? sortedPreviousResults.last()
15612
15662
  : sortedPreviousResults.first();
15613
15663
  if (!docAtLimitEdge) {
@@ -15623,6 +15673,22 @@ class QueryEngine {
15623
15673
  }
15624
15674
  return this.localDocumentsView.getDocumentsMatchingQuery(transaction, query, IndexOffset.min());
15625
15675
  }
15676
+ /**
15677
+ * Combines the results from an indexed execution with the remaining documents
15678
+ * that have not yet been indexed.
15679
+ */
15680
+ appendRemainingResults(transaction, indexedResults, query, offset) {
15681
+ // Retrieve all results for documents that were updated since the offset.
15682
+ return this.localDocumentsView
15683
+ .getDocumentsMatchingQuery(transaction, query, offset)
15684
+ .next(remainingResults => {
15685
+ // Merge with existing results
15686
+ indexedResults.forEach(d => {
15687
+ remainingResults = remainingResults.insert(d.key, d);
15688
+ });
15689
+ return remainingResults;
15690
+ });
15691
+ }
15626
15692
  }
15627
15693
 
15628
15694
  /**
@@ -21882,10 +21948,12 @@ class View {
21882
21948
  //
21883
21949
  // Note that this should never get used in a refill (when previousChanges is
21884
21950
  // set), because there will only be adds -- no deletes or updates.
21885
- const lastDocInLimit = hasLimitToFirst(this.query) && oldDocumentSet.size === this.query.limit
21951
+ const lastDocInLimit = this.query.limitType === "F" /* First */ &&
21952
+ oldDocumentSet.size === this.query.limit
21886
21953
  ? oldDocumentSet.last()
21887
21954
  : null;
21888
- const firstDocInLimit = hasLimitToLast(this.query) && oldDocumentSet.size === this.query.limit
21955
+ const firstDocInLimit = this.query.limitType === "L" /* Last */ &&
21956
+ oldDocumentSet.size === this.query.limit
21889
21957
  ? oldDocumentSet.first()
21890
21958
  : null;
21891
21959
  docChanges.inorderTraversal((key, entry) => {
@@ -21958,9 +22026,9 @@ class View {
21958
22026
  }
21959
22027
  });
21960
22028
  // Drop documents out to meet limit/limitToLast requirement.
21961
- if (hasLimitToFirst(this.query) || hasLimitToLast(this.query)) {
22029
+ if (this.query.limit !== null) {
21962
22030
  while (newDocumentSet.size > this.query.limit) {
21963
- const oldDoc = hasLimitToFirst(this.query)
22031
+ const oldDoc = this.query.limitType === "F" /* First */
21964
22032
  ? newDocumentSet.last()
21965
22033
  : newDocumentSet.first();
21966
22034
  newDocumentSet = newDocumentSet.delete(oldDoc.key);
@@ -23961,18 +24029,18 @@ class Transaction$2 {
23961
24029
  * See the License for the specific language governing permissions and
23962
24030
  * limitations under the License.
23963
24031
  */
23964
- const DEFAULT_MAX_ATTEMPTS_COUNT = 5;
23965
24032
  /**
23966
24033
  * TransactionRunner encapsulates the logic needed to run and retry transactions
23967
24034
  * with backoff.
23968
24035
  */
23969
24036
  class TransactionRunner {
23970
- constructor(asyncQueue, datastore, updateFunction, deferred) {
24037
+ constructor(asyncQueue, datastore, options, updateFunction, deferred) {
23971
24038
  this.asyncQueue = asyncQueue;
23972
24039
  this.datastore = datastore;
24040
+ this.options = options;
23973
24041
  this.updateFunction = updateFunction;
23974
24042
  this.deferred = deferred;
23975
- this.attemptsRemaining = DEFAULT_MAX_ATTEMPTS_COUNT;
24043
+ this.attemptsRemaining = options.maxAttempts;
23976
24044
  this.backoff = new ExponentialBackoff(this.asyncQueue, "transaction_retry" /* TransactionRetry */);
23977
24045
  }
23978
24046
  /** Runs the transaction and sets the result on deferred. */
@@ -24330,11 +24398,11 @@ function firestoreClientAddSnapshotsInSyncListener(client, observer) {
24330
24398
  * been committed. For this reason, it is required that all reads are
24331
24399
  * performed before any writes. Transactions must be performed while online.
24332
24400
  */
24333
- function firestoreClientTransaction(client, updateFunction) {
24401
+ function firestoreClientTransaction(client, updateFunction, options) {
24334
24402
  const deferred = new Deferred();
24335
24403
  client.asyncQueue.enqueueAndForget(async () => {
24336
24404
  const datastore = await getDatastore(client);
24337
- new TransactionRunner(client.asyncQueue, datastore, updateFunction, deferred).run();
24405
+ new TransactionRunner(client.asyncQueue, datastore, options, updateFunction, deferred).run();
24338
24406
  });
24339
24407
  return deferred.promise;
24340
24408
  }
@@ -27091,7 +27159,8 @@ function snapshotEqual(left, right) {
27091
27159
  * limitations under the License.
27092
27160
  */
27093
27161
  function validateHasExplicitOrderByForLimitToLast(query) {
27094
- if (hasLimitToLast(query) && query.explicitOrderBy.length === 0) {
27162
+ if (query.limitType === "L" /* Last */ &&
27163
+ query.explicitOrderBy.length === 0) {
27095
27164
  throw new FirestoreError(Code.UNIMPLEMENTED, 'limitToLast() queries require specifying at least one orderBy() clause');
27096
27165
  }
27097
27166
  }
@@ -27533,6 +27602,31 @@ function validateOrderByAndInequalityMatch(baseQuery, inequality, orderBy) {
27533
27602
  }
27534
27603
  }
27535
27604
 
27605
+ /**
27606
+ * @license
27607
+ * Copyright 2022 Google LLC
27608
+ *
27609
+ * Licensed under the Apache License, Version 2.0 (the "License");
27610
+ * you may not use this file except in compliance with the License.
27611
+ * You may obtain a copy of the License at
27612
+ *
27613
+ * http://www.apache.org/licenses/LICENSE-2.0
27614
+ *
27615
+ * Unless required by applicable law or agreed to in writing, software
27616
+ * distributed under the License is distributed on an "AS IS" BASIS,
27617
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27618
+ * See the License for the specific language governing permissions and
27619
+ * limitations under the License.
27620
+ */
27621
+ const DEFAULT_TRANSACTION_OPTIONS = {
27622
+ maxAttempts: 5
27623
+ };
27624
+ function validateTransactionOptions(options) {
27625
+ if (options.maxAttempts < 1) {
27626
+ throw new FirestoreError(Code.INVALID_ARGUMENT, 'Max attempts must be at least 1');
27627
+ }
27628
+ }
27629
+
27536
27630
  /**
27537
27631
  * @license
27538
27632
  * Copyright 2020 Google LLC
@@ -28254,10 +28348,12 @@ class Transaction extends Transaction$1 {
28254
28348
  * `updateFunction `is returned here. Otherwise, if the transaction failed, a
28255
28349
  * rejected promise with the corresponding failure error is returned.
28256
28350
  */
28257
- function runTransaction(firestore, updateFunction) {
28351
+ function runTransaction(firestore, updateFunction, options) {
28258
28352
  firestore = cast(firestore, Firestore);
28353
+ const optionsWithDefaults = Object.assign(Object.assign({}, DEFAULT_TRANSACTION_OPTIONS), options);
28354
+ validateTransactionOptions(optionsWithDefaults);
28259
28355
  const client = ensureFirestoreConfigured(firestore);
28260
- return firestoreClientTransaction(client, internalTransaction => updateFunction(new Transaction(firestore, internalTransaction)));
28356
+ return firestoreClientTransaction(client, internalTransaction => updateFunction(new Transaction(firestore, internalTransaction)), optionsWithDefaults);
28261
28357
  }
28262
28358
 
28263
28359
  /**