@firebase/firestore 3.7.3 → 3.8.0
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.
- package/CHANGELOG.md +18 -0
- package/dist/firestore/lite/index.d.ts +1 -1
- package/dist/firestore/src/api/filter.d.ts +1 -1
- package/dist/firestore/src/api.d.ts +1 -1
- package/dist/firestore/src/core/bound.d.ts +49 -0
- package/dist/firestore/src/core/filter.d.ts +134 -0
- package/dist/firestore/src/core/order_by.d.ts +35 -0
- package/dist/firestore/src/core/query.d.ts +5 -6
- package/dist/firestore/src/core/target.d.ts +4 -120
- package/dist/firestore/src/lite-api/query.d.ts +273 -66
- package/dist/firestore/src/local/indexeddb_index_manager.d.ts +2 -0
- package/dist/firestore/src/local/local_documents_view.d.ts +0 -2
- package/dist/firestore/src/model/document.d.ts +8 -1
- package/dist/firestore/src/protos/firestore_proto_api.d.ts +1 -1
- package/dist/firestore/src/remote/serializer.d.ts +10 -3
- package/dist/firestore/src/util/logic_utils.d.ts +52 -0
- package/dist/firestore/src/util/types.d.ts +1 -1
- package/dist/firestore/test/lite/helpers.d.ts +1 -1
- package/dist/firestore/test/unit/core/filter.test.d.ts +17 -0
- package/dist/firestore/test/unit/specs/spec_test_runner.d.ts +2 -1
- package/dist/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/firestore/test/util/helpers.d.ts +6 -2
- package/dist/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/index.d.ts +138 -62
- package/dist/index.esm2017.js +4295 -3742
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +4981 -4410
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +1657 -889
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/index.node.mjs +1650 -890
- package/dist/index.node.mjs.map +1 -1
- package/dist/index.rn.js +4520 -3967
- package/dist/index.rn.js.map +1 -1
- package/dist/internal.d.ts +328 -68
- package/dist/lite/firestore/lite/index.d.ts +1 -1
- package/dist/lite/firestore/src/api/filter.d.ts +1 -1
- package/dist/lite/firestore/src/api.d.ts +1 -1
- package/dist/lite/firestore/src/core/bound.d.ts +49 -0
- package/dist/lite/firestore/src/core/filter.d.ts +134 -0
- package/dist/lite/firestore/src/core/order_by.d.ts +35 -0
- package/dist/lite/firestore/src/core/query.d.ts +5 -6
- package/dist/lite/firestore/src/core/target.d.ts +4 -120
- package/dist/lite/firestore/src/lite-api/query.d.ts +273 -66
- package/dist/lite/firestore/src/local/indexeddb_index_manager.d.ts +2 -0
- package/dist/lite/firestore/src/local/local_documents_view.d.ts +0 -2
- package/dist/lite/firestore/src/model/document.d.ts +8 -1
- package/dist/lite/firestore/src/protos/firestore_proto_api.d.ts +1 -1
- package/dist/lite/firestore/src/remote/serializer.d.ts +10 -3
- package/dist/lite/firestore/src/util/logic_utils.d.ts +52 -0
- package/dist/lite/firestore/src/util/types.d.ts +1 -1
- package/dist/lite/firestore/test/lite/helpers.d.ts +1 -1
- package/dist/lite/firestore/test/unit/core/filter.test.d.ts +17 -0
- package/dist/lite/firestore/test/unit/specs/spec_test_runner.d.ts +2 -1
- package/dist/lite/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/lite/firestore/test/util/helpers.d.ts +6 -2
- package/dist/lite/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/lite/index.browser.esm2017.js +2091 -1793
- package/dist/lite/index.browser.esm2017.js.map +1 -1
- package/dist/lite/index.browser.esm5.js +2239 -2000
- package/dist/lite/index.browser.esm5.js.map +1 -1
- package/dist/lite/index.d.ts +138 -62
- package/dist/lite/index.node.cjs.js +2212 -1802
- package/dist/lite/index.node.cjs.js.map +1 -1
- package/dist/lite/index.node.mjs +2205 -1803
- package/dist/lite/index.node.mjs.map +1 -1
- package/dist/lite/index.rn.esm2017.js +2077 -1778
- package/dist/lite/index.rn.esm2017.js.map +1 -1
- package/dist/lite/internal.d.ts +328 -66
- package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +322 -174
- package/dist/lite/packages/firestore/lite/index.d.ts +1 -1
- package/dist/lite/packages/firestore/rollup.config.debug.d.ts +1 -1
- package/dist/lite/packages/firestore/src/api/filter.d.ts +1 -1
- package/dist/lite/packages/firestore/src/api.d.ts +1 -1
- package/dist/lite/packages/firestore/src/core/bound.d.ts +49 -0
- package/dist/lite/packages/firestore/src/core/filter.d.ts +134 -0
- package/dist/lite/packages/firestore/src/core/order_by.d.ts +35 -0
- package/dist/lite/packages/firestore/src/core/query.d.ts +5 -6
- package/dist/lite/packages/firestore/src/core/target.d.ts +4 -120
- package/dist/lite/packages/firestore/src/lite-api/query.d.ts +273 -66
- package/dist/lite/packages/firestore/src/local/indexeddb_index_manager.d.ts +2 -0
- package/dist/lite/packages/firestore/src/local/local_documents_view.d.ts +0 -2
- package/dist/lite/packages/firestore/src/model/document.d.ts +8 -1
- package/dist/lite/packages/firestore/src/protos/firestore_proto_api.d.ts +1 -1
- package/dist/lite/packages/firestore/src/remote/serializer.d.ts +10 -3
- package/dist/lite/packages/firestore/src/util/logic_utils.d.ts +52 -0
- package/dist/lite/packages/firestore/src/util/types.d.ts +1 -1
- package/dist/lite/packages/firestore/test/lite/helpers.d.ts +1 -1
- package/dist/lite/packages/firestore/test/unit/core/filter.test.d.ts +17 -0
- package/dist/lite/packages/firestore/test/unit/specs/spec_test_runner.d.ts +2 -1
- package/dist/lite/packages/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/lite/packages/firestore/test/util/helpers.d.ts +6 -2
- package/dist/lite/packages/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/lite/private.d.ts +240 -66
- package/dist/packages/firestore/dist/index.esm2017.d.ts +368 -208
- package/dist/packages/firestore/lite/index.d.ts +1 -1
- package/dist/packages/firestore/rollup.config.debug.d.ts +1 -1
- package/dist/packages/firestore/src/api/filter.d.ts +1 -1
- package/dist/packages/firestore/src/api.d.ts +1 -1
- package/dist/packages/firestore/src/core/bound.d.ts +49 -0
- package/dist/packages/firestore/src/core/filter.d.ts +134 -0
- package/dist/packages/firestore/src/core/order_by.d.ts +35 -0
- package/dist/packages/firestore/src/core/query.d.ts +5 -6
- package/dist/packages/firestore/src/core/target.d.ts +4 -120
- package/dist/packages/firestore/src/lite-api/query.d.ts +273 -66
- package/dist/packages/firestore/src/local/indexeddb_index_manager.d.ts +2 -0
- package/dist/packages/firestore/src/local/local_documents_view.d.ts +0 -2
- package/dist/packages/firestore/src/model/document.d.ts +8 -1
- package/dist/packages/firestore/src/protos/firestore_proto_api.d.ts +1 -1
- package/dist/packages/firestore/src/remote/serializer.d.ts +10 -3
- package/dist/packages/firestore/src/util/logic_utils.d.ts +52 -0
- package/dist/packages/firestore/src/util/types.d.ts +1 -1
- package/dist/packages/firestore/test/lite/helpers.d.ts +1 -1
- package/dist/packages/firestore/test/unit/core/filter.test.d.ts +17 -0
- package/dist/packages/firestore/test/unit/specs/spec_test_runner.d.ts +2 -1
- package/dist/packages/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/packages/firestore/test/util/helpers.d.ts +6 -2
- package/dist/packages/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/private.d.ts +240 -68
- package/package.json +13 -11
package/dist/index.node.mjs
CHANGED
|
@@ -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.
|
|
11
|
+
const version$1 = "3.8.0";
|
|
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.
|
|
64
|
+
const version = "9.15.0";
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* @license
|
|
@@ -1499,11 +1499,11 @@ class FieldIndex {
|
|
|
1499
1499
|
FieldIndex.UNKNOWN_ID = -1;
|
|
1500
1500
|
/** Returns the ArrayContains/ArrayContainsAny segment for this index. */
|
|
1501
1501
|
function fieldIndexGetArraySegment(fieldIndex) {
|
|
1502
|
-
return fieldIndex.fields.find(s => s.kind === 2 /* CONTAINS */);
|
|
1502
|
+
return fieldIndex.fields.find(s => s.kind === 2 /* IndexKind.CONTAINS */);
|
|
1503
1503
|
}
|
|
1504
1504
|
/** Returns all directional (ascending/descending) segments for this index. */
|
|
1505
1505
|
function fieldIndexGetDirectionalSegments(fieldIndex) {
|
|
1506
|
-
return fieldIndex.fields.filter(s => s.kind !== 2 /* CONTAINS */);
|
|
1506
|
+
return fieldIndex.fields.filter(s => s.kind !== 2 /* IndexKind.CONTAINS */);
|
|
1507
1507
|
}
|
|
1508
1508
|
/**
|
|
1509
1509
|
* Returns the order of the document key component for the given index.
|
|
@@ -1513,7 +1513,7 @@ function fieldIndexGetDirectionalSegments(fieldIndex) {
|
|
|
1513
1513
|
function fieldIndexGetKeyOrder(fieldIndex) {
|
|
1514
1514
|
const directionalSegments = fieldIndexGetDirectionalSegments(fieldIndex);
|
|
1515
1515
|
return directionalSegments.length === 0
|
|
1516
|
-
? 0 /* ASCENDING */
|
|
1516
|
+
? 0 /* IndexKind.ASCENDING */
|
|
1517
1517
|
: directionalSegments[directionalSegments.length - 1].kind;
|
|
1518
1518
|
}
|
|
1519
1519
|
/**
|
|
@@ -2627,7 +2627,7 @@ class IndexBackfillerScheduler {
|
|
|
2627
2627
|
}
|
|
2628
2628
|
schedule(delay) {
|
|
2629
2629
|
logDebug(LOG_TAG$h, `Scheduled in ${delay}ms`);
|
|
2630
|
-
this.task = this.asyncQueue.enqueueAfterDelay("index_backfill" /* IndexBackfill */, delay, async () => {
|
|
2630
|
+
this.task = this.asyncQueue.enqueueAfterDelay("index_backfill" /* TimerId.IndexBackfill */, delay, async () => {
|
|
2631
2631
|
this.task = null;
|
|
2632
2632
|
try {
|
|
2633
2633
|
const documentsProcessed = await this.backfiller.backfill();
|
|
@@ -4423,40 +4423,40 @@ const MIN_VALUE = {
|
|
|
4423
4423
|
/** Extracts the backend's type order for the provided value. */
|
|
4424
4424
|
function typeOrder(value) {
|
|
4425
4425
|
if ('nullValue' in value) {
|
|
4426
|
-
return 0 /* NullValue */;
|
|
4426
|
+
return 0 /* TypeOrder.NullValue */;
|
|
4427
4427
|
}
|
|
4428
4428
|
else if ('booleanValue' in value) {
|
|
4429
|
-
return 1 /* BooleanValue */;
|
|
4429
|
+
return 1 /* TypeOrder.BooleanValue */;
|
|
4430
4430
|
}
|
|
4431
4431
|
else if ('integerValue' in value || 'doubleValue' in value) {
|
|
4432
|
-
return 2 /* NumberValue */;
|
|
4432
|
+
return 2 /* TypeOrder.NumberValue */;
|
|
4433
4433
|
}
|
|
4434
4434
|
else if ('timestampValue' in value) {
|
|
4435
|
-
return 3 /* TimestampValue */;
|
|
4435
|
+
return 3 /* TypeOrder.TimestampValue */;
|
|
4436
4436
|
}
|
|
4437
4437
|
else if ('stringValue' in value) {
|
|
4438
|
-
return 5 /* StringValue */;
|
|
4438
|
+
return 5 /* TypeOrder.StringValue */;
|
|
4439
4439
|
}
|
|
4440
4440
|
else if ('bytesValue' in value) {
|
|
4441
|
-
return 6 /* BlobValue */;
|
|
4441
|
+
return 6 /* TypeOrder.BlobValue */;
|
|
4442
4442
|
}
|
|
4443
4443
|
else if ('referenceValue' in value) {
|
|
4444
|
-
return 7 /* RefValue */;
|
|
4444
|
+
return 7 /* TypeOrder.RefValue */;
|
|
4445
4445
|
}
|
|
4446
4446
|
else if ('geoPointValue' in value) {
|
|
4447
|
-
return 8 /* GeoPointValue */;
|
|
4447
|
+
return 8 /* TypeOrder.GeoPointValue */;
|
|
4448
4448
|
}
|
|
4449
4449
|
else if ('arrayValue' in value) {
|
|
4450
|
-
return 9 /* ArrayValue */;
|
|
4450
|
+
return 9 /* TypeOrder.ArrayValue */;
|
|
4451
4451
|
}
|
|
4452
4452
|
else if ('mapValue' in value) {
|
|
4453
4453
|
if (isServerTimestamp(value)) {
|
|
4454
|
-
return 4 /* ServerTimestampValue */;
|
|
4454
|
+
return 4 /* TypeOrder.ServerTimestampValue */;
|
|
4455
4455
|
}
|
|
4456
4456
|
else if (isMaxValue(value)) {
|
|
4457
|
-
return 9007199254740991 /* MaxValue */;
|
|
4457
|
+
return 9007199254740991 /* TypeOrder.MaxValue */;
|
|
4458
4458
|
}
|
|
4459
|
-
return 10 /* ObjectValue */;
|
|
4459
|
+
return 10 /* TypeOrder.ObjectValue */;
|
|
4460
4460
|
}
|
|
4461
4461
|
else {
|
|
4462
4462
|
return fail();
|
|
@@ -4473,29 +4473,29 @@ function valueEquals(left, right) {
|
|
|
4473
4473
|
return false;
|
|
4474
4474
|
}
|
|
4475
4475
|
switch (leftType) {
|
|
4476
|
-
case 0 /* NullValue */:
|
|
4476
|
+
case 0 /* TypeOrder.NullValue */:
|
|
4477
4477
|
return true;
|
|
4478
|
-
case 1 /* BooleanValue */:
|
|
4478
|
+
case 1 /* TypeOrder.BooleanValue */:
|
|
4479
4479
|
return left.booleanValue === right.booleanValue;
|
|
4480
|
-
case 4 /* ServerTimestampValue */:
|
|
4480
|
+
case 4 /* TypeOrder.ServerTimestampValue */:
|
|
4481
4481
|
return getLocalWriteTime(left).isEqual(getLocalWriteTime(right));
|
|
4482
|
-
case 3 /* TimestampValue */:
|
|
4482
|
+
case 3 /* TypeOrder.TimestampValue */:
|
|
4483
4483
|
return timestampEquals(left, right);
|
|
4484
|
-
case 5 /* StringValue */:
|
|
4484
|
+
case 5 /* TypeOrder.StringValue */:
|
|
4485
4485
|
return left.stringValue === right.stringValue;
|
|
4486
|
-
case 6 /* BlobValue */:
|
|
4486
|
+
case 6 /* TypeOrder.BlobValue */:
|
|
4487
4487
|
return blobEquals(left, right);
|
|
4488
|
-
case 7 /* RefValue */:
|
|
4488
|
+
case 7 /* TypeOrder.RefValue */:
|
|
4489
4489
|
return left.referenceValue === right.referenceValue;
|
|
4490
|
-
case 8 /* GeoPointValue */:
|
|
4490
|
+
case 8 /* TypeOrder.GeoPointValue */:
|
|
4491
4491
|
return geoPointEquals(left, right);
|
|
4492
|
-
case 2 /* NumberValue */:
|
|
4492
|
+
case 2 /* TypeOrder.NumberValue */:
|
|
4493
4493
|
return numberEquals(left, right);
|
|
4494
|
-
case 9 /* ArrayValue */:
|
|
4494
|
+
case 9 /* TypeOrder.ArrayValue */:
|
|
4495
4495
|
return arrayEquals(left.arrayValue.values || [], right.arrayValue.values || [], valueEquals);
|
|
4496
|
-
case 10 /* ObjectValue */:
|
|
4496
|
+
case 10 /* TypeOrder.ObjectValue */:
|
|
4497
4497
|
return objectEquals(left, right);
|
|
4498
|
-
case 9007199254740991 /* MaxValue */:
|
|
4498
|
+
case 9007199254740991 /* TypeOrder.MaxValue */:
|
|
4499
4499
|
return true;
|
|
4500
4500
|
default:
|
|
4501
4501
|
return fail();
|
|
@@ -4568,28 +4568,28 @@ function valueCompare(left, right) {
|
|
|
4568
4568
|
return primitiveComparator(leftType, rightType);
|
|
4569
4569
|
}
|
|
4570
4570
|
switch (leftType) {
|
|
4571
|
-
case 0 /* NullValue */:
|
|
4572
|
-
case 9007199254740991 /* MaxValue */:
|
|
4571
|
+
case 0 /* TypeOrder.NullValue */:
|
|
4572
|
+
case 9007199254740991 /* TypeOrder.MaxValue */:
|
|
4573
4573
|
return 0;
|
|
4574
|
-
case 1 /* BooleanValue */:
|
|
4574
|
+
case 1 /* TypeOrder.BooleanValue */:
|
|
4575
4575
|
return primitiveComparator(left.booleanValue, right.booleanValue);
|
|
4576
|
-
case 2 /* NumberValue */:
|
|
4576
|
+
case 2 /* TypeOrder.NumberValue */:
|
|
4577
4577
|
return compareNumbers(left, right);
|
|
4578
|
-
case 3 /* TimestampValue */:
|
|
4578
|
+
case 3 /* TypeOrder.TimestampValue */:
|
|
4579
4579
|
return compareTimestamps(left.timestampValue, right.timestampValue);
|
|
4580
|
-
case 4 /* ServerTimestampValue */:
|
|
4580
|
+
case 4 /* TypeOrder.ServerTimestampValue */:
|
|
4581
4581
|
return compareTimestamps(getLocalWriteTime(left), getLocalWriteTime(right));
|
|
4582
|
-
case 5 /* StringValue */:
|
|
4582
|
+
case 5 /* TypeOrder.StringValue */:
|
|
4583
4583
|
return primitiveComparator(left.stringValue, right.stringValue);
|
|
4584
|
-
case 6 /* BlobValue */:
|
|
4584
|
+
case 6 /* TypeOrder.BlobValue */:
|
|
4585
4585
|
return compareBlobs(left.bytesValue, right.bytesValue);
|
|
4586
|
-
case 7 /* RefValue */:
|
|
4586
|
+
case 7 /* TypeOrder.RefValue */:
|
|
4587
4587
|
return compareReferences(left.referenceValue, right.referenceValue);
|
|
4588
|
-
case 8 /* GeoPointValue */:
|
|
4588
|
+
case 8 /* TypeOrder.GeoPointValue */:
|
|
4589
4589
|
return compareGeoPoints(left.geoPointValue, right.geoPointValue);
|
|
4590
|
-
case 9 /* ArrayValue */:
|
|
4590
|
+
case 9 /* TypeOrder.ArrayValue */:
|
|
4591
4591
|
return compareArrays(left.arrayValue, right.arrayValue);
|
|
4592
|
-
case 10 /* ObjectValue */:
|
|
4592
|
+
case 10 /* TypeOrder.ObjectValue */:
|
|
4593
4593
|
return compareMaps(left.mapValue, right.mapValue);
|
|
4594
4594
|
default:
|
|
4595
4595
|
throw fail();
|
|
@@ -5142,11 +5142,12 @@ function extractFieldMask(value) {
|
|
|
5142
5142
|
* from all views.
|
|
5143
5143
|
*/
|
|
5144
5144
|
class MutableDocument {
|
|
5145
|
-
constructor(key, documentType, version, readTime, data, documentState) {
|
|
5145
|
+
constructor(key, documentType, version, readTime, createTime, data, documentState) {
|
|
5146
5146
|
this.key = key;
|
|
5147
5147
|
this.documentType = documentType;
|
|
5148
5148
|
this.version = version;
|
|
5149
5149
|
this.readTime = readTime;
|
|
5150
|
+
this.createTime = createTime;
|
|
5150
5151
|
this.data = data;
|
|
5151
5152
|
this.documentState = documentState;
|
|
5152
5153
|
}
|
|
@@ -5155,18 +5156,27 @@ class MutableDocument {
|
|
|
5155
5156
|
* base document for mutations.
|
|
5156
5157
|
*/
|
|
5157
5158
|
static newInvalidDocument(documentKey) {
|
|
5158
|
-
return new MutableDocument(documentKey, 0 /* INVALID */,
|
|
5159
|
+
return new MutableDocument(documentKey, 0 /* DocumentType.INVALID */,
|
|
5160
|
+
/* version */ SnapshotVersion.min(),
|
|
5161
|
+
/* readTime */ SnapshotVersion.min(),
|
|
5162
|
+
/* createTime */ SnapshotVersion.min(), ObjectValue.empty(), 0 /* DocumentState.SYNCED */);
|
|
5159
5163
|
}
|
|
5160
5164
|
/**
|
|
5161
5165
|
* Creates a new document that is known to exist with the given data at the
|
|
5162
5166
|
* given version.
|
|
5163
5167
|
*/
|
|
5164
|
-
static newFoundDocument(documentKey, version, value) {
|
|
5165
|
-
return new MutableDocument(documentKey, 1 /* FOUND_DOCUMENT */,
|
|
5168
|
+
static newFoundDocument(documentKey, version, createTime, value) {
|
|
5169
|
+
return new MutableDocument(documentKey, 1 /* DocumentType.FOUND_DOCUMENT */,
|
|
5170
|
+
/* version */ version,
|
|
5171
|
+
/* readTime */ SnapshotVersion.min(),
|
|
5172
|
+
/* createTime */ createTime, value, 0 /* DocumentState.SYNCED */);
|
|
5166
5173
|
}
|
|
5167
5174
|
/** Creates a new document that is known to not exist at the given version. */
|
|
5168
5175
|
static newNoDocument(documentKey, version) {
|
|
5169
|
-
return new MutableDocument(documentKey, 2 /* NO_DOCUMENT */,
|
|
5176
|
+
return new MutableDocument(documentKey, 2 /* DocumentType.NO_DOCUMENT */,
|
|
5177
|
+
/* version */ version,
|
|
5178
|
+
/* readTime */ SnapshotVersion.min(),
|
|
5179
|
+
/* createTime */ SnapshotVersion.min(), ObjectValue.empty(), 0 /* DocumentState.SYNCED */);
|
|
5170
5180
|
}
|
|
5171
5181
|
/**
|
|
5172
5182
|
* Creates a new document that is known to exist at the given version but
|
|
@@ -5174,17 +5184,30 @@ class MutableDocument {
|
|
|
5174
5184
|
* base document).
|
|
5175
5185
|
*/
|
|
5176
5186
|
static newUnknownDocument(documentKey, version) {
|
|
5177
|
-
return new MutableDocument(documentKey, 3 /* UNKNOWN_DOCUMENT */,
|
|
5187
|
+
return new MutableDocument(documentKey, 3 /* DocumentType.UNKNOWN_DOCUMENT */,
|
|
5188
|
+
/* version */ version,
|
|
5189
|
+
/* readTime */ SnapshotVersion.min(),
|
|
5190
|
+
/* createTime */ SnapshotVersion.min(), ObjectValue.empty(), 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */);
|
|
5178
5191
|
}
|
|
5179
5192
|
/**
|
|
5180
5193
|
* Changes the document type to indicate that it exists and that its version
|
|
5181
5194
|
* and data are known.
|
|
5182
5195
|
*/
|
|
5183
5196
|
convertToFoundDocument(version, value) {
|
|
5197
|
+
// If a document is switching state from being an invalid or deleted
|
|
5198
|
+
// document to a valid (FOUND_DOCUMENT) document, either due to receiving an
|
|
5199
|
+
// update from Watch or due to applying a local set mutation on top
|
|
5200
|
+
// of a deleted document, our best guess about its createTime would be the
|
|
5201
|
+
// version at which the document transitioned to a FOUND_DOCUMENT.
|
|
5202
|
+
if (this.createTime.isEqual(SnapshotVersion.min()) &&
|
|
5203
|
+
(this.documentType === 2 /* DocumentType.NO_DOCUMENT */ ||
|
|
5204
|
+
this.documentType === 0 /* DocumentType.INVALID */)) {
|
|
5205
|
+
this.createTime = version;
|
|
5206
|
+
}
|
|
5184
5207
|
this.version = version;
|
|
5185
|
-
this.documentType = 1 /* FOUND_DOCUMENT */;
|
|
5208
|
+
this.documentType = 1 /* DocumentType.FOUND_DOCUMENT */;
|
|
5186
5209
|
this.data = value;
|
|
5187
|
-
this.documentState = 0 /* SYNCED */;
|
|
5210
|
+
this.documentState = 0 /* DocumentState.SYNCED */;
|
|
5188
5211
|
return this;
|
|
5189
5212
|
}
|
|
5190
5213
|
/**
|
|
@@ -5193,9 +5216,9 @@ class MutableDocument {
|
|
|
5193
5216
|
*/
|
|
5194
5217
|
convertToNoDocument(version) {
|
|
5195
5218
|
this.version = version;
|
|
5196
|
-
this.documentType = 2 /* NO_DOCUMENT */;
|
|
5219
|
+
this.documentType = 2 /* DocumentType.NO_DOCUMENT */;
|
|
5197
5220
|
this.data = ObjectValue.empty();
|
|
5198
|
-
this.documentState = 0 /* SYNCED */;
|
|
5221
|
+
this.documentState = 0 /* DocumentState.SYNCED */;
|
|
5199
5222
|
return this;
|
|
5200
5223
|
}
|
|
5201
5224
|
/**
|
|
@@ -5205,17 +5228,17 @@ class MutableDocument {
|
|
|
5205
5228
|
*/
|
|
5206
5229
|
convertToUnknownDocument(version) {
|
|
5207
5230
|
this.version = version;
|
|
5208
|
-
this.documentType = 3 /* UNKNOWN_DOCUMENT */;
|
|
5231
|
+
this.documentType = 3 /* DocumentType.UNKNOWN_DOCUMENT */;
|
|
5209
5232
|
this.data = ObjectValue.empty();
|
|
5210
|
-
this.documentState = 2 /* HAS_COMMITTED_MUTATIONS */;
|
|
5233
|
+
this.documentState = 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */;
|
|
5211
5234
|
return this;
|
|
5212
5235
|
}
|
|
5213
5236
|
setHasCommittedMutations() {
|
|
5214
|
-
this.documentState = 2 /* HAS_COMMITTED_MUTATIONS */;
|
|
5237
|
+
this.documentState = 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */;
|
|
5215
5238
|
return this;
|
|
5216
5239
|
}
|
|
5217
5240
|
setHasLocalMutations() {
|
|
5218
|
-
this.documentState = 1 /* HAS_LOCAL_MUTATIONS */;
|
|
5241
|
+
this.documentState = 1 /* DocumentState.HAS_LOCAL_MUTATIONS */;
|
|
5219
5242
|
this.version = SnapshotVersion.min();
|
|
5220
5243
|
return this;
|
|
5221
5244
|
}
|
|
@@ -5224,25 +5247,25 @@ class MutableDocument {
|
|
|
5224
5247
|
return this;
|
|
5225
5248
|
}
|
|
5226
5249
|
get hasLocalMutations() {
|
|
5227
|
-
return this.documentState === 1 /* HAS_LOCAL_MUTATIONS */;
|
|
5250
|
+
return this.documentState === 1 /* DocumentState.HAS_LOCAL_MUTATIONS */;
|
|
5228
5251
|
}
|
|
5229
5252
|
get hasCommittedMutations() {
|
|
5230
|
-
return this.documentState === 2 /* HAS_COMMITTED_MUTATIONS */;
|
|
5253
|
+
return this.documentState === 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */;
|
|
5231
5254
|
}
|
|
5232
5255
|
get hasPendingWrites() {
|
|
5233
5256
|
return this.hasLocalMutations || this.hasCommittedMutations;
|
|
5234
5257
|
}
|
|
5235
5258
|
isValidDocument() {
|
|
5236
|
-
return this.documentType !== 0 /* INVALID */;
|
|
5259
|
+
return this.documentType !== 0 /* DocumentType.INVALID */;
|
|
5237
5260
|
}
|
|
5238
5261
|
isFoundDocument() {
|
|
5239
|
-
return this.documentType === 1 /* FOUND_DOCUMENT */;
|
|
5262
|
+
return this.documentType === 1 /* DocumentType.FOUND_DOCUMENT */;
|
|
5240
5263
|
}
|
|
5241
5264
|
isNoDocument() {
|
|
5242
|
-
return this.documentType === 2 /* NO_DOCUMENT */;
|
|
5265
|
+
return this.documentType === 2 /* DocumentType.NO_DOCUMENT */;
|
|
5243
5266
|
}
|
|
5244
5267
|
isUnknownDocument() {
|
|
5245
|
-
return this.documentType === 3 /* UNKNOWN_DOCUMENT */;
|
|
5268
|
+
return this.documentType === 3 /* DocumentType.UNKNOWN_DOCUMENT */;
|
|
5246
5269
|
}
|
|
5247
5270
|
isEqual(other) {
|
|
5248
5271
|
return (other instanceof MutableDocument &&
|
|
@@ -5253,10 +5276,11 @@ class MutableDocument {
|
|
|
5253
5276
|
this.data.isEqual(other.data));
|
|
5254
5277
|
}
|
|
5255
5278
|
mutableCopy() {
|
|
5256
|
-
return new MutableDocument(this.key, this.documentType, this.version, this.readTime, this.data.clone(), this.documentState);
|
|
5279
|
+
return new MutableDocument(this.key, this.documentType, this.version, this.readTime, this.createTime, this.data.clone(), this.documentState);
|
|
5257
5280
|
}
|
|
5258
5281
|
toString() {
|
|
5259
5282
|
return (`Document(${this.key}, ${this.version}, ${JSON.stringify(this.data.value)}, ` +
|
|
5283
|
+
`{createTime: ${this.createTime}}), ` +
|
|
5260
5284
|
`{documentType: ${this.documentType}}), ` +
|
|
5261
5285
|
`{documentState: ${this.documentState}})`);
|
|
5262
5286
|
}
|
|
@@ -5278,7 +5302,7 @@ function compareDocumentsByField(field, d1, d2) {
|
|
|
5278
5302
|
|
|
5279
5303
|
/**
|
|
5280
5304
|
* @license
|
|
5281
|
-
* Copyright
|
|
5305
|
+
* Copyright 2022 Google LLC
|
|
5282
5306
|
*
|
|
5283
5307
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5284
5308
|
* you may not use this file except in compliance with the License.
|
|
@@ -5292,453 +5316,344 @@ function compareDocumentsByField(field, d1, d2) {
|
|
|
5292
5316
|
* See the License for the specific language governing permissions and
|
|
5293
5317
|
* limitations under the License.
|
|
5294
5318
|
*/
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5319
|
+
/**
|
|
5320
|
+
* Represents a bound of a query.
|
|
5321
|
+
*
|
|
5322
|
+
* The bound is specified with the given components representing a position and
|
|
5323
|
+
* whether it's just before or just after the position (relative to whatever the
|
|
5324
|
+
* query order is).
|
|
5325
|
+
*
|
|
5326
|
+
* The position represents a logical index position for a query. It's a prefix
|
|
5327
|
+
* of values for the (potentially implicit) order by clauses of a query.
|
|
5328
|
+
*
|
|
5329
|
+
* Bound provides a function to determine whether a document comes before or
|
|
5330
|
+
* after a bound. This is influenced by whether the position is just before or
|
|
5331
|
+
* just after the provided values.
|
|
5332
|
+
*/
|
|
5333
|
+
class Bound {
|
|
5334
|
+
constructor(position, inclusive) {
|
|
5335
|
+
this.position = position;
|
|
5336
|
+
this.inclusive = inclusive;
|
|
5306
5337
|
}
|
|
5307
5338
|
}
|
|
5339
|
+
function boundCompareToDocument(bound, orderBy, doc) {
|
|
5340
|
+
let comparison = 0;
|
|
5341
|
+
for (let i = 0; i < bound.position.length; i++) {
|
|
5342
|
+
const orderByComponent = orderBy[i];
|
|
5343
|
+
const component = bound.position[i];
|
|
5344
|
+
if (orderByComponent.field.isKeyField()) {
|
|
5345
|
+
comparison = DocumentKey.comparator(DocumentKey.fromName(component.referenceValue), doc.key);
|
|
5346
|
+
}
|
|
5347
|
+
else {
|
|
5348
|
+
const docValue = doc.data.field(orderByComponent.field);
|
|
5349
|
+
comparison = valueCompare(component, docValue);
|
|
5350
|
+
}
|
|
5351
|
+
if (orderByComponent.dir === "desc" /* Direction.DESCENDING */) {
|
|
5352
|
+
comparison = comparison * -1;
|
|
5353
|
+
}
|
|
5354
|
+
if (comparison !== 0) {
|
|
5355
|
+
break;
|
|
5356
|
+
}
|
|
5357
|
+
}
|
|
5358
|
+
return comparison;
|
|
5359
|
+
}
|
|
5308
5360
|
/**
|
|
5309
|
-
*
|
|
5310
|
-
*
|
|
5361
|
+
* Returns true if a document sorts after a bound using the provided sort
|
|
5362
|
+
* order.
|
|
5363
|
+
*/
|
|
5364
|
+
function boundSortsAfterDocument(bound, orderBy, doc) {
|
|
5365
|
+
const comparison = boundCompareToDocument(bound, orderBy, doc);
|
|
5366
|
+
return bound.inclusive ? comparison >= 0 : comparison > 0;
|
|
5367
|
+
}
|
|
5368
|
+
/**
|
|
5369
|
+
* Returns true if a document sorts before a bound using the provided sort
|
|
5370
|
+
* order.
|
|
5371
|
+
*/
|
|
5372
|
+
function boundSortsBeforeDocument(bound, orderBy, doc) {
|
|
5373
|
+
const comparison = boundCompareToDocument(bound, orderBy, doc);
|
|
5374
|
+
return bound.inclusive ? comparison <= 0 : comparison < 0;
|
|
5375
|
+
}
|
|
5376
|
+
function boundEquals(left, right) {
|
|
5377
|
+
if (left === null) {
|
|
5378
|
+
return right === null;
|
|
5379
|
+
}
|
|
5380
|
+
else if (right === null) {
|
|
5381
|
+
return false;
|
|
5382
|
+
}
|
|
5383
|
+
if (left.inclusive !== right.inclusive ||
|
|
5384
|
+
left.position.length !== right.position.length) {
|
|
5385
|
+
return false;
|
|
5386
|
+
}
|
|
5387
|
+
for (let i = 0; i < left.position.length; i++) {
|
|
5388
|
+
const leftPosition = left.position[i];
|
|
5389
|
+
const rightPosition = right.position[i];
|
|
5390
|
+
if (!valueEquals(leftPosition, rightPosition)) {
|
|
5391
|
+
return false;
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
return true;
|
|
5395
|
+
}
|
|
5396
|
+
|
|
5397
|
+
/**
|
|
5398
|
+
* @license
|
|
5399
|
+
* Copyright 2022 Google LLC
|
|
5311
5400
|
*
|
|
5312
|
-
*
|
|
5313
|
-
*
|
|
5314
|
-
*
|
|
5401
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5402
|
+
* you may not use this file except in compliance with the License.
|
|
5403
|
+
* You may obtain a copy of the License at
|
|
5404
|
+
*
|
|
5405
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5406
|
+
*
|
|
5407
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
5408
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
5409
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5410
|
+
* See the License for the specific language governing permissions and
|
|
5411
|
+
* limitations under the License.
|
|
5315
5412
|
*/
|
|
5316
|
-
|
|
5317
|
-
return new TargetImpl(path, collectionGroup, orderBy, filters, limit, startAt, endAt);
|
|
5413
|
+
class Filter {
|
|
5318
5414
|
}
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5415
|
+
class FieldFilter extends Filter {
|
|
5416
|
+
constructor(field, op, value) {
|
|
5417
|
+
super();
|
|
5418
|
+
this.field = field;
|
|
5419
|
+
this.op = op;
|
|
5420
|
+
this.value = value;
|
|
5421
|
+
}
|
|
5422
|
+
/**
|
|
5423
|
+
* Creates a filter based on the provided arguments.
|
|
5424
|
+
*/
|
|
5425
|
+
static create(field, op, value) {
|
|
5426
|
+
if (field.isKeyField()) {
|
|
5427
|
+
if (op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */) {
|
|
5428
|
+
return this.createKeyFieldInFilter(field, op, value);
|
|
5429
|
+
}
|
|
5430
|
+
else {
|
|
5431
|
+
return new KeyFieldFilter(field, op, value);
|
|
5432
|
+
}
|
|
5325
5433
|
}
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
str += '|ob:';
|
|
5329
|
-
str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
|
|
5330
|
-
if (!isNullOrUndefined(targetImpl.limit)) {
|
|
5331
|
-
str += '|l:';
|
|
5332
|
-
str += targetImpl.limit;
|
|
5434
|
+
else if (op === "array-contains" /* Operator.ARRAY_CONTAINS */) {
|
|
5435
|
+
return new ArrayContainsFilter(field, value);
|
|
5333
5436
|
}
|
|
5334
|
-
if (
|
|
5335
|
-
|
|
5336
|
-
str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
|
|
5337
|
-
str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5437
|
+
else if (op === "in" /* Operator.IN */) {
|
|
5438
|
+
return new InFilter(field, value);
|
|
5338
5439
|
}
|
|
5339
|
-
if (
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5440
|
+
else if (op === "not-in" /* Operator.NOT_IN */) {
|
|
5441
|
+
return new NotInFilter(field, value);
|
|
5442
|
+
}
|
|
5443
|
+
else if (op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
5444
|
+
return new ArrayContainsAnyFilter(field, value);
|
|
5445
|
+
}
|
|
5446
|
+
else {
|
|
5447
|
+
return new FieldFilter(field, op, value);
|
|
5343
5448
|
}
|
|
5344
|
-
targetImpl.memoizedCanonicalId = str;
|
|
5345
5449
|
}
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
if (target.collectionGroup !== null) {
|
|
5351
|
-
str += ' collectionGroup=' + target.collectionGroup;
|
|
5450
|
+
static createKeyFieldInFilter(field, op, value) {
|
|
5451
|
+
return op === "in" /* Operator.IN */
|
|
5452
|
+
? new KeyFieldInFilter(field, value)
|
|
5453
|
+
: new KeyFieldNotInFilter(field, value);
|
|
5352
5454
|
}
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5455
|
+
matches(doc) {
|
|
5456
|
+
const other = doc.data.field(this.field);
|
|
5457
|
+
// Types do not have to match in NOT_EQUAL filters.
|
|
5458
|
+
if (this.op === "!=" /* Operator.NOT_EQUAL */) {
|
|
5459
|
+
return (other !== null &&
|
|
5460
|
+
this.matchesComparison(valueCompare(other, this.value)));
|
|
5461
|
+
}
|
|
5462
|
+
// Only compare types with matching backend order (such as double and int).
|
|
5463
|
+
return (other !== null &&
|
|
5464
|
+
typeOrder(this.value) === typeOrder(other) &&
|
|
5465
|
+
this.matchesComparison(valueCompare(other, this.value)));
|
|
5357
5466
|
}
|
|
5358
|
-
|
|
5359
|
-
|
|
5467
|
+
matchesComparison(comparison) {
|
|
5468
|
+
switch (this.op) {
|
|
5469
|
+
case "<" /* Operator.LESS_THAN */:
|
|
5470
|
+
return comparison < 0;
|
|
5471
|
+
case "<=" /* Operator.LESS_THAN_OR_EQUAL */:
|
|
5472
|
+
return comparison <= 0;
|
|
5473
|
+
case "==" /* Operator.EQUAL */:
|
|
5474
|
+
return comparison === 0;
|
|
5475
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
5476
|
+
return comparison !== 0;
|
|
5477
|
+
case ">" /* Operator.GREATER_THAN */:
|
|
5478
|
+
return comparison > 0;
|
|
5479
|
+
case ">=" /* Operator.GREATER_THAN_OR_EQUAL */:
|
|
5480
|
+
return comparison >= 0;
|
|
5481
|
+
default:
|
|
5482
|
+
return fail();
|
|
5483
|
+
}
|
|
5360
5484
|
}
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
.
|
|
5364
|
-
.
|
|
5485
|
+
isInequality() {
|
|
5486
|
+
return ([
|
|
5487
|
+
"<" /* Operator.LESS_THAN */,
|
|
5488
|
+
"<=" /* Operator.LESS_THAN_OR_EQUAL */,
|
|
5489
|
+
">" /* Operator.GREATER_THAN */,
|
|
5490
|
+
">=" /* Operator.GREATER_THAN_OR_EQUAL */,
|
|
5491
|
+
"!=" /* Operator.NOT_EQUAL */,
|
|
5492
|
+
"not-in" /* Operator.NOT_IN */
|
|
5493
|
+
].indexOf(this.op) >= 0);
|
|
5365
5494
|
}
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
str += target.startAt.inclusive ? 'b:' : 'a:';
|
|
5369
|
-
str += target.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5495
|
+
getFlattenedFilters() {
|
|
5496
|
+
return [this];
|
|
5370
5497
|
}
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5498
|
+
getFilters() {
|
|
5499
|
+
return [this];
|
|
5500
|
+
}
|
|
5501
|
+
getFirstInequalityField() {
|
|
5502
|
+
if (this.isInequality()) {
|
|
5503
|
+
return this.field;
|
|
5504
|
+
}
|
|
5505
|
+
return null;
|
|
5375
5506
|
}
|
|
5376
|
-
return `Target(${str})`;
|
|
5377
5507
|
}
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5508
|
+
class CompositeFilter extends Filter {
|
|
5509
|
+
constructor(filters, op) {
|
|
5510
|
+
super();
|
|
5511
|
+
this.filters = filters;
|
|
5512
|
+
this.op = op;
|
|
5513
|
+
this.memoizedFlattenedFilters = null;
|
|
5381
5514
|
}
|
|
5382
|
-
|
|
5383
|
-
|
|
5515
|
+
/**
|
|
5516
|
+
* Creates a filter based on the provided arguments.
|
|
5517
|
+
*/
|
|
5518
|
+
static create(filters, op) {
|
|
5519
|
+
return new CompositeFilter(filters, op);
|
|
5384
5520
|
}
|
|
5385
|
-
|
|
5386
|
-
if (
|
|
5387
|
-
return false
|
|
5521
|
+
matches(doc) {
|
|
5522
|
+
if (compositeFilterIsConjunction(this)) {
|
|
5523
|
+
// For conjunctions, all filters must match, so return false if any filter doesn't match.
|
|
5524
|
+
return this.filters.find(filter => !filter.matches(doc)) === undefined;
|
|
5525
|
+
}
|
|
5526
|
+
else {
|
|
5527
|
+
// For disjunctions, at least one filter should match.
|
|
5528
|
+
return this.filters.find(filter => filter.matches(doc)) !== undefined;
|
|
5388
5529
|
}
|
|
5389
5530
|
}
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
for (let i = 0; i < left.filters.length; i++) {
|
|
5394
|
-
if (!filterEquals(left.filters[i], right.filters[i])) {
|
|
5395
|
-
return false;
|
|
5531
|
+
getFlattenedFilters() {
|
|
5532
|
+
if (this.memoizedFlattenedFilters !== null) {
|
|
5533
|
+
return this.memoizedFlattenedFilters;
|
|
5396
5534
|
}
|
|
5535
|
+
this.memoizedFlattenedFilters = this.filters.reduce((result, subfilter) => {
|
|
5536
|
+
return result.concat(subfilter.getFlattenedFilters());
|
|
5537
|
+
}, []);
|
|
5538
|
+
return this.memoizedFlattenedFilters;
|
|
5397
5539
|
}
|
|
5398
|
-
|
|
5399
|
-
|
|
5540
|
+
// Returns a mutable copy of `this.filters`
|
|
5541
|
+
getFilters() {
|
|
5542
|
+
return Object.assign([], this.filters);
|
|
5400
5543
|
}
|
|
5401
|
-
|
|
5402
|
-
|
|
5544
|
+
getFirstInequalityField() {
|
|
5545
|
+
const found = this.findFirstMatchingFilter(filter => filter.isInequality());
|
|
5546
|
+
if (found !== null) {
|
|
5547
|
+
return found.field;
|
|
5548
|
+
}
|
|
5549
|
+
return null;
|
|
5403
5550
|
}
|
|
5404
|
-
|
|
5405
|
-
|
|
5551
|
+
// Performs a depth-first search to find and return the first FieldFilter in the composite filter
|
|
5552
|
+
// that satisfies the predicate. Returns `null` if none of the FieldFilters satisfy the
|
|
5553
|
+
// predicate.
|
|
5554
|
+
findFirstMatchingFilter(predicate) {
|
|
5555
|
+
for (const fieldFilter of this.getFlattenedFilters()) {
|
|
5556
|
+
if (predicate(fieldFilter)) {
|
|
5557
|
+
return fieldFilter;
|
|
5558
|
+
}
|
|
5559
|
+
}
|
|
5560
|
+
return null;
|
|
5406
5561
|
}
|
|
5407
|
-
return boundEquals(left.endAt, right.endAt);
|
|
5408
5562
|
}
|
|
5409
|
-
function
|
|
5410
|
-
return
|
|
5411
|
-
target.collectionGroup === null &&
|
|
5412
|
-
target.filters.length === 0);
|
|
5563
|
+
function compositeFilterIsConjunction(compositeFilter) {
|
|
5564
|
+
return compositeFilter.op === "and" /* CompositeOperator.AND */;
|
|
5413
5565
|
}
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
return target.filters.filter(f => f instanceof FieldFilter && f.field.isEqual(path));
|
|
5566
|
+
function compositeFilterIsDisjunction(compositeFilter) {
|
|
5567
|
+
return compositeFilter.op === "or" /* CompositeOperator.OR */;
|
|
5417
5568
|
}
|
|
5418
5569
|
/**
|
|
5419
|
-
* Returns
|
|
5420
|
-
* filters. Returns `null` if there are no such filters.
|
|
5570
|
+
* Returns true if this filter is a conjunction of field filters only. Returns false otherwise.
|
|
5421
5571
|
*/
|
|
5422
|
-
function
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
return null;
|
|
5426
|
-
}
|
|
5427
|
-
for (const fieldFilter of targetGetFieldFiltersForPath(target, segment.fieldPath)) {
|
|
5428
|
-
switch (fieldFilter.op) {
|
|
5429
|
-
case "array-contains-any" /* ARRAY_CONTAINS_ANY */:
|
|
5430
|
-
return fieldFilter.value.arrayValue.values || [];
|
|
5431
|
-
case "array-contains" /* ARRAY_CONTAINS */:
|
|
5432
|
-
return [fieldFilter.value];
|
|
5433
|
-
// Remaining filters are not array filters.
|
|
5434
|
-
}
|
|
5435
|
-
}
|
|
5436
|
-
return null;
|
|
5572
|
+
function compositeFilterIsFlatConjunction(compositeFilter) {
|
|
5573
|
+
return (compositeFilterIsFlat(compositeFilter) &&
|
|
5574
|
+
compositeFilterIsConjunction(compositeFilter));
|
|
5437
5575
|
}
|
|
5438
5576
|
/**
|
|
5439
|
-
* Returns
|
|
5440
|
-
* `null` if there are no such filters.
|
|
5577
|
+
* Returns true if this filter does not contain any composite filters. Returns false otherwise.
|
|
5441
5578
|
*/
|
|
5442
|
-
function
|
|
5443
|
-
const
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
switch (fieldFilter.op) {
|
|
5447
|
-
case "==" /* EQUAL */:
|
|
5448
|
-
case "in" /* IN */:
|
|
5449
|
-
// Encode equality prefix, which is encoded in the index value before
|
|
5450
|
-
// the inequality (e.g. `a == 'a' && b != 'b'` is encoded to
|
|
5451
|
-
// `value != 'ab'`).
|
|
5452
|
-
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5453
|
-
break;
|
|
5454
|
-
case "not-in" /* NOT_IN */:
|
|
5455
|
-
case "!=" /* NOT_EQUAL */:
|
|
5456
|
-
// NotIn/NotEqual is always a suffix. There cannot be any remaining
|
|
5457
|
-
// segments and hence we can return early here.
|
|
5458
|
-
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5459
|
-
return Array.from(values.values());
|
|
5460
|
-
// Remaining filters cannot be used as notIn bounds.
|
|
5461
|
-
}
|
|
5579
|
+
function compositeFilterIsFlat(compositeFilter) {
|
|
5580
|
+
for (const filter of compositeFilter.filters) {
|
|
5581
|
+
if (filter instanceof CompositeFilter) {
|
|
5582
|
+
return false;
|
|
5462
5583
|
}
|
|
5463
5584
|
}
|
|
5464
|
-
return
|
|
5585
|
+
return true;
|
|
5465
5586
|
}
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
// For each segment, retrieve a lower bound if there is a suitable filter or
|
|
5475
|
-
// startAt.
|
|
5476
|
-
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5477
|
-
const segmentBound = segment.kind === 0 /* ASCENDING */
|
|
5478
|
-
? targetGetAscendingBound(target, segment.fieldPath, target.startAt)
|
|
5479
|
-
: targetGetDescendingBound(target, segment.fieldPath, target.startAt);
|
|
5480
|
-
values.push(segmentBound.value);
|
|
5481
|
-
inclusive && (inclusive = segmentBound.inclusive);
|
|
5587
|
+
function canonifyFilter(filter) {
|
|
5588
|
+
if (filter instanceof FieldFilter) {
|
|
5589
|
+
// TODO(b/29183165): Technically, this won't be unique if two values have
|
|
5590
|
+
// the same description, such as the int 3 and the string "3". So we should
|
|
5591
|
+
// add the types in here somehow, too.
|
|
5592
|
+
return (filter.field.canonicalString() +
|
|
5593
|
+
filter.op.toString() +
|
|
5594
|
+
canonicalId(filter.value));
|
|
5482
5595
|
}
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
*/
|
|
5490
|
-
function targetGetUpperBound(target, fieldIndex) {
|
|
5491
|
-
const values = [];
|
|
5492
|
-
let inclusive = true;
|
|
5493
|
-
// For each segment, retrieve an upper bound if there is a suitable filter or
|
|
5494
|
-
// endAt.
|
|
5495
|
-
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5496
|
-
const segmentBound = segment.kind === 0 /* ASCENDING */
|
|
5497
|
-
? targetGetDescendingBound(target, segment.fieldPath, target.endAt)
|
|
5498
|
-
: targetGetAscendingBound(target, segment.fieldPath, target.endAt);
|
|
5499
|
-
values.push(segmentBound.value);
|
|
5500
|
-
inclusive && (inclusive = segmentBound.inclusive);
|
|
5596
|
+
else {
|
|
5597
|
+
// filter instanceof CompositeFilter
|
|
5598
|
+
const canonicalIdsString = filter.filters
|
|
5599
|
+
.map(filter => canonifyFilter(filter))
|
|
5600
|
+
.join(',');
|
|
5601
|
+
return `${filter.op}(${canonicalIdsString})`;
|
|
5501
5602
|
}
|
|
5502
|
-
return new Bound(values, inclusive);
|
|
5503
5603
|
}
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
*/
|
|
5508
|
-
function targetGetAscendingBound(target, fieldPath, bound) {
|
|
5509
|
-
let value = MIN_VALUE;
|
|
5510
|
-
let inclusive = true;
|
|
5511
|
-
// Process all filters to find a value for the current field segment
|
|
5512
|
-
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
5513
|
-
let filterValue = MIN_VALUE;
|
|
5514
|
-
let filterInclusive = true;
|
|
5515
|
-
switch (fieldFilter.op) {
|
|
5516
|
-
case "<" /* LESS_THAN */:
|
|
5517
|
-
case "<=" /* LESS_THAN_OR_EQUAL */:
|
|
5518
|
-
filterValue = valuesGetLowerBound(fieldFilter.value);
|
|
5519
|
-
break;
|
|
5520
|
-
case "==" /* EQUAL */:
|
|
5521
|
-
case "in" /* IN */:
|
|
5522
|
-
case ">=" /* GREATER_THAN_OR_EQUAL */:
|
|
5523
|
-
filterValue = fieldFilter.value;
|
|
5524
|
-
break;
|
|
5525
|
-
case ">" /* GREATER_THAN */:
|
|
5526
|
-
filterValue = fieldFilter.value;
|
|
5527
|
-
filterInclusive = false;
|
|
5528
|
-
break;
|
|
5529
|
-
case "!=" /* NOT_EQUAL */:
|
|
5530
|
-
case "not-in" /* NOT_IN */:
|
|
5531
|
-
filterValue = MIN_VALUE;
|
|
5532
|
-
break;
|
|
5533
|
-
// Remaining filters cannot be used as lower bounds.
|
|
5534
|
-
}
|
|
5535
|
-
if (lowerBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) < 0) {
|
|
5536
|
-
value = filterValue;
|
|
5537
|
-
inclusive = filterInclusive;
|
|
5538
|
-
}
|
|
5539
|
-
}
|
|
5540
|
-
// If there is an additional bound, compare the values against the existing
|
|
5541
|
-
// range to see if we can narrow the scope.
|
|
5542
|
-
if (bound !== null) {
|
|
5543
|
-
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
5544
|
-
const orderBy = target.orderBy[i];
|
|
5545
|
-
if (orderBy.field.isEqual(fieldPath)) {
|
|
5546
|
-
const cursorValue = bound.position[i];
|
|
5547
|
-
if (lowerBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) < 0) {
|
|
5548
|
-
value = cursorValue;
|
|
5549
|
-
inclusive = bound.inclusive;
|
|
5550
|
-
}
|
|
5551
|
-
break;
|
|
5552
|
-
}
|
|
5553
|
-
}
|
|
5604
|
+
function filterEquals(f1, f2) {
|
|
5605
|
+
if (f1 instanceof FieldFilter) {
|
|
5606
|
+
return fieldFilterEquals(f1, f2);
|
|
5554
5607
|
}
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
/**
|
|
5558
|
-
* Returns the value to use as the upper bound for ascending index segment at
|
|
5559
|
-
* the provided `fieldPath` (or the lower bound for a descending segment).
|
|
5560
|
-
*/
|
|
5561
|
-
function targetGetDescendingBound(target, fieldPath, bound) {
|
|
5562
|
-
let value = MAX_VALUE;
|
|
5563
|
-
let inclusive = true;
|
|
5564
|
-
// Process all filters to find a value for the current field segment
|
|
5565
|
-
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
5566
|
-
let filterValue = MAX_VALUE;
|
|
5567
|
-
let filterInclusive = true;
|
|
5568
|
-
switch (fieldFilter.op) {
|
|
5569
|
-
case ">=" /* GREATER_THAN_OR_EQUAL */:
|
|
5570
|
-
case ">" /* GREATER_THAN */:
|
|
5571
|
-
filterValue = valuesGetUpperBound(fieldFilter.value);
|
|
5572
|
-
filterInclusive = false;
|
|
5573
|
-
break;
|
|
5574
|
-
case "==" /* EQUAL */:
|
|
5575
|
-
case "in" /* IN */:
|
|
5576
|
-
case "<=" /* LESS_THAN_OR_EQUAL */:
|
|
5577
|
-
filterValue = fieldFilter.value;
|
|
5578
|
-
break;
|
|
5579
|
-
case "<" /* LESS_THAN */:
|
|
5580
|
-
filterValue = fieldFilter.value;
|
|
5581
|
-
filterInclusive = false;
|
|
5582
|
-
break;
|
|
5583
|
-
case "!=" /* NOT_EQUAL */:
|
|
5584
|
-
case "not-in" /* NOT_IN */:
|
|
5585
|
-
filterValue = MAX_VALUE;
|
|
5586
|
-
break;
|
|
5587
|
-
// Remaining filters cannot be used as upper bounds.
|
|
5588
|
-
}
|
|
5589
|
-
if (upperBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) > 0) {
|
|
5590
|
-
value = filterValue;
|
|
5591
|
-
inclusive = filterInclusive;
|
|
5592
|
-
}
|
|
5608
|
+
else if (f1 instanceof CompositeFilter) {
|
|
5609
|
+
return compositeFilterEquals(f1, f2);
|
|
5593
5610
|
}
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
if (bound !== null) {
|
|
5597
|
-
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
5598
|
-
const orderBy = target.orderBy[i];
|
|
5599
|
-
if (orderBy.field.isEqual(fieldPath)) {
|
|
5600
|
-
const cursorValue = bound.position[i];
|
|
5601
|
-
if (upperBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) > 0) {
|
|
5602
|
-
value = cursorValue;
|
|
5603
|
-
inclusive = bound.inclusive;
|
|
5604
|
-
}
|
|
5605
|
-
break;
|
|
5606
|
-
}
|
|
5607
|
-
}
|
|
5611
|
+
else {
|
|
5612
|
+
fail();
|
|
5608
5613
|
}
|
|
5609
|
-
return { value, inclusive };
|
|
5610
5614
|
}
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
// ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filters must be counted separately.
|
|
5624
|
-
// For instance, it is possible to have an index for "a ARRAY a ASC". Even
|
|
5625
|
-
// though these are on the same field, they should be counted as two
|
|
5626
|
-
// separate segments in an index.
|
|
5627
|
-
if (fieldFilter.op === "array-contains" /* ARRAY_CONTAINS */ ||
|
|
5628
|
-
fieldFilter.op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
5629
|
-
hasArraySegment = true;
|
|
5630
|
-
}
|
|
5631
|
-
else {
|
|
5632
|
-
fields = fields.add(fieldFilter.field);
|
|
5633
|
-
}
|
|
5634
|
-
}
|
|
5635
|
-
for (const orderBy of target.orderBy) {
|
|
5636
|
-
// __name__ is not an explicit segment of any index, so we don't need to
|
|
5637
|
-
// count it.
|
|
5638
|
-
if (!orderBy.field.isKeyField()) {
|
|
5639
|
-
fields = fields.add(orderBy.field);
|
|
5640
|
-
}
|
|
5615
|
+
function fieldFilterEquals(f1, f2) {
|
|
5616
|
+
return (f2 instanceof FieldFilter &&
|
|
5617
|
+
f1.op === f2.op &&
|
|
5618
|
+
f1.field.isEqual(f2.field) &&
|
|
5619
|
+
valueEquals(f1.value, f2.value));
|
|
5620
|
+
}
|
|
5621
|
+
function compositeFilterEquals(f1, f2) {
|
|
5622
|
+
if (f2 instanceof CompositeFilter &&
|
|
5623
|
+
f1.op === f2.op &&
|
|
5624
|
+
f1.filters.length === f2.filters.length) {
|
|
5625
|
+
const subFiltersMatch = f1.filters.reduce((result, f1Filter, index) => result && filterEquals(f1Filter, f2.filters[index]), true);
|
|
5626
|
+
return subFiltersMatch;
|
|
5641
5627
|
}
|
|
5642
|
-
return
|
|
5628
|
+
return false;
|
|
5643
5629
|
}
|
|
5644
|
-
|
|
5630
|
+
/**
|
|
5631
|
+
* Returns a new composite filter that contains all filter from
|
|
5632
|
+
* `compositeFilter` plus all the given filters in `otherFilters`.
|
|
5633
|
+
*/
|
|
5634
|
+
function compositeFilterWithAddedFilters(compositeFilter, otherFilters) {
|
|
5635
|
+
const mergedFilters = compositeFilter.filters.concat(otherFilters);
|
|
5636
|
+
return CompositeFilter.create(mergedFilters, compositeFilter.op);
|
|
5645
5637
|
}
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
this.op = op;
|
|
5651
|
-
this.value = value;
|
|
5652
|
-
}
|
|
5653
|
-
/**
|
|
5654
|
-
* Creates a filter based on the provided arguments.
|
|
5655
|
-
*/
|
|
5656
|
-
static create(field, op, value) {
|
|
5657
|
-
if (field.isKeyField()) {
|
|
5658
|
-
if (op === "in" /* IN */ || op === "not-in" /* NOT_IN */) {
|
|
5659
|
-
return this.createKeyFieldInFilter(field, op, value);
|
|
5660
|
-
}
|
|
5661
|
-
else {
|
|
5662
|
-
return new KeyFieldFilter(field, op, value);
|
|
5663
|
-
}
|
|
5664
|
-
}
|
|
5665
|
-
else if (op === "array-contains" /* ARRAY_CONTAINS */) {
|
|
5666
|
-
return new ArrayContainsFilter(field, value);
|
|
5667
|
-
}
|
|
5668
|
-
else if (op === "in" /* IN */) {
|
|
5669
|
-
return new InFilter(field, value);
|
|
5670
|
-
}
|
|
5671
|
-
else if (op === "not-in" /* NOT_IN */) {
|
|
5672
|
-
return new NotInFilter(field, value);
|
|
5673
|
-
}
|
|
5674
|
-
else if (op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
5675
|
-
return new ArrayContainsAnyFilter(field, value);
|
|
5676
|
-
}
|
|
5677
|
-
else {
|
|
5678
|
-
return new FieldFilter(field, op, value);
|
|
5679
|
-
}
|
|
5680
|
-
}
|
|
5681
|
-
static createKeyFieldInFilter(field, op, value) {
|
|
5682
|
-
return op === "in" /* IN */
|
|
5683
|
-
? new KeyFieldInFilter(field, value)
|
|
5684
|
-
: new KeyFieldNotInFilter(field, value);
|
|
5685
|
-
}
|
|
5686
|
-
matches(doc) {
|
|
5687
|
-
const other = doc.data.field(this.field);
|
|
5688
|
-
// Types do not have to match in NOT_EQUAL filters.
|
|
5689
|
-
if (this.op === "!=" /* NOT_EQUAL */) {
|
|
5690
|
-
return (other !== null &&
|
|
5691
|
-
this.matchesComparison(valueCompare(other, this.value)));
|
|
5692
|
-
}
|
|
5693
|
-
// Only compare types with matching backend order (such as double and int).
|
|
5694
|
-
return (other !== null &&
|
|
5695
|
-
typeOrder(this.value) === typeOrder(other) &&
|
|
5696
|
-
this.matchesComparison(valueCompare(other, this.value)));
|
|
5638
|
+
/** Returns a debug description for `filter`. */
|
|
5639
|
+
function stringifyFilter(filter) {
|
|
5640
|
+
if (filter instanceof FieldFilter) {
|
|
5641
|
+
return stringifyFieldFilter(filter);
|
|
5697
5642
|
}
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
case "<" /* LESS_THAN */:
|
|
5701
|
-
return comparison < 0;
|
|
5702
|
-
case "<=" /* LESS_THAN_OR_EQUAL */:
|
|
5703
|
-
return comparison <= 0;
|
|
5704
|
-
case "==" /* EQUAL */:
|
|
5705
|
-
return comparison === 0;
|
|
5706
|
-
case "!=" /* NOT_EQUAL */:
|
|
5707
|
-
return comparison !== 0;
|
|
5708
|
-
case ">" /* GREATER_THAN */:
|
|
5709
|
-
return comparison > 0;
|
|
5710
|
-
case ">=" /* GREATER_THAN_OR_EQUAL */:
|
|
5711
|
-
return comparison >= 0;
|
|
5712
|
-
default:
|
|
5713
|
-
return fail();
|
|
5714
|
-
}
|
|
5643
|
+
else if (filter instanceof CompositeFilter) {
|
|
5644
|
+
return stringifyCompositeFilter(filter);
|
|
5715
5645
|
}
|
|
5716
|
-
|
|
5717
|
-
return
|
|
5718
|
-
"<" /* LESS_THAN */,
|
|
5719
|
-
"<=" /* LESS_THAN_OR_EQUAL */,
|
|
5720
|
-
">" /* GREATER_THAN */,
|
|
5721
|
-
">=" /* GREATER_THAN_OR_EQUAL */,
|
|
5722
|
-
"!=" /* NOT_EQUAL */,
|
|
5723
|
-
"not-in" /* NOT_IN */
|
|
5724
|
-
].indexOf(this.op) >= 0);
|
|
5646
|
+
else {
|
|
5647
|
+
return 'Filter';
|
|
5725
5648
|
}
|
|
5726
5649
|
}
|
|
5727
|
-
function
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
filter.op.toString() +
|
|
5733
|
-
canonicalId(filter.value));
|
|
5734
|
-
}
|
|
5735
|
-
function filterEquals(f1, f2) {
|
|
5736
|
-
return (f1.op === f2.op &&
|
|
5737
|
-
f1.field.isEqual(f2.field) &&
|
|
5738
|
-
valueEquals(f1.value, f2.value));
|
|
5650
|
+
function stringifyCompositeFilter(filter) {
|
|
5651
|
+
return (filter.op.toString() +
|
|
5652
|
+
` {` +
|
|
5653
|
+
filter.getFilters().map(stringifyFilter).join(' ,') +
|
|
5654
|
+
'}');
|
|
5739
5655
|
}
|
|
5740
|
-
|
|
5741
|
-
function stringifyFilter(filter) {
|
|
5656
|
+
function stringifyFieldFilter(filter) {
|
|
5742
5657
|
return `${filter.field.canonicalString()} ${filter.op} ${canonicalId(filter.value)}`;
|
|
5743
5658
|
}
|
|
5744
5659
|
/** Filter that matches on key fields (i.e. '__name__'). */
|
|
@@ -5755,8 +5670,8 @@ class KeyFieldFilter extends FieldFilter {
|
|
|
5755
5670
|
/** Filter that matches on key fields within an array. */
|
|
5756
5671
|
class KeyFieldInFilter extends FieldFilter {
|
|
5757
5672
|
constructor(field, value) {
|
|
5758
|
-
super(field, "in" /* IN */, value);
|
|
5759
|
-
this.keys = extractDocumentKeysFromArrayValue("in" /* IN */, value);
|
|
5673
|
+
super(field, "in" /* Operator.IN */, value);
|
|
5674
|
+
this.keys = extractDocumentKeysFromArrayValue("in" /* Operator.IN */, value);
|
|
5760
5675
|
}
|
|
5761
5676
|
matches(doc) {
|
|
5762
5677
|
return this.keys.some(key => key.isEqual(doc.key));
|
|
@@ -5765,8 +5680,8 @@ class KeyFieldInFilter extends FieldFilter {
|
|
|
5765
5680
|
/** Filter that matches on key fields not present within an array. */
|
|
5766
5681
|
class KeyFieldNotInFilter extends FieldFilter {
|
|
5767
5682
|
constructor(field, value) {
|
|
5768
|
-
super(field, "not-in" /* NOT_IN */, value);
|
|
5769
|
-
this.keys = extractDocumentKeysFromArrayValue("not-in" /* NOT_IN */, value);
|
|
5683
|
+
super(field, "not-in" /* Operator.NOT_IN */, value);
|
|
5684
|
+
this.keys = extractDocumentKeysFromArrayValue("not-in" /* Operator.NOT_IN */, value);
|
|
5770
5685
|
}
|
|
5771
5686
|
matches(doc) {
|
|
5772
5687
|
return !this.keys.some(key => key.isEqual(doc.key));
|
|
@@ -5781,7 +5696,7 @@ function extractDocumentKeysFromArrayValue(op, value) {
|
|
|
5781
5696
|
/** A Filter that implements the array-contains operator. */
|
|
5782
5697
|
class ArrayContainsFilter extends FieldFilter {
|
|
5783
5698
|
constructor(field, value) {
|
|
5784
|
-
super(field, "array-contains" /* ARRAY_CONTAINS */, value);
|
|
5699
|
+
super(field, "array-contains" /* Operator.ARRAY_CONTAINS */, value);
|
|
5785
5700
|
}
|
|
5786
5701
|
matches(doc) {
|
|
5787
5702
|
const other = doc.data.field(this.field);
|
|
@@ -5791,7 +5706,7 @@ class ArrayContainsFilter extends FieldFilter {
|
|
|
5791
5706
|
/** A Filter that implements the IN operator. */
|
|
5792
5707
|
class InFilter extends FieldFilter {
|
|
5793
5708
|
constructor(field, value) {
|
|
5794
|
-
super(field, "in" /* IN */, value);
|
|
5709
|
+
super(field, "in" /* Operator.IN */, value);
|
|
5795
5710
|
}
|
|
5796
5711
|
matches(doc) {
|
|
5797
5712
|
const other = doc.data.field(this.field);
|
|
@@ -5801,7 +5716,7 @@ class InFilter extends FieldFilter {
|
|
|
5801
5716
|
/** A Filter that implements the not-in operator. */
|
|
5802
5717
|
class NotInFilter extends FieldFilter {
|
|
5803
5718
|
constructor(field, value) {
|
|
5804
|
-
super(field, "not-in" /* NOT_IN */, value);
|
|
5719
|
+
super(field, "not-in" /* Operator.NOT_IN */, value);
|
|
5805
5720
|
}
|
|
5806
5721
|
matches(doc) {
|
|
5807
5722
|
if (arrayValueContains(this.value.arrayValue, { nullValue: 'NULL_VALUE' })) {
|
|
@@ -5814,7 +5729,7 @@ class NotInFilter extends FieldFilter {
|
|
|
5814
5729
|
/** A Filter that implements the array-contains-any operator. */
|
|
5815
5730
|
class ArrayContainsAnyFilter extends FieldFilter {
|
|
5816
5731
|
constructor(field, value) {
|
|
5817
|
-
super(field, "array-contains-any" /* ARRAY_CONTAINS_ANY */, value);
|
|
5732
|
+
super(field, "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */, value);
|
|
5818
5733
|
}
|
|
5819
5734
|
matches(doc) {
|
|
5820
5735
|
const other = doc.data.field(this.field);
|
|
@@ -5823,32 +5738,29 @@ class ArrayContainsAnyFilter extends FieldFilter {
|
|
|
5823
5738
|
}
|
|
5824
5739
|
return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
|
|
5825
5740
|
}
|
|
5826
|
-
}
|
|
5827
|
-
|
|
5828
|
-
|
|
5741
|
+
}
|
|
5742
|
+
|
|
5743
|
+
/**
|
|
5744
|
+
* @license
|
|
5745
|
+
* Copyright 2022 Google LLC
|
|
5829
5746
|
*
|
|
5830
|
-
*
|
|
5831
|
-
*
|
|
5832
|
-
*
|
|
5747
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5748
|
+
* you may not use this file except in compliance with the License.
|
|
5749
|
+
* You may obtain a copy of the License at
|
|
5833
5750
|
*
|
|
5834
|
-
*
|
|
5835
|
-
* of values for the (potentially implicit) order by clauses of a query.
|
|
5751
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5836
5752
|
*
|
|
5837
|
-
*
|
|
5838
|
-
*
|
|
5839
|
-
*
|
|
5753
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
5754
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
5755
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5756
|
+
* See the License for the specific language governing permissions and
|
|
5757
|
+
* limitations under the License.
|
|
5840
5758
|
*/
|
|
5841
|
-
class Bound {
|
|
5842
|
-
constructor(position, inclusive) {
|
|
5843
|
-
this.position = position;
|
|
5844
|
-
this.inclusive = inclusive;
|
|
5845
|
-
}
|
|
5846
|
-
}
|
|
5847
5759
|
/**
|
|
5848
5760
|
* An ordering on a field, in some Direction. Direction defaults to ASCENDING.
|
|
5849
5761
|
*/
|
|
5850
5762
|
class OrderBy {
|
|
5851
|
-
constructor(field, dir = "asc" /* ASCENDING */) {
|
|
5763
|
+
constructor(field, dir = "asc" /* Direction.ASCENDING */) {
|
|
5852
5764
|
this.field = field;
|
|
5853
5765
|
this.dir = dir;
|
|
5854
5766
|
}
|
|
@@ -5862,63 +5774,375 @@ function stringifyOrderBy(orderBy) {
|
|
|
5862
5774
|
}
|
|
5863
5775
|
function orderByEquals(left, right) {
|
|
5864
5776
|
return left.dir === right.dir && left.field.isEqual(right.field);
|
|
5777
|
+
}
|
|
5778
|
+
|
|
5779
|
+
/**
|
|
5780
|
+
* @license
|
|
5781
|
+
* Copyright 2019 Google LLC
|
|
5782
|
+
*
|
|
5783
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5784
|
+
* you may not use this file except in compliance with the License.
|
|
5785
|
+
* You may obtain a copy of the License at
|
|
5786
|
+
*
|
|
5787
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5788
|
+
*
|
|
5789
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
5790
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
5791
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5792
|
+
* See the License for the specific language governing permissions and
|
|
5793
|
+
* limitations under the License.
|
|
5794
|
+
*/
|
|
5795
|
+
// Visible for testing
|
|
5796
|
+
class TargetImpl {
|
|
5797
|
+
constructor(path, collectionGroup = null, orderBy = [], filters = [], limit = null, startAt = null, endAt = null) {
|
|
5798
|
+
this.path = path;
|
|
5799
|
+
this.collectionGroup = collectionGroup;
|
|
5800
|
+
this.orderBy = orderBy;
|
|
5801
|
+
this.filters = filters;
|
|
5802
|
+
this.limit = limit;
|
|
5803
|
+
this.startAt = startAt;
|
|
5804
|
+
this.endAt = endAt;
|
|
5805
|
+
this.memoizedCanonicalId = null;
|
|
5806
|
+
}
|
|
5865
5807
|
}
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5808
|
+
/**
|
|
5809
|
+
* Initializes a Target with a path and optional additional query constraints.
|
|
5810
|
+
* Path must currently be empty if this is a collection group query.
|
|
5811
|
+
*
|
|
5812
|
+
* NOTE: you should always construct `Target` from `Query.toTarget` instead of
|
|
5813
|
+
* using this factory method, because `Query` provides an implicit `orderBy`
|
|
5814
|
+
* property.
|
|
5815
|
+
*/
|
|
5816
|
+
function newTarget(path, collectionGroup = null, orderBy = [], filters = [], limit = null, startAt = null, endAt = null) {
|
|
5817
|
+
return new TargetImpl(path, collectionGroup, orderBy, filters, limit, startAt, endAt);
|
|
5818
|
+
}
|
|
5819
|
+
function canonifyTarget(target) {
|
|
5820
|
+
const targetImpl = debugCast(target);
|
|
5821
|
+
if (targetImpl.memoizedCanonicalId === null) {
|
|
5822
|
+
let str = targetImpl.path.canonicalString();
|
|
5823
|
+
if (targetImpl.collectionGroup !== null) {
|
|
5824
|
+
str += '|cg:' + targetImpl.collectionGroup;
|
|
5873
5825
|
}
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5826
|
+
str += '|f:';
|
|
5827
|
+
str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
|
|
5828
|
+
str += '|ob:';
|
|
5829
|
+
str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
|
|
5830
|
+
if (!isNullOrUndefined(targetImpl.limit)) {
|
|
5831
|
+
str += '|l:';
|
|
5832
|
+
str += targetImpl.limit;
|
|
5877
5833
|
}
|
|
5878
|
-
if (
|
|
5879
|
-
|
|
5834
|
+
if (targetImpl.startAt) {
|
|
5835
|
+
str += '|lb:';
|
|
5836
|
+
str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
|
|
5837
|
+
str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5880
5838
|
}
|
|
5881
|
-
if (
|
|
5882
|
-
|
|
5839
|
+
if (targetImpl.endAt) {
|
|
5840
|
+
str += '|ub:';
|
|
5841
|
+
str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
|
|
5842
|
+
str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
|
|
5883
5843
|
}
|
|
5844
|
+
targetImpl.memoizedCanonicalId = str;
|
|
5884
5845
|
}
|
|
5885
|
-
return
|
|
5846
|
+
return targetImpl.memoizedCanonicalId;
|
|
5847
|
+
}
|
|
5848
|
+
function stringifyTarget(target) {
|
|
5849
|
+
let str = target.path.canonicalString();
|
|
5850
|
+
if (target.collectionGroup !== null) {
|
|
5851
|
+
str += ' collectionGroup=' + target.collectionGroup;
|
|
5852
|
+
}
|
|
5853
|
+
if (target.filters.length > 0) {
|
|
5854
|
+
str += `, filters: [${target.filters
|
|
5855
|
+
.map(f => stringifyFilter(f))
|
|
5856
|
+
.join(', ')}]`;
|
|
5857
|
+
}
|
|
5858
|
+
if (!isNullOrUndefined(target.limit)) {
|
|
5859
|
+
str += ', limit: ' + target.limit;
|
|
5860
|
+
}
|
|
5861
|
+
if (target.orderBy.length > 0) {
|
|
5862
|
+
str += `, orderBy: [${target.orderBy
|
|
5863
|
+
.map(o => stringifyOrderBy(o))
|
|
5864
|
+
.join(', ')}]`;
|
|
5865
|
+
}
|
|
5866
|
+
if (target.startAt) {
|
|
5867
|
+
str += ', startAt: ';
|
|
5868
|
+
str += target.startAt.inclusive ? 'b:' : 'a:';
|
|
5869
|
+
str += target.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5870
|
+
}
|
|
5871
|
+
if (target.endAt) {
|
|
5872
|
+
str += ', endAt: ';
|
|
5873
|
+
str += target.endAt.inclusive ? 'a:' : 'b:';
|
|
5874
|
+
str += target.endAt.position.map(p => canonicalId(p)).join(',');
|
|
5875
|
+
}
|
|
5876
|
+
return `Target(${str})`;
|
|
5877
|
+
}
|
|
5878
|
+
function targetEquals(left, right) {
|
|
5879
|
+
if (left.limit !== right.limit) {
|
|
5880
|
+
return false;
|
|
5881
|
+
}
|
|
5882
|
+
if (left.orderBy.length !== right.orderBy.length) {
|
|
5883
|
+
return false;
|
|
5884
|
+
}
|
|
5885
|
+
for (let i = 0; i < left.orderBy.length; i++) {
|
|
5886
|
+
if (!orderByEquals(left.orderBy[i], right.orderBy[i])) {
|
|
5887
|
+
return false;
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
if (left.filters.length !== right.filters.length) {
|
|
5891
|
+
return false;
|
|
5892
|
+
}
|
|
5893
|
+
for (let i = 0; i < left.filters.length; i++) {
|
|
5894
|
+
if (!filterEquals(left.filters[i], right.filters[i])) {
|
|
5895
|
+
return false;
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
if (left.collectionGroup !== right.collectionGroup) {
|
|
5899
|
+
return false;
|
|
5900
|
+
}
|
|
5901
|
+
if (!left.path.isEqual(right.path)) {
|
|
5902
|
+
return false;
|
|
5903
|
+
}
|
|
5904
|
+
if (!boundEquals(left.startAt, right.startAt)) {
|
|
5905
|
+
return false;
|
|
5906
|
+
}
|
|
5907
|
+
return boundEquals(left.endAt, right.endAt);
|
|
5908
|
+
}
|
|
5909
|
+
function targetIsDocumentTarget(target) {
|
|
5910
|
+
return (DocumentKey.isDocumentKey(target.path) &&
|
|
5911
|
+
target.collectionGroup === null &&
|
|
5912
|
+
target.filters.length === 0);
|
|
5913
|
+
}
|
|
5914
|
+
/** Returns the field filters that target the given field path. */
|
|
5915
|
+
function targetGetFieldFiltersForPath(target, path) {
|
|
5916
|
+
return target.filters.filter(f => f instanceof FieldFilter && f.field.isEqual(path));
|
|
5886
5917
|
}
|
|
5887
5918
|
/**
|
|
5888
|
-
* Returns
|
|
5889
|
-
*
|
|
5919
|
+
* Returns the values that are used in ARRAY_CONTAINS or ARRAY_CONTAINS_ANY
|
|
5920
|
+
* filters. Returns `null` if there are no such filters.
|
|
5890
5921
|
*/
|
|
5891
|
-
function
|
|
5892
|
-
const
|
|
5893
|
-
|
|
5922
|
+
function targetGetArrayValues(target, fieldIndex) {
|
|
5923
|
+
const segment = fieldIndexGetArraySegment(fieldIndex);
|
|
5924
|
+
if (segment === undefined) {
|
|
5925
|
+
return null;
|
|
5926
|
+
}
|
|
5927
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, segment.fieldPath)) {
|
|
5928
|
+
switch (fieldFilter.op) {
|
|
5929
|
+
case "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */:
|
|
5930
|
+
return fieldFilter.value.arrayValue.values || [];
|
|
5931
|
+
case "array-contains" /* Operator.ARRAY_CONTAINS */:
|
|
5932
|
+
return [fieldFilter.value];
|
|
5933
|
+
// Remaining filters are not array filters.
|
|
5934
|
+
}
|
|
5935
|
+
}
|
|
5936
|
+
return null;
|
|
5894
5937
|
}
|
|
5895
5938
|
/**
|
|
5896
|
-
* Returns
|
|
5897
|
-
*
|
|
5939
|
+
* Returns the list of values that are used in != or NOT_IN filters. Returns
|
|
5940
|
+
* `null` if there are no such filters.
|
|
5898
5941
|
*/
|
|
5899
|
-
function
|
|
5900
|
-
const
|
|
5901
|
-
|
|
5942
|
+
function targetGetNotInValues(target, fieldIndex) {
|
|
5943
|
+
const values = new Map();
|
|
5944
|
+
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5945
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, segment.fieldPath)) {
|
|
5946
|
+
switch (fieldFilter.op) {
|
|
5947
|
+
case "==" /* Operator.EQUAL */:
|
|
5948
|
+
case "in" /* Operator.IN */:
|
|
5949
|
+
// Encode equality prefix, which is encoded in the index value before
|
|
5950
|
+
// the inequality (e.g. `a == 'a' && b != 'b'` is encoded to
|
|
5951
|
+
// `value != 'ab'`).
|
|
5952
|
+
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5953
|
+
break;
|
|
5954
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
5955
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
5956
|
+
// NotIn/NotEqual is always a suffix. There cannot be any remaining
|
|
5957
|
+
// segments and hence we can return early here.
|
|
5958
|
+
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5959
|
+
return Array.from(values.values());
|
|
5960
|
+
// Remaining filters cannot be used as notIn bounds.
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
}
|
|
5964
|
+
return null;
|
|
5902
5965
|
}
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5966
|
+
/**
|
|
5967
|
+
* Returns a lower bound of field values that can be used as a starting point to
|
|
5968
|
+
* scan the index defined by `fieldIndex`. Returns `MIN_VALUE` if no lower bound
|
|
5969
|
+
* exists.
|
|
5970
|
+
*/
|
|
5971
|
+
function targetGetLowerBound(target, fieldIndex) {
|
|
5972
|
+
const values = [];
|
|
5973
|
+
let inclusive = true;
|
|
5974
|
+
// For each segment, retrieve a lower bound if there is a suitable filter or
|
|
5975
|
+
// startAt.
|
|
5976
|
+
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5977
|
+
const segmentBound = segment.kind === 0 /* IndexKind.ASCENDING */
|
|
5978
|
+
? targetGetAscendingBound(target, segment.fieldPath, target.startAt)
|
|
5979
|
+
: targetGetDescendingBound(target, segment.fieldPath, target.startAt);
|
|
5980
|
+
values.push(segmentBound.value);
|
|
5981
|
+
inclusive && (inclusive = segmentBound.inclusive);
|
|
5906
5982
|
}
|
|
5907
|
-
|
|
5908
|
-
|
|
5983
|
+
return new Bound(values, inclusive);
|
|
5984
|
+
}
|
|
5985
|
+
/**
|
|
5986
|
+
* Returns an upper bound of field values that can be used as an ending point
|
|
5987
|
+
* when scanning the index defined by `fieldIndex`. Returns `MAX_VALUE` if no
|
|
5988
|
+
* upper bound exists.
|
|
5989
|
+
*/
|
|
5990
|
+
function targetGetUpperBound(target, fieldIndex) {
|
|
5991
|
+
const values = [];
|
|
5992
|
+
let inclusive = true;
|
|
5993
|
+
// For each segment, retrieve an upper bound if there is a suitable filter or
|
|
5994
|
+
// endAt.
|
|
5995
|
+
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5996
|
+
const segmentBound = segment.kind === 0 /* IndexKind.ASCENDING */
|
|
5997
|
+
? targetGetDescendingBound(target, segment.fieldPath, target.endAt)
|
|
5998
|
+
: targetGetAscendingBound(target, segment.fieldPath, target.endAt);
|
|
5999
|
+
values.push(segmentBound.value);
|
|
6000
|
+
inclusive && (inclusive = segmentBound.inclusive);
|
|
6001
|
+
}
|
|
6002
|
+
return new Bound(values, inclusive);
|
|
6003
|
+
}
|
|
6004
|
+
/**
|
|
6005
|
+
* Returns the value to use as the lower bound for ascending index segment at
|
|
6006
|
+
* the provided `fieldPath` (or the upper bound for an descending segment).
|
|
6007
|
+
*/
|
|
6008
|
+
function targetGetAscendingBound(target, fieldPath, bound) {
|
|
6009
|
+
let value = MIN_VALUE;
|
|
6010
|
+
let inclusive = true;
|
|
6011
|
+
// Process all filters to find a value for the current field segment
|
|
6012
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
6013
|
+
let filterValue = MIN_VALUE;
|
|
6014
|
+
let filterInclusive = true;
|
|
6015
|
+
switch (fieldFilter.op) {
|
|
6016
|
+
case "<" /* Operator.LESS_THAN */:
|
|
6017
|
+
case "<=" /* Operator.LESS_THAN_OR_EQUAL */:
|
|
6018
|
+
filterValue = valuesGetLowerBound(fieldFilter.value);
|
|
6019
|
+
break;
|
|
6020
|
+
case "==" /* Operator.EQUAL */:
|
|
6021
|
+
case "in" /* Operator.IN */:
|
|
6022
|
+
case ">=" /* Operator.GREATER_THAN_OR_EQUAL */:
|
|
6023
|
+
filterValue = fieldFilter.value;
|
|
6024
|
+
break;
|
|
6025
|
+
case ">" /* Operator.GREATER_THAN */:
|
|
6026
|
+
filterValue = fieldFilter.value;
|
|
6027
|
+
filterInclusive = false;
|
|
6028
|
+
break;
|
|
6029
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
6030
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
6031
|
+
filterValue = MIN_VALUE;
|
|
6032
|
+
break;
|
|
6033
|
+
// Remaining filters cannot be used as lower bounds.
|
|
6034
|
+
}
|
|
6035
|
+
if (lowerBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) < 0) {
|
|
6036
|
+
value = filterValue;
|
|
6037
|
+
inclusive = filterInclusive;
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
// If there is an additional bound, compare the values against the existing
|
|
6041
|
+
// range to see if we can narrow the scope.
|
|
6042
|
+
if (bound !== null) {
|
|
6043
|
+
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
6044
|
+
const orderBy = target.orderBy[i];
|
|
6045
|
+
if (orderBy.field.isEqual(fieldPath)) {
|
|
6046
|
+
const cursorValue = bound.position[i];
|
|
6047
|
+
if (lowerBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) < 0) {
|
|
6048
|
+
value = cursorValue;
|
|
6049
|
+
inclusive = bound.inclusive;
|
|
6050
|
+
}
|
|
6051
|
+
break;
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
}
|
|
6055
|
+
return { value, inclusive };
|
|
6056
|
+
}
|
|
6057
|
+
/**
|
|
6058
|
+
* Returns the value to use as the upper bound for ascending index segment at
|
|
6059
|
+
* the provided `fieldPath` (or the lower bound for a descending segment).
|
|
6060
|
+
*/
|
|
6061
|
+
function targetGetDescendingBound(target, fieldPath, bound) {
|
|
6062
|
+
let value = MAX_VALUE;
|
|
6063
|
+
let inclusive = true;
|
|
6064
|
+
// Process all filters to find a value for the current field segment
|
|
6065
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
6066
|
+
let filterValue = MAX_VALUE;
|
|
6067
|
+
let filterInclusive = true;
|
|
6068
|
+
switch (fieldFilter.op) {
|
|
6069
|
+
case ">=" /* Operator.GREATER_THAN_OR_EQUAL */:
|
|
6070
|
+
case ">" /* Operator.GREATER_THAN */:
|
|
6071
|
+
filterValue = valuesGetUpperBound(fieldFilter.value);
|
|
6072
|
+
filterInclusive = false;
|
|
6073
|
+
break;
|
|
6074
|
+
case "==" /* Operator.EQUAL */:
|
|
6075
|
+
case "in" /* Operator.IN */:
|
|
6076
|
+
case "<=" /* Operator.LESS_THAN_OR_EQUAL */:
|
|
6077
|
+
filterValue = fieldFilter.value;
|
|
6078
|
+
break;
|
|
6079
|
+
case "<" /* Operator.LESS_THAN */:
|
|
6080
|
+
filterValue = fieldFilter.value;
|
|
6081
|
+
filterInclusive = false;
|
|
6082
|
+
break;
|
|
6083
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
6084
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
6085
|
+
filterValue = MAX_VALUE;
|
|
6086
|
+
break;
|
|
6087
|
+
// Remaining filters cannot be used as upper bounds.
|
|
6088
|
+
}
|
|
6089
|
+
if (upperBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) > 0) {
|
|
6090
|
+
value = filterValue;
|
|
6091
|
+
inclusive = filterInclusive;
|
|
6092
|
+
}
|
|
6093
|
+
}
|
|
6094
|
+
// If there is an additional bound, compare the values against the existing
|
|
6095
|
+
// range to see if we can narrow the scope.
|
|
6096
|
+
if (bound !== null) {
|
|
6097
|
+
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
6098
|
+
const orderBy = target.orderBy[i];
|
|
6099
|
+
if (orderBy.field.isEqual(fieldPath)) {
|
|
6100
|
+
const cursorValue = bound.position[i];
|
|
6101
|
+
if (upperBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) > 0) {
|
|
6102
|
+
value = cursorValue;
|
|
6103
|
+
inclusive = bound.inclusive;
|
|
6104
|
+
}
|
|
6105
|
+
break;
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
5909
6108
|
}
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
6109
|
+
return { value, inclusive };
|
|
6110
|
+
}
|
|
6111
|
+
/** Returns the number of segments of a perfect index for this target. */
|
|
6112
|
+
function targetGetSegmentCount(target) {
|
|
6113
|
+
let fields = new SortedSet(FieldPath$1.comparator);
|
|
6114
|
+
let hasArraySegment = false;
|
|
6115
|
+
for (const filter of target.filters) {
|
|
6116
|
+
for (const subFilter of filter.getFlattenedFilters()) {
|
|
6117
|
+
// __name__ is not an explicit segment of any index, so we don't need to
|
|
6118
|
+
// count it.
|
|
6119
|
+
if (subFilter.field.isKeyField()) {
|
|
6120
|
+
continue;
|
|
6121
|
+
}
|
|
6122
|
+
// ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filters must be counted separately.
|
|
6123
|
+
// For instance, it is possible to have an index for "a ARRAY a ASC". Even
|
|
6124
|
+
// though these are on the same field, they should be counted as two
|
|
6125
|
+
// separate segments in an index.
|
|
6126
|
+
if (subFilter.op === "array-contains" /* Operator.ARRAY_CONTAINS */ ||
|
|
6127
|
+
subFilter.op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
6128
|
+
hasArraySegment = true;
|
|
6129
|
+
}
|
|
6130
|
+
else {
|
|
6131
|
+
fields = fields.add(subFilter.field);
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
5913
6134
|
}
|
|
5914
|
-
for (
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
if (!
|
|
5918
|
-
|
|
6135
|
+
for (const orderBy of target.orderBy) {
|
|
6136
|
+
// __name__ is not an explicit segment of any index, so we don't need to
|
|
6137
|
+
// count it.
|
|
6138
|
+
if (!orderBy.field.isKeyField()) {
|
|
6139
|
+
fields = fields.add(orderBy.field);
|
|
5919
6140
|
}
|
|
5920
6141
|
}
|
|
5921
|
-
return
|
|
6142
|
+
return fields.size + (hasArraySegment ? 1 : 0);
|
|
6143
|
+
}
|
|
6144
|
+
function targetHasLimit(target) {
|
|
6145
|
+
return target.limit !== null;
|
|
5922
6146
|
}
|
|
5923
6147
|
|
|
5924
6148
|
/**
|
|
@@ -5949,7 +6173,7 @@ class QueryImpl {
|
|
|
5949
6173
|
* Initializes a Query with a path and optional additional query constraints.
|
|
5950
6174
|
* Path must currently be empty if this is a collection group query.
|
|
5951
6175
|
*/
|
|
5952
|
-
constructor(path, collectionGroup = null, explicitOrderBy = [], filters = [], limit = null, limitType = "F" /* First */, startAt = null, endAt = null) {
|
|
6176
|
+
constructor(path, collectionGroup = null, explicitOrderBy = [], filters = [], limit = null, limitType = "F" /* LimitType.First */, startAt = null, endAt = null) {
|
|
5953
6177
|
this.path = path;
|
|
5954
6178
|
this.collectionGroup = collectionGroup;
|
|
5955
6179
|
this.explicitOrderBy = explicitOrderBy;
|
|
@@ -6003,20 +6227,9 @@ function getFirstOrderByField(query) {
|
|
|
6003
6227
|
}
|
|
6004
6228
|
function getInequalityFilterField(query) {
|
|
6005
6229
|
for (const filter of query.filters) {
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
}
|
|
6010
|
-
return null;
|
|
6011
|
-
}
|
|
6012
|
-
/**
|
|
6013
|
-
* Checks if any of the provided Operators are included in the query and
|
|
6014
|
-
* returns the first one that is, or null if none are.
|
|
6015
|
-
*/
|
|
6016
|
-
function findFilterOperator(query, operators) {
|
|
6017
|
-
for (const filter of query.filters) {
|
|
6018
|
-
if (operators.indexOf(filter.op) >= 0) {
|
|
6019
|
-
return filter.op;
|
|
6230
|
+
const result = filter.getFirstInequalityField();
|
|
6231
|
+
if (result !== null) {
|
|
6232
|
+
return result;
|
|
6020
6233
|
}
|
|
6021
6234
|
}
|
|
6022
6235
|
return null;
|
|
@@ -6062,7 +6275,7 @@ function queryOrderBy(query) {
|
|
|
6062
6275
|
if (!inequalityField.isKeyField()) {
|
|
6063
6276
|
queryImpl.memoizedOrderBy.push(new OrderBy(inequalityField));
|
|
6064
6277
|
}
|
|
6065
|
-
queryImpl.memoizedOrderBy.push(new OrderBy(FieldPath$1.keyField(), "asc" /* ASCENDING */));
|
|
6278
|
+
queryImpl.memoizedOrderBy.push(new OrderBy(FieldPath$1.keyField(), "asc" /* Direction.ASCENDING */));
|
|
6066
6279
|
}
|
|
6067
6280
|
else {
|
|
6068
6281
|
let foundKeyOrdering = false;
|
|
@@ -6078,7 +6291,7 @@ function queryOrderBy(query) {
|
|
|
6078
6291
|
const lastDirection = queryImpl.explicitOrderBy.length > 0
|
|
6079
6292
|
? queryImpl.explicitOrderBy[queryImpl.explicitOrderBy.length - 1]
|
|
6080
6293
|
.dir
|
|
6081
|
-
: "asc" /* ASCENDING */;
|
|
6294
|
+
: "asc" /* Direction.ASCENDING */;
|
|
6082
6295
|
queryImpl.memoizedOrderBy.push(new OrderBy(FieldPath$1.keyField(), lastDirection));
|
|
6083
6296
|
}
|
|
6084
6297
|
}
|
|
@@ -6091,16 +6304,16 @@ function queryOrderBy(query) {
|
|
|
6091
6304
|
function queryToTarget(query) {
|
|
6092
6305
|
const queryImpl = debugCast(query);
|
|
6093
6306
|
if (!queryImpl.memoizedTarget) {
|
|
6094
|
-
if (queryImpl.limitType === "F" /* First */) {
|
|
6307
|
+
if (queryImpl.limitType === "F" /* LimitType.First */) {
|
|
6095
6308
|
queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, queryOrderBy(queryImpl), queryImpl.filters, queryImpl.limit, queryImpl.startAt, queryImpl.endAt);
|
|
6096
6309
|
}
|
|
6097
6310
|
else {
|
|
6098
6311
|
// Flip the orderBy directions since we want the last results
|
|
6099
6312
|
const orderBys = [];
|
|
6100
6313
|
for (const orderBy of queryOrderBy(queryImpl)) {
|
|
6101
|
-
const dir = orderBy.dir === "desc" /* DESCENDING */
|
|
6102
|
-
? "asc" /* ASCENDING */
|
|
6103
|
-
: "desc" /* DESCENDING */;
|
|
6314
|
+
const dir = orderBy.dir === "desc" /* Direction.DESCENDING */
|
|
6315
|
+
? "asc" /* Direction.ASCENDING */
|
|
6316
|
+
: "desc" /* Direction.DESCENDING */;
|
|
6104
6317
|
orderBys.push(new OrderBy(orderBy.field, dir));
|
|
6105
6318
|
}
|
|
6106
6319
|
// We need to swap the cursors to match the now-flipped query ordering.
|
|
@@ -6117,6 +6330,8 @@ function queryToTarget(query) {
|
|
|
6117
6330
|
return queryImpl.memoizedTarget;
|
|
6118
6331
|
}
|
|
6119
6332
|
function queryWithAddedFilter(query, filter) {
|
|
6333
|
+
filter.getFirstInequalityField();
|
|
6334
|
+
getInequalityFilterField(query);
|
|
6120
6335
|
const newFilters = query.filters.concat([filter]);
|
|
6121
6336
|
return new QueryImpl(query.path, query.collectionGroup, query.explicitOrderBy.slice(), newFilters, query.limit, query.limitType, query.startAt, query.endAt);
|
|
6122
6337
|
}
|
|
@@ -6177,7 +6392,13 @@ function queryMatchesPathAndCollectionGroup(query, doc) {
|
|
|
6177
6392
|
* in the results.
|
|
6178
6393
|
*/
|
|
6179
6394
|
function queryMatchesOrderBy(query, doc) {
|
|
6180
|
-
|
|
6395
|
+
// We must use `queryOrderBy()` to get the list of all orderBys (both implicit and explicit).
|
|
6396
|
+
// Note that for OR queries, orderBy applies to all disjunction terms and implicit orderBys must
|
|
6397
|
+
// be taken into account. For example, the query "a > 1 || b==1" has an implicit "orderBy a" due
|
|
6398
|
+
// to the inequality, and is evaluated as "a > 1 orderBy a || b==1 orderBy a".
|
|
6399
|
+
// A document with content of {b:1} matches the filters, but does not match the orderBy because
|
|
6400
|
+
// it's missing the field 'a'.
|
|
6401
|
+
for (const orderBy of queryOrderBy(query)) {
|
|
6181
6402
|
// order by key always matches
|
|
6182
6403
|
if (!orderBy.field.isKeyField() && doc.data.field(orderBy.field) === null) {
|
|
6183
6404
|
return false;
|
|
@@ -6239,9 +6460,9 @@ function compareDocs(orderBy, d1, d2) {
|
|
|
6239
6460
|
? DocumentKey.comparator(d1.key, d2.key)
|
|
6240
6461
|
: compareDocumentsByField(orderBy.field, d1, d2);
|
|
6241
6462
|
switch (orderBy.dir) {
|
|
6242
|
-
case "asc" /* ASCENDING */:
|
|
6463
|
+
case "asc" /* Direction.ASCENDING */:
|
|
6243
6464
|
return comparison;
|
|
6244
|
-
case "desc" /* DESCENDING */:
|
|
6465
|
+
case "desc" /* Direction.DESCENDING */:
|
|
6245
6466
|
return -1 * comparison;
|
|
6246
6467
|
default:
|
|
6247
6468
|
return fail();
|
|
@@ -6927,10 +7148,10 @@ function mutationEquals(left, right) {
|
|
|
6927
7148
|
if (!fieldTransformsAreEqual(left.fieldTransforms, right.fieldTransforms)) {
|
|
6928
7149
|
return false;
|
|
6929
7150
|
}
|
|
6930
|
-
if (left.type === 0 /* Set */) {
|
|
7151
|
+
if (left.type === 0 /* MutationType.Set */) {
|
|
6931
7152
|
return left.value.isEqual(right.value);
|
|
6932
7153
|
}
|
|
6933
|
-
if (left.type === 1 /* Patch */) {
|
|
7154
|
+
if (left.type === 1 /* MutationType.Patch */) {
|
|
6934
7155
|
return (left.data.isEqual(right.data) &&
|
|
6935
7156
|
left.fieldMask.isEqual(right.fieldMask));
|
|
6936
7157
|
}
|
|
@@ -6947,7 +7168,7 @@ class SetMutation extends Mutation {
|
|
|
6947
7168
|
this.value = value;
|
|
6948
7169
|
this.precondition = precondition;
|
|
6949
7170
|
this.fieldTransforms = fieldTransforms;
|
|
6950
|
-
this.type = 0 /* Set */;
|
|
7171
|
+
this.type = 0 /* MutationType.Set */;
|
|
6951
7172
|
}
|
|
6952
7173
|
getFieldMask() {
|
|
6953
7174
|
return null;
|
|
@@ -6999,7 +7220,7 @@ class PatchMutation extends Mutation {
|
|
|
6999
7220
|
this.fieldMask = fieldMask;
|
|
7000
7221
|
this.precondition = precondition;
|
|
7001
7222
|
this.fieldTransforms = fieldTransforms;
|
|
7002
|
-
this.type = 1 /* Patch */;
|
|
7223
|
+
this.type = 1 /* MutationType.Patch */;
|
|
7003
7224
|
}
|
|
7004
7225
|
getFieldMask() {
|
|
7005
7226
|
return this.fieldMask;
|
|
@@ -7101,7 +7322,7 @@ class DeleteMutation extends Mutation {
|
|
|
7101
7322
|
super();
|
|
7102
7323
|
this.key = key;
|
|
7103
7324
|
this.precondition = precondition;
|
|
7104
|
-
this.type = 2 /* Delete */;
|
|
7325
|
+
this.type = 2 /* MutationType.Delete */;
|
|
7105
7326
|
this.fieldTransforms = [];
|
|
7106
7327
|
}
|
|
7107
7328
|
getFieldMask() {
|
|
@@ -7135,7 +7356,7 @@ class VerifyMutation extends Mutation {
|
|
|
7135
7356
|
super();
|
|
7136
7357
|
this.key = key;
|
|
7137
7358
|
this.precondition = precondition;
|
|
7138
|
-
this.type = 3 /* Verify */;
|
|
7359
|
+
this.type = 3 /* MutationType.Verify */;
|
|
7139
7360
|
this.fieldTransforms = [];
|
|
7140
7361
|
}
|
|
7141
7362
|
getFieldMask() {
|
|
@@ -7764,13 +7985,13 @@ class TargetState {
|
|
|
7764
7985
|
let removedDocuments = documentKeySet();
|
|
7765
7986
|
this.documentChanges.forEach((key, changeType) => {
|
|
7766
7987
|
switch (changeType) {
|
|
7767
|
-
case 0 /* Added */:
|
|
7988
|
+
case 0 /* ChangeType.Added */:
|
|
7768
7989
|
addedDocuments = addedDocuments.add(key);
|
|
7769
7990
|
break;
|
|
7770
|
-
case 2 /* Modified */:
|
|
7991
|
+
case 2 /* ChangeType.Modified */:
|
|
7771
7992
|
modifiedDocuments = modifiedDocuments.add(key);
|
|
7772
7993
|
break;
|
|
7773
|
-
case 1 /* Removed */:
|
|
7994
|
+
case 1 /* ChangeType.Removed */:
|
|
7774
7995
|
removedDocuments = removedDocuments.add(key);
|
|
7775
7996
|
break;
|
|
7776
7997
|
default:
|
|
@@ -7846,12 +8067,12 @@ class WatchChangeAggregator {
|
|
|
7846
8067
|
this.forEachTarget(targetChange, targetId => {
|
|
7847
8068
|
const targetState = this.ensureTargetState(targetId);
|
|
7848
8069
|
switch (targetChange.state) {
|
|
7849
|
-
case 0 /* NoChange */:
|
|
8070
|
+
case 0 /* WatchTargetChangeState.NoChange */:
|
|
7850
8071
|
if (this.isActiveTarget(targetId)) {
|
|
7851
8072
|
targetState.updateResumeToken(targetChange.resumeToken);
|
|
7852
8073
|
}
|
|
7853
8074
|
break;
|
|
7854
|
-
case 1 /* Added */:
|
|
8075
|
+
case 1 /* WatchTargetChangeState.Added */:
|
|
7855
8076
|
// We need to decrement the number of pending acks needed from watch
|
|
7856
8077
|
// for this targetId.
|
|
7857
8078
|
targetState.recordTargetResponse();
|
|
@@ -7863,7 +8084,7 @@ class WatchChangeAggregator {
|
|
|
7863
8084
|
}
|
|
7864
8085
|
targetState.updateResumeToken(targetChange.resumeToken);
|
|
7865
8086
|
break;
|
|
7866
|
-
case 2 /* Removed */:
|
|
8087
|
+
case 2 /* WatchTargetChangeState.Removed */:
|
|
7867
8088
|
// We need to keep track of removed targets to we can post-filter and
|
|
7868
8089
|
// remove any target changes.
|
|
7869
8090
|
// We need to decrement the number of pending acks needed from watch
|
|
@@ -7873,13 +8094,13 @@ class WatchChangeAggregator {
|
|
|
7873
8094
|
this.removeTarget(targetId);
|
|
7874
8095
|
}
|
|
7875
8096
|
break;
|
|
7876
|
-
case 3 /* Current */:
|
|
8097
|
+
case 3 /* WatchTargetChangeState.Current */:
|
|
7877
8098
|
if (this.isActiveTarget(targetId)) {
|
|
7878
8099
|
targetState.markCurrent();
|
|
7879
8100
|
targetState.updateResumeToken(targetChange.resumeToken);
|
|
7880
8101
|
}
|
|
7881
8102
|
break;
|
|
7882
|
-
case 4 /* Reset */:
|
|
8103
|
+
case 4 /* WatchTargetChangeState.Reset */:
|
|
7883
8104
|
if (this.isActiveTarget(targetId)) {
|
|
7884
8105
|
// Reset the target and synthesizes removes for all existing
|
|
7885
8106
|
// documents. The backend will re-add any documents that still
|
|
@@ -7989,7 +8210,7 @@ class WatchChangeAggregator {
|
|
|
7989
8210
|
targets.forEachWhile(targetId => {
|
|
7990
8211
|
const targetData = this.targetDataForActiveTarget(targetId);
|
|
7991
8212
|
if (targetData &&
|
|
7992
|
-
targetData.purpose !== 2 /* LimboResolution */) {
|
|
8213
|
+
targetData.purpose !== 2 /* TargetPurpose.LimboResolution */) {
|
|
7993
8214
|
isOnlyLimboTarget = false;
|
|
7994
8215
|
return false;
|
|
7995
8216
|
}
|
|
@@ -8016,8 +8237,8 @@ class WatchChangeAggregator {
|
|
|
8016
8237
|
return;
|
|
8017
8238
|
}
|
|
8018
8239
|
const changeType = this.targetContainsDocument(targetId, document.key)
|
|
8019
|
-
? 2 /* Modified */
|
|
8020
|
-
: 0 /* Added */;
|
|
8240
|
+
? 2 /* ChangeType.Modified */
|
|
8241
|
+
: 0 /* ChangeType.Added */;
|
|
8021
8242
|
const targetState = this.ensureTargetState(targetId);
|
|
8022
8243
|
targetState.addDocumentChange(document.key, changeType);
|
|
8023
8244
|
this.pendingDocumentUpdates = this.pendingDocumentUpdates.insert(document.key, document);
|
|
@@ -8038,7 +8259,7 @@ class WatchChangeAggregator {
|
|
|
8038
8259
|
}
|
|
8039
8260
|
const targetState = this.ensureTargetState(targetId);
|
|
8040
8261
|
if (this.targetContainsDocument(targetId, key)) {
|
|
8041
|
-
targetState.addDocumentChange(key, 1 /* Removed */);
|
|
8262
|
+
targetState.addDocumentChange(key, 1 /* ChangeType.Removed */);
|
|
8042
8263
|
}
|
|
8043
8264
|
else {
|
|
8044
8265
|
// The document may have entered and left the target before we raised a
|
|
@@ -8163,22 +8384,28 @@ function snapshotChangesMap() {
|
|
|
8163
8384
|
*/
|
|
8164
8385
|
const DIRECTIONS = (() => {
|
|
8165
8386
|
const dirs = {};
|
|
8166
|
-
dirs["asc" /* ASCENDING */] = 'ASCENDING';
|
|
8167
|
-
dirs["desc" /* DESCENDING */] = 'DESCENDING';
|
|
8387
|
+
dirs["asc" /* Direction.ASCENDING */] = 'ASCENDING';
|
|
8388
|
+
dirs["desc" /* Direction.DESCENDING */] = 'DESCENDING';
|
|
8168
8389
|
return dirs;
|
|
8169
8390
|
})();
|
|
8170
8391
|
const OPERATORS = (() => {
|
|
8171
8392
|
const ops = {};
|
|
8172
|
-
ops["<" /* LESS_THAN */] = 'LESS_THAN';
|
|
8173
|
-
ops["<=" /* LESS_THAN_OR_EQUAL */] = 'LESS_THAN_OR_EQUAL';
|
|
8174
|
-
ops[">" /* GREATER_THAN */] = 'GREATER_THAN';
|
|
8175
|
-
ops[">=" /* GREATER_THAN_OR_EQUAL */] = 'GREATER_THAN_OR_EQUAL';
|
|
8176
|
-
ops["==" /* EQUAL */] = 'EQUAL';
|
|
8177
|
-
ops["!=" /* NOT_EQUAL */] = 'NOT_EQUAL';
|
|
8178
|
-
ops["array-contains" /* ARRAY_CONTAINS */] = 'ARRAY_CONTAINS';
|
|
8179
|
-
ops["in" /* IN */] = 'IN';
|
|
8180
|
-
ops["not-in" /* NOT_IN */] = 'NOT_IN';
|
|
8181
|
-
ops["array-contains-any" /* ARRAY_CONTAINS_ANY */] = 'ARRAY_CONTAINS_ANY';
|
|
8393
|
+
ops["<" /* Operator.LESS_THAN */] = 'LESS_THAN';
|
|
8394
|
+
ops["<=" /* Operator.LESS_THAN_OR_EQUAL */] = 'LESS_THAN_OR_EQUAL';
|
|
8395
|
+
ops[">" /* Operator.GREATER_THAN */] = 'GREATER_THAN';
|
|
8396
|
+
ops[">=" /* Operator.GREATER_THAN_OR_EQUAL */] = 'GREATER_THAN_OR_EQUAL';
|
|
8397
|
+
ops["==" /* Operator.EQUAL */] = 'EQUAL';
|
|
8398
|
+
ops["!=" /* Operator.NOT_EQUAL */] = 'NOT_EQUAL';
|
|
8399
|
+
ops["array-contains" /* Operator.ARRAY_CONTAINS */] = 'ARRAY_CONTAINS';
|
|
8400
|
+
ops["in" /* Operator.IN */] = 'IN';
|
|
8401
|
+
ops["not-in" /* Operator.NOT_IN */] = 'NOT_IN';
|
|
8402
|
+
ops["array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */] = 'ARRAY_CONTAINS_ANY';
|
|
8403
|
+
return ops;
|
|
8404
|
+
})();
|
|
8405
|
+
const COMPOSITE_OPERATORS = (() => {
|
|
8406
|
+
const ops = {};
|
|
8407
|
+
ops["and" /* CompositeOperator.AND */] = 'AND';
|
|
8408
|
+
ops["or" /* CompositeOperator.OR */] = 'OR';
|
|
8182
8409
|
return ops;
|
|
8183
8410
|
})();
|
|
8184
8411
|
function assertPresent(value, description) {
|
|
@@ -8372,14 +8599,21 @@ function toDocument(serializer, document) {
|
|
|
8372
8599
|
return {
|
|
8373
8600
|
name: toName(serializer, document.key),
|
|
8374
8601
|
fields: document.data.value.mapValue.fields,
|
|
8375
|
-
updateTime: toTimestamp(serializer, document.version.toTimestamp())
|
|
8602
|
+
updateTime: toTimestamp(serializer, document.version.toTimestamp()),
|
|
8603
|
+
createTime: toTimestamp(serializer, document.createTime.toTimestamp())
|
|
8376
8604
|
};
|
|
8377
8605
|
}
|
|
8378
8606
|
function fromDocument(serializer, document, hasCommittedMutations) {
|
|
8379
8607
|
const key = fromName(serializer, document.name);
|
|
8380
8608
|
const version = fromVersion(document.updateTime);
|
|
8609
|
+
// If we read a document from persistence that is missing createTime, it's due
|
|
8610
|
+
// to older SDK versions not storing this information. In such cases, we'll
|
|
8611
|
+
// set the createTime to zero. This can be removed in the long term.
|
|
8612
|
+
const createTime = document.createTime
|
|
8613
|
+
? fromVersion(document.createTime)
|
|
8614
|
+
: SnapshotVersion.min();
|
|
8381
8615
|
const data = new ObjectValue({ mapValue: { fields: document.fields } });
|
|
8382
|
-
const result = MutableDocument.newFoundDocument(key, version, data);
|
|
8616
|
+
const result = MutableDocument.newFoundDocument(key, version, createTime, data);
|
|
8383
8617
|
if (hasCommittedMutations) {
|
|
8384
8618
|
result.setHasCommittedMutations();
|
|
8385
8619
|
}
|
|
@@ -8391,8 +8625,11 @@ function fromFound(serializer, doc) {
|
|
|
8391
8625
|
assertPresent(doc.found.updateTime);
|
|
8392
8626
|
const key = fromName(serializer, doc.found.name);
|
|
8393
8627
|
const version = fromVersion(doc.found.updateTime);
|
|
8628
|
+
const createTime = doc.found.createTime
|
|
8629
|
+
? fromVersion(doc.found.createTime)
|
|
8630
|
+
: SnapshotVersion.min();
|
|
8394
8631
|
const data = new ObjectValue({ mapValue: { fields: doc.found.fields } });
|
|
8395
|
-
return MutableDocument.newFoundDocument(key, version, data);
|
|
8632
|
+
return MutableDocument.newFoundDocument(key, version, createTime, data);
|
|
8396
8633
|
}
|
|
8397
8634
|
function fromMissing(serializer, result) {
|
|
8398
8635
|
hardAssert(!!result.missing);
|
|
@@ -8431,10 +8668,13 @@ function fromWatchChange(serializer, change) {
|
|
|
8431
8668
|
assertPresent(entityChange.document.updateTime);
|
|
8432
8669
|
const key = fromName(serializer, entityChange.document.name);
|
|
8433
8670
|
const version = fromVersion(entityChange.document.updateTime);
|
|
8671
|
+
const createTime = entityChange.document.createTime
|
|
8672
|
+
? fromVersion(entityChange.document.createTime)
|
|
8673
|
+
: SnapshotVersion.min();
|
|
8434
8674
|
const data = new ObjectValue({
|
|
8435
8675
|
mapValue: { fields: entityChange.document.fields }
|
|
8436
8676
|
});
|
|
8437
|
-
const doc = MutableDocument.newFoundDocument(key, version, data);
|
|
8677
|
+
const doc = MutableDocument.newFoundDocument(key, version, createTime, data);
|
|
8438
8678
|
const updatedTargetIds = entityChange.targetIds || [];
|
|
8439
8679
|
const removedTargetIds = entityChange.removedTargetIds || [];
|
|
8440
8680
|
watchChange = new DocumentWatchChange(updatedTargetIds, removedTargetIds, doc.key, doc);
|
|
@@ -8476,19 +8716,19 @@ function fromWatchChange(serializer, change) {
|
|
|
8476
8716
|
}
|
|
8477
8717
|
function fromWatchTargetChangeState(state) {
|
|
8478
8718
|
if (state === 'NO_CHANGE') {
|
|
8479
|
-
return 0 /* NoChange */;
|
|
8719
|
+
return 0 /* WatchTargetChangeState.NoChange */;
|
|
8480
8720
|
}
|
|
8481
8721
|
else if (state === 'ADD') {
|
|
8482
|
-
return 1 /* Added */;
|
|
8722
|
+
return 1 /* WatchTargetChangeState.Added */;
|
|
8483
8723
|
}
|
|
8484
8724
|
else if (state === 'REMOVE') {
|
|
8485
|
-
return 2 /* Removed */;
|
|
8725
|
+
return 2 /* WatchTargetChangeState.Removed */;
|
|
8486
8726
|
}
|
|
8487
8727
|
else if (state === 'CURRENT') {
|
|
8488
|
-
return 3 /* Current */;
|
|
8728
|
+
return 3 /* WatchTargetChangeState.Current */;
|
|
8489
8729
|
}
|
|
8490
8730
|
else if (state === 'RESET') {
|
|
8491
|
-
return 4 /* Reset */;
|
|
8731
|
+
return 4 /* WatchTargetChangeState.Reset */;
|
|
8492
8732
|
}
|
|
8493
8733
|
else {
|
|
8494
8734
|
return fail();
|
|
@@ -8706,7 +8946,7 @@ function toQueryTarget(serializer, target) {
|
|
|
8706
8946
|
result.parent = toQueryPath(serializer, path.popLast());
|
|
8707
8947
|
result.structuredQuery.from = [{ collectionId: path.lastSegment() }];
|
|
8708
8948
|
}
|
|
8709
|
-
const where =
|
|
8949
|
+
const where = toFilters(target.filters);
|
|
8710
8950
|
if (where) {
|
|
8711
8951
|
result.structuredQuery.where = where;
|
|
8712
8952
|
}
|
|
@@ -8758,7 +8998,7 @@ function convertQueryTargetToQuery(target) {
|
|
|
8758
8998
|
}
|
|
8759
8999
|
let filterBy = [];
|
|
8760
9000
|
if (query.where) {
|
|
8761
|
-
filterBy =
|
|
9001
|
+
filterBy = fromFilters(query.where);
|
|
8762
9002
|
}
|
|
8763
9003
|
let orderBy = [];
|
|
8764
9004
|
if (query.orderBy) {
|
|
@@ -8776,7 +9016,7 @@ function convertQueryTargetToQuery(target) {
|
|
|
8776
9016
|
if (query.endAt) {
|
|
8777
9017
|
endAt = fromEndAtCursor(query.endAt);
|
|
8778
9018
|
}
|
|
8779
|
-
return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
|
|
9019
|
+
return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* LimitType.First */, startAt, endAt);
|
|
8780
9020
|
}
|
|
8781
9021
|
function fromQueryTarget(target) {
|
|
8782
9022
|
return queryToTarget(convertQueryTargetToQuery(target));
|
|
@@ -8794,11 +9034,11 @@ function toListenRequestLabels(serializer, targetData) {
|
|
|
8794
9034
|
}
|
|
8795
9035
|
function toLabel(serializer, purpose) {
|
|
8796
9036
|
switch (purpose) {
|
|
8797
|
-
case 0 /* Listen */:
|
|
9037
|
+
case 0 /* TargetPurpose.Listen */:
|
|
8798
9038
|
return null;
|
|
8799
|
-
case 1 /* ExistenceFilterMismatch */:
|
|
9039
|
+
case 1 /* TargetPurpose.ExistenceFilterMismatch */:
|
|
8800
9040
|
return 'existence-filter-mismatch';
|
|
8801
|
-
case 2 /* LimboResolution */:
|
|
9041
|
+
case 2 /* TargetPurpose.LimboResolution */:
|
|
8802
9042
|
return 'limbo-document';
|
|
8803
9043
|
default:
|
|
8804
9044
|
return fail();
|
|
@@ -8825,32 +9065,29 @@ function toTarget(serializer, targetData) {
|
|
|
8825
9065
|
}
|
|
8826
9066
|
return result;
|
|
8827
9067
|
}
|
|
8828
|
-
function
|
|
9068
|
+
function toFilters(filters) {
|
|
8829
9069
|
if (filters.length === 0) {
|
|
8830
9070
|
return;
|
|
8831
9071
|
}
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
9072
|
+
return toFilter(CompositeFilter.create(filters, "and" /* CompositeOperator.AND */));
|
|
9073
|
+
}
|
|
9074
|
+
function fromFilters(filter) {
|
|
9075
|
+
const result = fromFilter(filter);
|
|
9076
|
+
if (result instanceof CompositeFilter &&
|
|
9077
|
+
compositeFilterIsFlatConjunction(result)) {
|
|
9078
|
+
return result.getFilters();
|
|
8837
9079
|
}
|
|
8838
|
-
return
|
|
9080
|
+
return [result];
|
|
8839
9081
|
}
|
|
8840
9082
|
function fromFilter(filter) {
|
|
8841
|
-
if (
|
|
8842
|
-
return
|
|
8843
|
-
}
|
|
8844
|
-
else if (filter.unaryFilter !== undefined) {
|
|
8845
|
-
return [fromUnaryFilter(filter)];
|
|
9083
|
+
if (filter.unaryFilter !== undefined) {
|
|
9084
|
+
return fromUnaryFilter(filter);
|
|
8846
9085
|
}
|
|
8847
9086
|
else if (filter.fieldFilter !== undefined) {
|
|
8848
|
-
return
|
|
9087
|
+
return fromFieldFilter(filter);
|
|
8849
9088
|
}
|
|
8850
9089
|
else if (filter.compositeFilter !== undefined) {
|
|
8851
|
-
return filter
|
|
8852
|
-
.filters.map(f => fromFilter(f))
|
|
8853
|
-
.reduce((accum, current) => accum.concat(current));
|
|
9090
|
+
return fromCompositeFilter(filter);
|
|
8854
9091
|
}
|
|
8855
9092
|
else {
|
|
8856
9093
|
return fail();
|
|
@@ -8895,9 +9132,9 @@ function toDirection(dir) {
|
|
|
8895
9132
|
function fromDirection(dir) {
|
|
8896
9133
|
switch (dir) {
|
|
8897
9134
|
case 'ASCENDING':
|
|
8898
|
-
return "asc" /* ASCENDING */;
|
|
9135
|
+
return "asc" /* Direction.ASCENDING */;
|
|
8899
9136
|
case 'DESCENDING':
|
|
8900
|
-
return "desc" /* DESCENDING */;
|
|
9137
|
+
return "desc" /* Direction.DESCENDING */;
|
|
8901
9138
|
default:
|
|
8902
9139
|
return undefined;
|
|
8903
9140
|
}
|
|
@@ -8906,34 +9143,47 @@ function fromDirection(dir) {
|
|
|
8906
9143
|
function toOperatorName(op) {
|
|
8907
9144
|
return OPERATORS[op];
|
|
8908
9145
|
}
|
|
9146
|
+
function toCompositeOperatorName(op) {
|
|
9147
|
+
return COMPOSITE_OPERATORS[op];
|
|
9148
|
+
}
|
|
8909
9149
|
function fromOperatorName(op) {
|
|
8910
9150
|
switch (op) {
|
|
8911
9151
|
case 'EQUAL':
|
|
8912
|
-
return "==" /* EQUAL */;
|
|
9152
|
+
return "==" /* Operator.EQUAL */;
|
|
8913
9153
|
case 'NOT_EQUAL':
|
|
8914
|
-
return "!=" /* NOT_EQUAL */;
|
|
9154
|
+
return "!=" /* Operator.NOT_EQUAL */;
|
|
8915
9155
|
case 'GREATER_THAN':
|
|
8916
|
-
return ">" /* GREATER_THAN */;
|
|
9156
|
+
return ">" /* Operator.GREATER_THAN */;
|
|
8917
9157
|
case 'GREATER_THAN_OR_EQUAL':
|
|
8918
|
-
return ">=" /* GREATER_THAN_OR_EQUAL */;
|
|
9158
|
+
return ">=" /* Operator.GREATER_THAN_OR_EQUAL */;
|
|
8919
9159
|
case 'LESS_THAN':
|
|
8920
|
-
return "<" /* LESS_THAN */;
|
|
9160
|
+
return "<" /* Operator.LESS_THAN */;
|
|
8921
9161
|
case 'LESS_THAN_OR_EQUAL':
|
|
8922
|
-
return "<=" /* LESS_THAN_OR_EQUAL */;
|
|
9162
|
+
return "<=" /* Operator.LESS_THAN_OR_EQUAL */;
|
|
8923
9163
|
case 'ARRAY_CONTAINS':
|
|
8924
|
-
return "array-contains" /* ARRAY_CONTAINS */;
|
|
9164
|
+
return "array-contains" /* Operator.ARRAY_CONTAINS */;
|
|
8925
9165
|
case 'IN':
|
|
8926
|
-
return "in" /* IN */;
|
|
9166
|
+
return "in" /* Operator.IN */;
|
|
8927
9167
|
case 'NOT_IN':
|
|
8928
|
-
return "not-in" /* NOT_IN */;
|
|
9168
|
+
return "not-in" /* Operator.NOT_IN */;
|
|
8929
9169
|
case 'ARRAY_CONTAINS_ANY':
|
|
8930
|
-
return "array-contains-any" /* ARRAY_CONTAINS_ANY */;
|
|
9170
|
+
return "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */;
|
|
8931
9171
|
case 'OPERATOR_UNSPECIFIED':
|
|
8932
9172
|
return fail();
|
|
8933
9173
|
default:
|
|
8934
9174
|
return fail();
|
|
8935
9175
|
}
|
|
8936
9176
|
}
|
|
9177
|
+
function fromCompositeOperatorName(op) {
|
|
9178
|
+
switch (op) {
|
|
9179
|
+
case 'AND':
|
|
9180
|
+
return "and" /* CompositeOperator.AND */;
|
|
9181
|
+
case 'OR':
|
|
9182
|
+
return "or" /* CompositeOperator.OR */;
|
|
9183
|
+
default:
|
|
9184
|
+
return fail();
|
|
9185
|
+
}
|
|
9186
|
+
}
|
|
8937
9187
|
function toFieldPathReference(path) {
|
|
8938
9188
|
return { fieldPath: path.canonicalString() };
|
|
8939
9189
|
}
|
|
@@ -8950,12 +9200,32 @@ function toPropertyOrder(orderBy) {
|
|
|
8950
9200
|
function fromPropertyOrder(orderBy) {
|
|
8951
9201
|
return new OrderBy(fromFieldPathReference(orderBy.field), fromDirection(orderBy.direction));
|
|
8952
9202
|
}
|
|
8953
|
-
function fromFieldFilter(filter) {
|
|
8954
|
-
return FieldFilter.create(fromFieldPathReference(filter.fieldFilter.field), fromOperatorName(filter.fieldFilter.op), filter.fieldFilter.value);
|
|
8955
|
-
}
|
|
8956
9203
|
// visible for testing
|
|
9204
|
+
function toFilter(filter) {
|
|
9205
|
+
if (filter instanceof FieldFilter) {
|
|
9206
|
+
return toUnaryOrFieldFilter(filter);
|
|
9207
|
+
}
|
|
9208
|
+
else if (filter instanceof CompositeFilter) {
|
|
9209
|
+
return toCompositeFilter(filter);
|
|
9210
|
+
}
|
|
9211
|
+
else {
|
|
9212
|
+
return fail();
|
|
9213
|
+
}
|
|
9214
|
+
}
|
|
9215
|
+
function toCompositeFilter(filter) {
|
|
9216
|
+
const protos = filter.getFilters().map(filter => toFilter(filter));
|
|
9217
|
+
if (protos.length === 1) {
|
|
9218
|
+
return protos[0];
|
|
9219
|
+
}
|
|
9220
|
+
return {
|
|
9221
|
+
compositeFilter: {
|
|
9222
|
+
op: toCompositeOperatorName(filter.op),
|
|
9223
|
+
filters: protos
|
|
9224
|
+
}
|
|
9225
|
+
};
|
|
9226
|
+
}
|
|
8957
9227
|
function toUnaryOrFieldFilter(filter) {
|
|
8958
|
-
if (filter.op === "==" /* EQUAL */) {
|
|
9228
|
+
if (filter.op === "==" /* Operator.EQUAL */) {
|
|
8959
9229
|
if (isNanValue(filter.value)) {
|
|
8960
9230
|
return {
|
|
8961
9231
|
unaryFilter: {
|
|
@@ -8973,7 +9243,7 @@ function toUnaryOrFieldFilter(filter) {
|
|
|
8973
9243
|
};
|
|
8974
9244
|
}
|
|
8975
9245
|
}
|
|
8976
|
-
else if (filter.op === "!=" /* NOT_EQUAL */) {
|
|
9246
|
+
else if (filter.op === "!=" /* Operator.NOT_EQUAL */) {
|
|
8977
9247
|
if (isNanValue(filter.value)) {
|
|
8978
9248
|
return {
|
|
8979
9249
|
unaryFilter: {
|
|
@@ -9003,22 +9273,22 @@ function fromUnaryFilter(filter) {
|
|
|
9003
9273
|
switch (filter.unaryFilter.op) {
|
|
9004
9274
|
case 'IS_NAN':
|
|
9005
9275
|
const nanField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9006
|
-
return FieldFilter.create(nanField, "==" /* EQUAL */, {
|
|
9276
|
+
return FieldFilter.create(nanField, "==" /* Operator.EQUAL */, {
|
|
9007
9277
|
doubleValue: NaN
|
|
9008
9278
|
});
|
|
9009
9279
|
case 'IS_NULL':
|
|
9010
9280
|
const nullField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9011
|
-
return FieldFilter.create(nullField, "==" /* EQUAL */, {
|
|
9281
|
+
return FieldFilter.create(nullField, "==" /* Operator.EQUAL */, {
|
|
9012
9282
|
nullValue: 'NULL_VALUE'
|
|
9013
9283
|
});
|
|
9014
9284
|
case 'IS_NOT_NAN':
|
|
9015
9285
|
const notNanField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9016
|
-
return FieldFilter.create(notNanField, "!=" /* NOT_EQUAL */, {
|
|
9286
|
+
return FieldFilter.create(notNanField, "!=" /* Operator.NOT_EQUAL */, {
|
|
9017
9287
|
doubleValue: NaN
|
|
9018
9288
|
});
|
|
9019
9289
|
case 'IS_NOT_NULL':
|
|
9020
9290
|
const notNullField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9021
|
-
return FieldFilter.create(notNullField, "!=" /* NOT_EQUAL */, {
|
|
9291
|
+
return FieldFilter.create(notNullField, "!=" /* Operator.NOT_EQUAL */, {
|
|
9022
9292
|
nullValue: 'NULL_VALUE'
|
|
9023
9293
|
});
|
|
9024
9294
|
case 'OPERATOR_UNSPECIFIED':
|
|
@@ -9027,6 +9297,12 @@ function fromUnaryFilter(filter) {
|
|
|
9027
9297
|
return fail();
|
|
9028
9298
|
}
|
|
9029
9299
|
}
|
|
9300
|
+
function fromFieldFilter(filter) {
|
|
9301
|
+
return FieldFilter.create(fromFieldPathReference(filter.fieldFilter.field), fromOperatorName(filter.fieldFilter.op), filter.fieldFilter.value);
|
|
9302
|
+
}
|
|
9303
|
+
function fromCompositeFilter(filter) {
|
|
9304
|
+
return CompositeFilter.create(filter.compositeFilter.filters.map(filter => fromFilter(filter)), fromCompositeOperatorName(filter.compositeFilter.op));
|
|
9305
|
+
}
|
|
9030
9306
|
function toDocumentMask(fieldMask) {
|
|
9031
9307
|
const canonicalFields = [];
|
|
9032
9308
|
fieldMask.fields.forEach(field => canonicalFields.push(field.canonicalString()));
|
|
@@ -9266,7 +9542,7 @@ function fromDbTarget(dbTarget) {
|
|
|
9266
9542
|
else {
|
|
9267
9543
|
target = fromQueryTarget(dbTarget.query);
|
|
9268
9544
|
}
|
|
9269
|
-
return new TargetData(target, dbTarget.targetId, 0 /* Listen */, dbTarget.lastListenSequenceNumber, version, lastLimboFreeSnapshotVersion, ByteString.fromBase64String(dbTarget.resumeToken));
|
|
9545
|
+
return new TargetData(target, dbTarget.targetId, 0 /* TargetPurpose.Listen */, dbTarget.lastListenSequenceNumber, version, lastLimboFreeSnapshotVersion, ByteString.fromBase64String(dbTarget.resumeToken));
|
|
9270
9546
|
}
|
|
9271
9547
|
/** Encodes TargetData into a DbTarget for storage locally. */
|
|
9272
9548
|
function toDbTarget(localSerializer, targetData) {
|
|
@@ -9343,7 +9619,7 @@ function fromBundledQuery(bundledQuery) {
|
|
|
9343
9619
|
structuredQuery: bundledQuery.structuredQuery
|
|
9344
9620
|
});
|
|
9345
9621
|
if (bundledQuery.limitType === 'LAST') {
|
|
9346
|
-
return queryWithLimit(query, query.limit, "L" /* Last */);
|
|
9622
|
+
return queryWithLimit(query, query.limit, "L" /* LimitType.Last */);
|
|
9347
9623
|
}
|
|
9348
9624
|
return query;
|
|
9349
9625
|
}
|
|
@@ -10118,7 +10394,7 @@ class IndexByteEncoder {
|
|
|
10118
10394
|
this.orderedCode.seed(encodedBytes);
|
|
10119
10395
|
}
|
|
10120
10396
|
forKind(kind) {
|
|
10121
|
-
return kind === 0 /* ASCENDING */ ? this.ascending : this.descending;
|
|
10397
|
+
return kind === 0 /* IndexKind.ASCENDING */ ? this.ascending : this.descending;
|
|
10122
10398
|
}
|
|
10123
10399
|
encodedBytes() {
|
|
10124
10400
|
return this.orderedCode.encodedBytes();
|
|
@@ -10273,6 +10549,7 @@ class TargetIndexMatcher {
|
|
|
10273
10549
|
* omitted.
|
|
10274
10550
|
*/
|
|
10275
10551
|
servedByIndex(index) {
|
|
10552
|
+
hardAssert(index.collectionGroup === this.collectionId);
|
|
10276
10553
|
// If there is an array element, find a matching filter.
|
|
10277
10554
|
const arraySegment = fieldIndexGetArraySegment(index);
|
|
10278
10555
|
if (arraySegment !== undefined &&
|
|
@@ -10336,19 +10613,268 @@ class TargetIndexMatcher {
|
|
|
10336
10613
|
if (filter === undefined || !filter.field.isEqual(segment.fieldPath)) {
|
|
10337
10614
|
return false;
|
|
10338
10615
|
}
|
|
10339
|
-
const isArrayOperator = filter.op === "array-contains" /* ARRAY_CONTAINS */ ||
|
|
10340
|
-
filter.op === "array-contains-any" /* ARRAY_CONTAINS_ANY */;
|
|
10341
|
-
return (segment.kind === 2 /* CONTAINS */) === isArrayOperator;
|
|
10616
|
+
const isArrayOperator = filter.op === "array-contains" /* Operator.ARRAY_CONTAINS */ ||
|
|
10617
|
+
filter.op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */;
|
|
10618
|
+
return (segment.kind === 2 /* IndexKind.CONTAINS */) === isArrayOperator;
|
|
10342
10619
|
}
|
|
10343
10620
|
matchesOrderBy(orderBy, segment) {
|
|
10344
10621
|
if (!orderBy.field.isEqual(segment.fieldPath)) {
|
|
10345
10622
|
return false;
|
|
10346
10623
|
}
|
|
10347
|
-
return ((segment.kind === 0 /* ASCENDING */ &&
|
|
10348
|
-
orderBy.dir === "asc" /* ASCENDING */) ||
|
|
10349
|
-
(segment.kind === 1 /* DESCENDING */ &&
|
|
10350
|
-
orderBy.dir === "desc" /* DESCENDING */));
|
|
10624
|
+
return ((segment.kind === 0 /* IndexKind.ASCENDING */ &&
|
|
10625
|
+
orderBy.dir === "asc" /* Direction.ASCENDING */) ||
|
|
10626
|
+
(segment.kind === 1 /* IndexKind.DESCENDING */ &&
|
|
10627
|
+
orderBy.dir === "desc" /* Direction.DESCENDING */));
|
|
10628
|
+
}
|
|
10629
|
+
}
|
|
10630
|
+
|
|
10631
|
+
/**
|
|
10632
|
+
* @license
|
|
10633
|
+
* Copyright 2022 Google LLC
|
|
10634
|
+
*
|
|
10635
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10636
|
+
* you may not use this file except in compliance with the License.
|
|
10637
|
+
* You may obtain a copy of the License at
|
|
10638
|
+
*
|
|
10639
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10640
|
+
*
|
|
10641
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10642
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
10643
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10644
|
+
* See the License for the specific language governing permissions and
|
|
10645
|
+
* limitations under the License.
|
|
10646
|
+
*/
|
|
10647
|
+
/**
|
|
10648
|
+
* Provides utility functions that help with boolean logic transformations needed for handling
|
|
10649
|
+
* complex filters used in queries.
|
|
10650
|
+
*/
|
|
10651
|
+
/**
|
|
10652
|
+
* The `in` filter is only a syntactic sugar over a disjunction of equalities. For instance: `a in
|
|
10653
|
+
* [1,2,3]` is in fact `a==1 || a==2 || a==3`. This method expands any `in` filter in the given
|
|
10654
|
+
* input into a disjunction of equality filters and returns the expanded filter.
|
|
10655
|
+
*/
|
|
10656
|
+
function computeInExpansion(filter) {
|
|
10657
|
+
var _a, _b;
|
|
10658
|
+
hardAssert(filter instanceof FieldFilter || filter instanceof CompositeFilter);
|
|
10659
|
+
if (filter instanceof FieldFilter) {
|
|
10660
|
+
if (filter instanceof InFilter) {
|
|
10661
|
+
const expandedFilters = ((_b = (_a = filter.value.arrayValue) === null || _a === void 0 ? void 0 : _a.values) === null || _b === void 0 ? void 0 : _b.map(value => FieldFilter.create(filter.field, "==" /* Operator.EQUAL */, value))) || [];
|
|
10662
|
+
return CompositeFilter.create(expandedFilters, "or" /* CompositeOperator.OR */);
|
|
10663
|
+
}
|
|
10664
|
+
else {
|
|
10665
|
+
// We have reached other kinds of field filters.
|
|
10666
|
+
return filter;
|
|
10667
|
+
}
|
|
10668
|
+
}
|
|
10669
|
+
// We have a composite filter.
|
|
10670
|
+
const expandedFilters = filter.filters.map(subfilter => computeInExpansion(subfilter));
|
|
10671
|
+
return CompositeFilter.create(expandedFilters, filter.op);
|
|
10672
|
+
}
|
|
10673
|
+
/**
|
|
10674
|
+
* Given a composite filter, returns the list of terms in its disjunctive normal form.
|
|
10675
|
+
*
|
|
10676
|
+
* <p>Each element in the return value is one term of the resulting DNF. For instance: For the
|
|
10677
|
+
* input: (A || B) && C, the DNF form is: (A && C) || (B && C), and the return value is a list
|
|
10678
|
+
* with two elements: a composite filter that performs (A && C), and a composite filter that
|
|
10679
|
+
* performs (B && C).
|
|
10680
|
+
*
|
|
10681
|
+
* @param filter the composite filter to calculate DNF transform for.
|
|
10682
|
+
* @return the terms in the DNF transform.
|
|
10683
|
+
*/
|
|
10684
|
+
function getDnfTerms(filter) {
|
|
10685
|
+
if (filter.getFilters().length === 0) {
|
|
10686
|
+
return [];
|
|
10687
|
+
}
|
|
10688
|
+
const result = computeDistributedNormalForm(computeInExpansion(filter));
|
|
10689
|
+
hardAssert(isDisjunctiveNormalForm(result));
|
|
10690
|
+
if (isSingleFieldFilter(result) || isFlatConjunction(result)) {
|
|
10691
|
+
return [result];
|
|
10692
|
+
}
|
|
10693
|
+
return result.getFilters();
|
|
10694
|
+
}
|
|
10695
|
+
/** Returns true if the given filter is a single field filter. e.g. (a == 10). */
|
|
10696
|
+
function isSingleFieldFilter(filter) {
|
|
10697
|
+
return filter instanceof FieldFilter;
|
|
10698
|
+
}
|
|
10699
|
+
/**
|
|
10700
|
+
* Returns true if the given filter is the conjunction of one or more field filters. e.g. (a == 10
|
|
10701
|
+
* && b == 20)
|
|
10702
|
+
*/
|
|
10703
|
+
function isFlatConjunction(filter) {
|
|
10704
|
+
return (filter instanceof CompositeFilter &&
|
|
10705
|
+
compositeFilterIsFlatConjunction(filter));
|
|
10706
|
+
}
|
|
10707
|
+
/**
|
|
10708
|
+
* Returns whether or not the given filter is in disjunctive normal form (DNF).
|
|
10709
|
+
*
|
|
10710
|
+
* <p>In boolean logic, a disjunctive normal form (DNF) is a canonical normal form of a logical
|
|
10711
|
+
* formula consisting of a disjunction of conjunctions; it can also be described as an OR of ANDs.
|
|
10712
|
+
*
|
|
10713
|
+
* <p>For more info, visit: https://en.wikipedia.org/wiki/Disjunctive_normal_form
|
|
10714
|
+
*/
|
|
10715
|
+
function isDisjunctiveNormalForm(filter) {
|
|
10716
|
+
return (isSingleFieldFilter(filter) ||
|
|
10717
|
+
isFlatConjunction(filter) ||
|
|
10718
|
+
isDisjunctionOfFieldFiltersAndFlatConjunctions(filter));
|
|
10719
|
+
}
|
|
10720
|
+
/**
|
|
10721
|
+
* Returns true if the given filter is the disjunction of one or more "flat conjunctions" and
|
|
10722
|
+
* field filters. e.g. (a == 10) || (b==20 && c==30)
|
|
10723
|
+
*/
|
|
10724
|
+
function isDisjunctionOfFieldFiltersAndFlatConjunctions(filter) {
|
|
10725
|
+
if (filter instanceof CompositeFilter) {
|
|
10726
|
+
if (compositeFilterIsDisjunction(filter)) {
|
|
10727
|
+
for (const subFilter of filter.getFilters()) {
|
|
10728
|
+
if (!isSingleFieldFilter(subFilter) && !isFlatConjunction(subFilter)) {
|
|
10729
|
+
return false;
|
|
10730
|
+
}
|
|
10731
|
+
}
|
|
10732
|
+
return true;
|
|
10733
|
+
}
|
|
10734
|
+
}
|
|
10735
|
+
return false;
|
|
10736
|
+
}
|
|
10737
|
+
function computeDistributedNormalForm(filter) {
|
|
10738
|
+
hardAssert(filter instanceof FieldFilter || filter instanceof CompositeFilter);
|
|
10739
|
+
if (filter instanceof FieldFilter) {
|
|
10740
|
+
return filter;
|
|
10741
|
+
}
|
|
10742
|
+
if (filter.filters.length === 1) {
|
|
10743
|
+
return computeDistributedNormalForm(filter.filters[0]);
|
|
10744
|
+
}
|
|
10745
|
+
// Compute DNF for each of the subfilters first
|
|
10746
|
+
const result = filter.filters.map(subfilter => computeDistributedNormalForm(subfilter));
|
|
10747
|
+
let newFilter = CompositeFilter.create(result, filter.op);
|
|
10748
|
+
newFilter = applyAssociation(newFilter);
|
|
10749
|
+
if (isDisjunctiveNormalForm(newFilter)) {
|
|
10750
|
+
return newFilter;
|
|
10751
|
+
}
|
|
10752
|
+
hardAssert(newFilter instanceof CompositeFilter);
|
|
10753
|
+
hardAssert(compositeFilterIsConjunction(newFilter));
|
|
10754
|
+
hardAssert(newFilter.filters.length > 1);
|
|
10755
|
+
return newFilter.filters.reduce((runningResult, filter) => applyDistribution(runningResult, filter));
|
|
10756
|
+
}
|
|
10757
|
+
function applyDistribution(lhs, rhs) {
|
|
10758
|
+
hardAssert(lhs instanceof FieldFilter || lhs instanceof CompositeFilter);
|
|
10759
|
+
hardAssert(rhs instanceof FieldFilter || rhs instanceof CompositeFilter);
|
|
10760
|
+
let result;
|
|
10761
|
+
if (lhs instanceof FieldFilter) {
|
|
10762
|
+
if (rhs instanceof FieldFilter) {
|
|
10763
|
+
// FieldFilter FieldFilter
|
|
10764
|
+
result = applyDistributionFieldFilters(lhs, rhs);
|
|
10765
|
+
}
|
|
10766
|
+
else {
|
|
10767
|
+
// FieldFilter CompositeFilter
|
|
10768
|
+
result = applyDistributionFieldAndCompositeFilters(lhs, rhs);
|
|
10769
|
+
}
|
|
10770
|
+
}
|
|
10771
|
+
else {
|
|
10772
|
+
if (rhs instanceof FieldFilter) {
|
|
10773
|
+
// CompositeFilter FieldFilter
|
|
10774
|
+
result = applyDistributionFieldAndCompositeFilters(rhs, lhs);
|
|
10775
|
+
}
|
|
10776
|
+
else {
|
|
10777
|
+
// CompositeFilter CompositeFilter
|
|
10778
|
+
result = applyDistributionCompositeFilters(lhs, rhs);
|
|
10779
|
+
}
|
|
10780
|
+
}
|
|
10781
|
+
return applyAssociation(result);
|
|
10782
|
+
}
|
|
10783
|
+
function applyDistributionFieldFilters(lhs, rhs) {
|
|
10784
|
+
// Conjunction distribution for two field filters is the conjunction of them.
|
|
10785
|
+
return CompositeFilter.create([lhs, rhs], "and" /* CompositeOperator.AND */);
|
|
10786
|
+
}
|
|
10787
|
+
function applyDistributionCompositeFilters(lhs, rhs) {
|
|
10788
|
+
hardAssert(lhs.filters.length > 0 && rhs.filters.length > 0);
|
|
10789
|
+
// There are four cases:
|
|
10790
|
+
// (A & B) & (C & D) --> (A & B & C & D)
|
|
10791
|
+
// (A & B) & (C | D) --> (A & B & C) | (A & B & D)
|
|
10792
|
+
// (A | B) & (C & D) --> (C & D & A) | (C & D & B)
|
|
10793
|
+
// (A | B) & (C | D) --> (A & C) | (A & D) | (B & C) | (B & D)
|
|
10794
|
+
// Case 1 is a merge.
|
|
10795
|
+
if (compositeFilterIsConjunction(lhs) && compositeFilterIsConjunction(rhs)) {
|
|
10796
|
+
return compositeFilterWithAddedFilters(lhs, rhs.getFilters());
|
|
10797
|
+
}
|
|
10798
|
+
// Case 2,3,4 all have at least one side (lhs or rhs) that is a disjunction. In all three cases
|
|
10799
|
+
// we should take each element of the disjunction and distribute it over the other side, and
|
|
10800
|
+
// return the disjunction of the distribution results.
|
|
10801
|
+
const disjunctionSide = compositeFilterIsDisjunction(lhs) ? lhs : rhs;
|
|
10802
|
+
const otherSide = compositeFilterIsDisjunction(lhs) ? rhs : lhs;
|
|
10803
|
+
const results = disjunctionSide.filters.map(subfilter => applyDistribution(subfilter, otherSide));
|
|
10804
|
+
return CompositeFilter.create(results, "or" /* CompositeOperator.OR */);
|
|
10805
|
+
}
|
|
10806
|
+
function applyDistributionFieldAndCompositeFilters(fieldFilter, compositeFilter) {
|
|
10807
|
+
// There are two cases:
|
|
10808
|
+
// A & (B & C) --> (A & B & C)
|
|
10809
|
+
// A & (B | C) --> (A & B) | (A & C)
|
|
10810
|
+
if (compositeFilterIsConjunction(compositeFilter)) {
|
|
10811
|
+
// Case 1
|
|
10812
|
+
return compositeFilterWithAddedFilters(compositeFilter, fieldFilter.getFilters());
|
|
10813
|
+
}
|
|
10814
|
+
else {
|
|
10815
|
+
// Case 2
|
|
10816
|
+
const newFilters = compositeFilter.filters.map(subfilter => applyDistribution(fieldFilter, subfilter));
|
|
10817
|
+
return CompositeFilter.create(newFilters, "or" /* CompositeOperator.OR */);
|
|
10818
|
+
}
|
|
10819
|
+
}
|
|
10820
|
+
/**
|
|
10821
|
+
* Applies the associativity property to the given filter and returns the resulting filter.
|
|
10822
|
+
*
|
|
10823
|
+
* <ul>
|
|
10824
|
+
* <li>A | (B | C) == (A | B) | C == (A | B | C)
|
|
10825
|
+
* <li>A & (B & C) == (A & B) & C == (A & B & C)
|
|
10826
|
+
* </ul>
|
|
10827
|
+
*
|
|
10828
|
+
* <p>For more info, visit: https://en.wikipedia.org/wiki/Associative_property#Propositional_logic
|
|
10829
|
+
*/
|
|
10830
|
+
function applyAssociation(filter) {
|
|
10831
|
+
hardAssert(filter instanceof FieldFilter || filter instanceof CompositeFilter);
|
|
10832
|
+
if (filter instanceof FieldFilter) {
|
|
10833
|
+
return filter;
|
|
10834
|
+
}
|
|
10835
|
+
const filters = filter.getFilters();
|
|
10836
|
+
// If the composite filter only contains 1 filter, apply associativity to it.
|
|
10837
|
+
if (filters.length === 1) {
|
|
10838
|
+
return applyAssociation(filters[0]);
|
|
10839
|
+
}
|
|
10840
|
+
// Associativity applied to a flat composite filter results is itself.
|
|
10841
|
+
if (compositeFilterIsFlat(filter)) {
|
|
10842
|
+
return filter;
|
|
10843
|
+
}
|
|
10844
|
+
// First apply associativity to all subfilters. This will in turn recursively apply
|
|
10845
|
+
// associativity to all nested composite filters and field filters.
|
|
10846
|
+
const updatedFilters = filters.map(subfilter => applyAssociation(subfilter));
|
|
10847
|
+
// For composite subfilters that perform the same kind of logical operation as `compositeFilter`
|
|
10848
|
+
// take out their filters and add them to `compositeFilter`. For example:
|
|
10849
|
+
// compositeFilter = (A | (B | C | D))
|
|
10850
|
+
// compositeSubfilter = (B | C | D)
|
|
10851
|
+
// Result: (A | B | C | D)
|
|
10852
|
+
// Note that the `compositeSubfilter` has been eliminated, and its filters (B, C, D) have been
|
|
10853
|
+
// added to the top-level "compositeFilter".
|
|
10854
|
+
const newSubfilters = [];
|
|
10855
|
+
updatedFilters.forEach(subfilter => {
|
|
10856
|
+
if (subfilter instanceof FieldFilter) {
|
|
10857
|
+
newSubfilters.push(subfilter);
|
|
10858
|
+
}
|
|
10859
|
+
else if (subfilter instanceof CompositeFilter) {
|
|
10860
|
+
if (subfilter.op === filter.op) {
|
|
10861
|
+
// compositeFilter: (A | (B | C))
|
|
10862
|
+
// compositeSubfilter: (B | C)
|
|
10863
|
+
// Result: (A | B | C)
|
|
10864
|
+
newSubfilters.push(...subfilter.filters);
|
|
10865
|
+
}
|
|
10866
|
+
else {
|
|
10867
|
+
// compositeFilter: (A | (B & C))
|
|
10868
|
+
// compositeSubfilter: (B & C)
|
|
10869
|
+
// Result: (A | (B & C))
|
|
10870
|
+
newSubfilters.push(subfilter);
|
|
10871
|
+
}
|
|
10872
|
+
}
|
|
10873
|
+
});
|
|
10874
|
+
if (newSubfilters.length === 1) {
|
|
10875
|
+
return newSubfilters[0];
|
|
10351
10876
|
}
|
|
10877
|
+
return CompositeFilter.create(newSubfilters, filter.op);
|
|
10352
10878
|
}
|
|
10353
10879
|
|
|
10354
10880
|
/**
|
|
@@ -10395,7 +10921,7 @@ class MemoryIndexManager {
|
|
|
10395
10921
|
}
|
|
10396
10922
|
getIndexType(transaction, target) {
|
|
10397
10923
|
// Field indices are not supported with memory persistence.
|
|
10398
|
-
return PersistencePromise.resolve(0 /* NONE */);
|
|
10924
|
+
return PersistencePromise.resolve(0 /* IndexType.NONE */);
|
|
10399
10925
|
}
|
|
10400
10926
|
getFieldIndexes(transaction, collectionGroup) {
|
|
10401
10927
|
// Field indices are not supported with memory persistence.
|
|
@@ -10618,8 +11144,14 @@ class IndexedDbIndexManager {
|
|
|
10618
11144
|
if (subTargets) {
|
|
10619
11145
|
return subTargets;
|
|
10620
11146
|
}
|
|
10621
|
-
|
|
10622
|
-
|
|
11147
|
+
if (target.filters.length === 0) {
|
|
11148
|
+
subTargets = [target];
|
|
11149
|
+
}
|
|
11150
|
+
else {
|
|
11151
|
+
// There is an implicit AND operation between all the filters stored in the target
|
|
11152
|
+
const dnf = getDnfTerms(CompositeFilter.create(target.filters, "and" /* CompositeOperator.AND */));
|
|
11153
|
+
subTargets = dnf.map(term => newTarget(target.path, target.collectionGroup, target.orderBy, term.getFilters(), target.limit, target.startAt, target.endAt));
|
|
11154
|
+
}
|
|
10623
11155
|
this.targetToDnfSubTargets.set(target, subTargets);
|
|
10624
11156
|
return subTargets;
|
|
10625
11157
|
}
|
|
@@ -10677,18 +11209,29 @@ class IndexedDbIndexManager {
|
|
|
10677
11209
|
});
|
|
10678
11210
|
}
|
|
10679
11211
|
getIndexType(transaction, target) {
|
|
10680
|
-
let indexType = 2 /* FULL */;
|
|
10681
|
-
|
|
11212
|
+
let indexType = 2 /* IndexType.FULL */;
|
|
11213
|
+
const subTargets = this.getSubTargets(target);
|
|
11214
|
+
return PersistencePromise.forEach(subTargets, (target) => {
|
|
10682
11215
|
return this.getFieldIndex(transaction, target).next(index => {
|
|
10683
11216
|
if (!index) {
|
|
10684
|
-
indexType = 0 /* NONE */;
|
|
11217
|
+
indexType = 0 /* IndexType.NONE */;
|
|
10685
11218
|
}
|
|
10686
|
-
else if (indexType !== 0 /* NONE */ &&
|
|
11219
|
+
else if (indexType !== 0 /* IndexType.NONE */ &&
|
|
10687
11220
|
index.fields.length < targetGetSegmentCount(target)) {
|
|
10688
|
-
indexType = 1 /* PARTIAL */;
|
|
11221
|
+
indexType = 1 /* IndexType.PARTIAL */;
|
|
10689
11222
|
}
|
|
10690
11223
|
});
|
|
10691
|
-
}).next(() =>
|
|
11224
|
+
}).next(() => {
|
|
11225
|
+
// OR queries have more than one sub-target (one sub-target per DNF term). We currently consider
|
|
11226
|
+
// OR queries that have a `limit` to have a partial index. For such queries we perform sorting
|
|
11227
|
+
// and apply the limit in memory as a post-processing step.
|
|
11228
|
+
if (targetHasLimit(target) &&
|
|
11229
|
+
subTargets.length > 1 &&
|
|
11230
|
+
indexType === 2 /* IndexType.FULL */) {
|
|
11231
|
+
return 1 /* IndexType.PARTIAL */;
|
|
11232
|
+
}
|
|
11233
|
+
return indexType;
|
|
11234
|
+
});
|
|
10692
11235
|
}
|
|
10693
11236
|
/**
|
|
10694
11237
|
* Returns the byte encoded form of the directional values in the field index.
|
|
@@ -10710,7 +11253,7 @@ class IndexedDbIndexManager {
|
|
|
10710
11253
|
/** Encodes a single value to the ascending index format. */
|
|
10711
11254
|
encodeSingleElement(value) {
|
|
10712
11255
|
const encoder = new IndexByteEncoder();
|
|
10713
|
-
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(value, encoder.forKind(0 /* ASCENDING */));
|
|
11256
|
+
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(value, encoder.forKind(0 /* IndexKind.ASCENDING */));
|
|
10714
11257
|
return encoder.encodedBytes();
|
|
10715
11258
|
}
|
|
10716
11259
|
/**
|
|
@@ -10726,15 +11269,15 @@ class IndexedDbIndexManager {
|
|
|
10726
11269
|
* Encodes the given field values according to the specification in `target`.
|
|
10727
11270
|
* For IN queries, a list of possible values is returned.
|
|
10728
11271
|
*/
|
|
10729
|
-
encodeValues(fieldIndex, target,
|
|
10730
|
-
if (
|
|
11272
|
+
encodeValues(fieldIndex, target, values) {
|
|
11273
|
+
if (values === null) {
|
|
10731
11274
|
return [];
|
|
10732
11275
|
}
|
|
10733
11276
|
let encoders = [];
|
|
10734
11277
|
encoders.push(new IndexByteEncoder());
|
|
10735
|
-
let
|
|
11278
|
+
let valueIdx = 0;
|
|
10736
11279
|
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
10737
|
-
const value =
|
|
11280
|
+
const value = values[valueIdx++];
|
|
10738
11281
|
for (const encoder of encoders) {
|
|
10739
11282
|
if (this.isInFilter(target, segment.fieldPath) && isArray(value)) {
|
|
10740
11283
|
encoders = this.expandIndexValues(encoders, segment, value);
|
|
@@ -10785,7 +11328,7 @@ class IndexedDbIndexManager {
|
|
|
10785
11328
|
isInFilter(target, fieldPath) {
|
|
10786
11329
|
return !!target.filters.find(f => f instanceof FieldFilter &&
|
|
10787
11330
|
f.field.isEqual(fieldPath) &&
|
|
10788
|
-
(f.op === "in" /* IN */ || f.op === "not-in" /* NOT_IN */));
|
|
11331
|
+
(f.op === "in" /* Operator.IN */ || f.op === "not-in" /* Operator.NOT_IN */));
|
|
10789
11332
|
}
|
|
10790
11333
|
getFieldIndexes(transaction, collectionGroup) {
|
|
10791
11334
|
const indexes = indexConfigurationStore(transaction);
|
|
@@ -10974,24 +11517,36 @@ class IndexedDbIndexManager {
|
|
|
10974
11517
|
bounds.push(upper);
|
|
10975
11518
|
const ranges = [];
|
|
10976
11519
|
for (let i = 0; i < bounds.length; i += 2) {
|
|
10977
|
-
|
|
11520
|
+
// If we encounter two bounds that will create an unmatchable key range,
|
|
11521
|
+
// then we return an empty set of key ranges.
|
|
11522
|
+
if (this.isRangeMatchable(bounds[i], bounds[i + 1])) {
|
|
11523
|
+
return [];
|
|
11524
|
+
}
|
|
11525
|
+
const lowerBound = [
|
|
10978
11526
|
bounds[i].indexId,
|
|
10979
11527
|
this.uid,
|
|
10980
11528
|
bounds[i].arrayValue,
|
|
10981
11529
|
bounds[i].directionalValue,
|
|
10982
11530
|
EMPTY_VALUE,
|
|
10983
11531
|
[]
|
|
10984
|
-
]
|
|
11532
|
+
];
|
|
11533
|
+
const upperBound = [
|
|
10985
11534
|
bounds[i + 1].indexId,
|
|
10986
11535
|
this.uid,
|
|
10987
11536
|
bounds[i + 1].arrayValue,
|
|
10988
11537
|
bounds[i + 1].directionalValue,
|
|
10989
11538
|
EMPTY_VALUE,
|
|
10990
11539
|
[]
|
|
10991
|
-
]
|
|
11540
|
+
];
|
|
11541
|
+
ranges.push(IDBKeyRange.bound(lowerBound, upperBound));
|
|
10992
11542
|
}
|
|
10993
11543
|
return ranges;
|
|
10994
11544
|
}
|
|
11545
|
+
isRangeMatchable(lowerBound, upperBound) {
|
|
11546
|
+
// If lower bound is greater than the upper bound, then the key
|
|
11547
|
+
// range can never be matched.
|
|
11548
|
+
return indexEntryComparator(lowerBound, upperBound) > 0;
|
|
11549
|
+
}
|
|
10995
11550
|
getMinOffsetFromCollectionGroup(transaction, collectionGroup) {
|
|
10996
11551
|
return this.getFieldIndexes(transaction, collectionGroup).next(getMinOffsetFromFieldIndexes);
|
|
10997
11552
|
}
|
|
@@ -11968,7 +12523,7 @@ class LruScheduler {
|
|
|
11968
12523
|
}
|
|
11969
12524
|
scheduleGC(delay) {
|
|
11970
12525
|
logDebug(LOG_TAG$e, `Garbage collection scheduled in ${delay}ms`);
|
|
11971
|
-
this.gcTask = this.asyncQueue.enqueueAfterDelay("lru_garbage_collection" /* LruGarbageCollection */, delay, async () => {
|
|
12526
|
+
this.gcTask = this.asyncQueue.enqueueAfterDelay("lru_garbage_collection" /* TimerId.LruGarbageCollection */, delay, async () => {
|
|
11972
12527
|
this.gcTask = null;
|
|
11973
12528
|
try {
|
|
11974
12529
|
await this.localStore.collectGarbage(this.garbageCollector);
|
|
@@ -12866,7 +13421,7 @@ class LocalDocumentsView {
|
|
|
12866
13421
|
.getOverlay(transaction, key)
|
|
12867
13422
|
.next(value => {
|
|
12868
13423
|
overlay = value;
|
|
12869
|
-
return this.
|
|
13424
|
+
return this.remoteDocumentCache.getEntry(transaction, key);
|
|
12870
13425
|
})
|
|
12871
13426
|
.next(document => {
|
|
12872
13427
|
if (overlay !== null) {
|
|
@@ -13089,7 +13644,9 @@ class LocalDocumentsView {
|
|
|
13089
13644
|
if (originalDocs.get(key)) {
|
|
13090
13645
|
return PersistencePromise.resolve();
|
|
13091
13646
|
}
|
|
13092
|
-
return this.
|
|
13647
|
+
return this.remoteDocumentCache
|
|
13648
|
+
.getEntry(transaction, key)
|
|
13649
|
+
.next(doc => {
|
|
13093
13650
|
modifiedDocs = modifiedDocs.insert(key, doc);
|
|
13094
13651
|
});
|
|
13095
13652
|
})
|
|
@@ -13163,12 +13720,6 @@ class LocalDocumentsView {
|
|
|
13163
13720
|
return results;
|
|
13164
13721
|
});
|
|
13165
13722
|
}
|
|
13166
|
-
/** Returns a base document that can be used to apply `overlay`. */
|
|
13167
|
-
getBaseDocument(transaction, key, overlay) {
|
|
13168
|
-
return overlay === null || overlay.mutation.type === 1 /* Patch */
|
|
13169
|
-
? this.remoteDocumentCache.getEntry(transaction, key)
|
|
13170
|
-
: PersistencePromise.resolve(MutableDocument.newInvalidDocument(key));
|
|
13171
|
-
}
|
|
13172
13723
|
}
|
|
13173
13724
|
|
|
13174
13725
|
/**
|
|
@@ -14918,7 +15469,7 @@ class IndexedDbPersistence {
|
|
|
14918
15469
|
* extend or acquire the primary lease if the client is eligible.
|
|
14919
15470
|
*/
|
|
14920
15471
|
scheduleClientMetadataAndPrimaryLeaseRefreshes() {
|
|
14921
|
-
this.clientMetadataRefresher = this.queue.enqueueAfterDelay("client_metadata_refresh" /* ClientMetadataRefresh */, CLIENT_METADATA_REFRESH_INTERVAL_MS, () => {
|
|
15472
|
+
this.clientMetadataRefresher = this.queue.enqueueAfterDelay("client_metadata_refresh" /* TimerId.ClientMetadataRefresh */, CLIENT_METADATA_REFRESH_INTERVAL_MS, () => {
|
|
14922
15473
|
return this.updateClientMetadataAndTryBecomePrimary()
|
|
14923
15474
|
.then(() => this.maybeGarbageCollectMultiClientState())
|
|
14924
15475
|
.then(() => this.scheduleClientMetadataAndPrimaryLeaseRefreshes());
|
|
@@ -15928,7 +16479,7 @@ function localStoreAllocateTarget(localStore, target) {
|
|
|
15928
16479
|
return localStoreImpl.targetCache
|
|
15929
16480
|
.allocateTargetId(txn)
|
|
15930
16481
|
.next(targetId => {
|
|
15931
|
-
targetData = new TargetData(target, targetId, 0 /* Listen */, txn.currentSequenceNumber);
|
|
16482
|
+
targetData = new TargetData(target, targetId, 0 /* TargetPurpose.Listen */, txn.currentSequenceNumber);
|
|
15932
16483
|
return localStoreImpl.targetCache
|
|
15933
16484
|
.addTargetData(txn, targetData)
|
|
15934
16485
|
.next(() => targetData);
|
|
@@ -16350,11 +16901,11 @@ class QueryEngine {
|
|
|
16350
16901
|
return this.indexManager
|
|
16351
16902
|
.getIndexType(transaction, target)
|
|
16352
16903
|
.next(indexType => {
|
|
16353
|
-
if (indexType === 0 /* NONE */) {
|
|
16904
|
+
if (indexType === 0 /* IndexType.NONE */) {
|
|
16354
16905
|
// The target cannot be served from any index.
|
|
16355
16906
|
return null;
|
|
16356
16907
|
}
|
|
16357
|
-
if (query.limit !== null && indexType === 1 /* PARTIAL */) {
|
|
16908
|
+
if (query.limit !== null && indexType === 1 /* IndexType.PARTIAL */) {
|
|
16358
16909
|
// We cannot apply a limit for targets that are served using a partial
|
|
16359
16910
|
// index. If a partial index will be used to serve the target, the
|
|
16360
16911
|
// query may return a superset of documents that match the target
|
|
@@ -16362,7 +16913,7 @@ class QueryEngine {
|
|
|
16362
16913
|
// may return the correct set of documents in the wrong order (e.g. if
|
|
16363
16914
|
// the index doesn't include a segment for one of the orderBys).
|
|
16364
16915
|
// Therefore, a limit should not be applied in such cases.
|
|
16365
|
-
query = queryWithLimit(query, null, "F" /* First */);
|
|
16916
|
+
query = queryWithLimit(query, null, "F" /* LimitType.First */);
|
|
16366
16917
|
target = queryToTarget(query);
|
|
16367
16918
|
}
|
|
16368
16919
|
return this.indexManager
|
|
@@ -16383,7 +16934,7 @@ class QueryEngine {
|
|
|
16383
16934
|
// query's filters are included in the result set. The SDK
|
|
16384
16935
|
// can then apply the limit once all local edits are
|
|
16385
16936
|
// incorporated.
|
|
16386
|
-
return this.performQueryUsingIndex(transaction, queryWithLimit(query, null, "F" /* First */));
|
|
16937
|
+
return this.performQueryUsingIndex(transaction, queryWithLimit(query, null, "F" /* LimitType.First */));
|
|
16387
16938
|
}
|
|
16388
16939
|
return this.appendRemainingResults(transaction, previousResults, query, offset);
|
|
16389
16940
|
});
|
|
@@ -16462,7 +17013,7 @@ class QueryEngine {
|
|
|
16462
17013
|
// the boundary of the limit itself did not change and documents from cache
|
|
16463
17014
|
// will continue to be "rejected" by this boundary. Therefore, we can ignore
|
|
16464
17015
|
// any modifications that don't affect the last document.
|
|
16465
|
-
const docAtLimitEdge = query.limitType === "F" /* First */
|
|
17016
|
+
const docAtLimitEdge = query.limitType === "F" /* LimitType.First */
|
|
16466
17017
|
? sortedPreviousResults.last()
|
|
16467
17018
|
: sortedPreviousResults.first();
|
|
16468
17019
|
if (!docAtLimitEdge) {
|
|
@@ -17383,7 +17934,7 @@ function nodePromise(action) {
|
|
|
17383
17934
|
*/
|
|
17384
17935
|
// TODO: Fetch runtime version from grpc-js/package.json instead
|
|
17385
17936
|
// when there's a cleaner way to dynamic require JSON in both Node ESM and CJS
|
|
17386
|
-
const grpcVersion = '1.3
|
|
17937
|
+
const grpcVersion = '1.7.3';
|
|
17387
17938
|
const LOG_TAG$9 = 'Connection';
|
|
17388
17939
|
const X_GOOG_API_CLIENT_VALUE = `gl-node/${process.versions.node} fire/${SDK_VERSION} grpc/${grpcVersion}`;
|
|
17389
17940
|
function createMetadata(databasePath, authToken, appCheckToken, appId) {
|
|
@@ -19831,7 +20382,8 @@ const nested = {
|
|
|
19831
20382
|
Operator: {
|
|
19832
20383
|
values: {
|
|
19833
20384
|
OPERATOR_UNSPECIFIED: 0,
|
|
19834
|
-
AND: 1
|
|
20385
|
+
AND: 1,
|
|
20386
|
+
OR: 2
|
|
19835
20387
|
}
|
|
19836
20388
|
}
|
|
19837
20389
|
}
|
|
@@ -20707,7 +21259,7 @@ class PersistentStream {
|
|
|
20707
21259
|
this.authCredentialsProvider = authCredentialsProvider;
|
|
20708
21260
|
this.appCheckCredentialsProvider = appCheckCredentialsProvider;
|
|
20709
21261
|
this.listener = listener;
|
|
20710
|
-
this.state = 0 /* Initial */;
|
|
21262
|
+
this.state = 0 /* PersistentStreamState.Initial */;
|
|
20711
21263
|
/**
|
|
20712
21264
|
* A close count that's incremented every time the stream is closed; used by
|
|
20713
21265
|
* getCloseGuardedDispatcher() to invalidate callbacks that happen after
|
|
@@ -20727,8 +21279,8 @@ class PersistentStream {
|
|
|
20727
21279
|
* outbound requests.
|
|
20728
21280
|
*/
|
|
20729
21281
|
isStarted() {
|
|
20730
|
-
return (this.state === 1 /* Starting */ ||
|
|
20731
|
-
this.state === 5 /* Backoff */ ||
|
|
21282
|
+
return (this.state === 1 /* PersistentStreamState.Starting */ ||
|
|
21283
|
+
this.state === 5 /* PersistentStreamState.Backoff */ ||
|
|
20732
21284
|
this.isOpen());
|
|
20733
21285
|
}
|
|
20734
21286
|
/**
|
|
@@ -20736,8 +21288,8 @@ class PersistentStream {
|
|
|
20736
21288
|
* called) and the stream is ready for outbound requests.
|
|
20737
21289
|
*/
|
|
20738
21290
|
isOpen() {
|
|
20739
|
-
return (this.state === 2 /* Open */ ||
|
|
20740
|
-
this.state === 3 /* Healthy */);
|
|
21291
|
+
return (this.state === 2 /* PersistentStreamState.Open */ ||
|
|
21292
|
+
this.state === 3 /* PersistentStreamState.Healthy */);
|
|
20741
21293
|
}
|
|
20742
21294
|
/**
|
|
20743
21295
|
* Starts the RPC. Only allowed if isStarted() returns false. The stream is
|
|
@@ -20747,7 +21299,7 @@ class PersistentStream {
|
|
|
20747
21299
|
* When start returns, isStarted() will return true.
|
|
20748
21300
|
*/
|
|
20749
21301
|
start() {
|
|
20750
|
-
if (this.state === 4 /* Error */) {
|
|
21302
|
+
if (this.state === 4 /* PersistentStreamState.Error */) {
|
|
20751
21303
|
this.performBackoff();
|
|
20752
21304
|
return;
|
|
20753
21305
|
}
|
|
@@ -20761,7 +21313,7 @@ class PersistentStream {
|
|
|
20761
21313
|
*/
|
|
20762
21314
|
async stop() {
|
|
20763
21315
|
if (this.isStarted()) {
|
|
20764
|
-
await this.close(0 /* Initial */);
|
|
21316
|
+
await this.close(0 /* PersistentStreamState.Initial */);
|
|
20765
21317
|
}
|
|
20766
21318
|
}
|
|
20767
21319
|
/**
|
|
@@ -20773,7 +21325,7 @@ class PersistentStream {
|
|
|
20773
21325
|
* inhibit backoff if required.
|
|
20774
21326
|
*/
|
|
20775
21327
|
inhibitBackoff() {
|
|
20776
|
-
this.state = 0 /* Initial */;
|
|
21328
|
+
this.state = 0 /* PersistentStreamState.Initial */;
|
|
20777
21329
|
this.backoff.reset();
|
|
20778
21330
|
}
|
|
20779
21331
|
/**
|
|
@@ -20803,7 +21355,7 @@ class PersistentStream {
|
|
|
20803
21355
|
if (this.isOpen()) {
|
|
20804
21356
|
// When timing out an idle stream there's no reason to force the stream into backoff when
|
|
20805
21357
|
// it restarts so set the stream state to Initial instead of Error.
|
|
20806
|
-
return this.close(0 /* Initial */);
|
|
21358
|
+
return this.close(0 /* PersistentStreamState.Initial */);
|
|
20807
21359
|
}
|
|
20808
21360
|
}
|
|
20809
21361
|
/** Marks the stream as active again. */
|
|
@@ -20841,7 +21393,7 @@ class PersistentStream {
|
|
|
20841
21393
|
// Invalidates any stream-related callbacks (e.g. from auth or the
|
|
20842
21394
|
// underlying stream), guaranteeing they won't execute.
|
|
20843
21395
|
this.closeCount++;
|
|
20844
|
-
if (finalState !== 4 /* Error */) {
|
|
21396
|
+
if (finalState !== 4 /* PersistentStreamState.Error */) {
|
|
20845
21397
|
// If this is an intentional close ensure we don't delay our next connection attempt.
|
|
20846
21398
|
this.backoff.reset();
|
|
20847
21399
|
}
|
|
@@ -20853,7 +21405,7 @@ class PersistentStream {
|
|
|
20853
21405
|
}
|
|
20854
21406
|
else if (error &&
|
|
20855
21407
|
error.code === Code.UNAUTHENTICATED &&
|
|
20856
|
-
this.state !== 3 /* Healthy */) {
|
|
21408
|
+
this.state !== 3 /* PersistentStreamState.Healthy */) {
|
|
20857
21409
|
// "unauthenticated" error means the token was rejected. This should rarely
|
|
20858
21410
|
// happen since both Auth and AppCheck ensure a sufficient TTL when we
|
|
20859
21411
|
// request a token. If a user manually resets their system clock this can
|
|
@@ -20881,7 +21433,7 @@ class PersistentStream {
|
|
|
20881
21433
|
*/
|
|
20882
21434
|
tearDown() { }
|
|
20883
21435
|
auth() {
|
|
20884
|
-
this.state = 1 /* Starting */;
|
|
21436
|
+
this.state = 1 /* PersistentStreamState.Starting */;
|
|
20885
21437
|
const dispatchIfNotClosed = this.getCloseGuardedDispatcher(this.closeCount);
|
|
20886
21438
|
// TODO(mikelehen): Just use dispatchIfNotClosed, but see TODO below.
|
|
20887
21439
|
const closeCount = this.closeCount;
|
|
@@ -20911,10 +21463,10 @@ class PersistentStream {
|
|
|
20911
21463
|
this.stream = this.startRpc(authToken, appCheckToken);
|
|
20912
21464
|
this.stream.onOpen(() => {
|
|
20913
21465
|
dispatchIfNotClosed(() => {
|
|
20914
|
-
this.state = 2 /* Open */;
|
|
21466
|
+
this.state = 2 /* PersistentStreamState.Open */;
|
|
20915
21467
|
this.healthCheck = this.queue.enqueueAfterDelay(this.healthTimerId, HEALTHY_TIMEOUT_MS, () => {
|
|
20916
21468
|
if (this.isOpen()) {
|
|
20917
|
-
this.state = 3 /* Healthy */;
|
|
21469
|
+
this.state = 3 /* PersistentStreamState.Healthy */;
|
|
20918
21470
|
}
|
|
20919
21471
|
return Promise.resolve();
|
|
20920
21472
|
});
|
|
@@ -20933,9 +21485,9 @@ class PersistentStream {
|
|
|
20933
21485
|
});
|
|
20934
21486
|
}
|
|
20935
21487
|
performBackoff() {
|
|
20936
|
-
this.state = 5 /* Backoff */;
|
|
21488
|
+
this.state = 5 /* PersistentStreamState.Backoff */;
|
|
20937
21489
|
this.backoff.backoffAndRun(async () => {
|
|
20938
|
-
this.state = 0 /* Initial */;
|
|
21490
|
+
this.state = 0 /* PersistentStreamState.Initial */;
|
|
20939
21491
|
this.start();
|
|
20940
21492
|
});
|
|
20941
21493
|
}
|
|
@@ -20947,7 +21499,7 @@ class PersistentStream {
|
|
|
20947
21499
|
// we never expect this to happen because if we stop a stream ourselves,
|
|
20948
21500
|
// this callback will never be called. To prevent cases where we retry
|
|
20949
21501
|
// without a backoff accidentally, we set the stream to error in all cases.
|
|
20950
|
-
return this.close(4 /* Error */, error);
|
|
21502
|
+
return this.close(4 /* PersistentStreamState.Error */, error);
|
|
20951
21503
|
}
|
|
20952
21504
|
/**
|
|
20953
21505
|
* Returns a "dispatcher" function that dispatches operations onto the
|
|
@@ -20978,7 +21530,7 @@ class PersistentStream {
|
|
|
20978
21530
|
*/
|
|
20979
21531
|
class PersistentListenStream extends PersistentStream {
|
|
20980
21532
|
constructor(queue, connection, authCredentials, appCheckCredentials, serializer, listener) {
|
|
20981
|
-
super(queue, "listen_stream_connection_backoff" /* ListenStreamConnectionBackoff */, "listen_stream_idle" /* ListenStreamIdle */, "health_check_timeout" /* HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21533
|
+
super(queue, "listen_stream_connection_backoff" /* TimerId.ListenStreamConnectionBackoff */, "listen_stream_idle" /* TimerId.ListenStreamIdle */, "health_check_timeout" /* TimerId.HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
20982
21534
|
this.serializer = serializer;
|
|
20983
21535
|
}
|
|
20984
21536
|
startRpc(authToken, appCheckToken) {
|
|
@@ -21037,7 +21589,7 @@ class PersistentListenStream extends PersistentStream {
|
|
|
21037
21589
|
*/
|
|
21038
21590
|
class PersistentWriteStream extends PersistentStream {
|
|
21039
21591
|
constructor(queue, connection, authCredentials, appCheckCredentials, serializer, listener) {
|
|
21040
|
-
super(queue, "write_stream_connection_backoff" /* WriteStreamConnectionBackoff */, "write_stream_idle" /* WriteStreamIdle */, "health_check_timeout" /* HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21592
|
+
super(queue, "write_stream_connection_backoff" /* TimerId.WriteStreamConnectionBackoff */, "write_stream_idle" /* TimerId.WriteStreamIdle */, "health_check_timeout" /* TimerId.HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21041
21593
|
this.serializer = serializer;
|
|
21042
21594
|
this.handshakeComplete_ = false;
|
|
21043
21595
|
}
|
|
@@ -21296,7 +21848,7 @@ class OnlineStateTracker {
|
|
|
21296
21848
|
this.asyncQueue = asyncQueue;
|
|
21297
21849
|
this.onlineStateHandler = onlineStateHandler;
|
|
21298
21850
|
/** The current OnlineState. */
|
|
21299
|
-
this.state = "Unknown" /* Unknown */;
|
|
21851
|
+
this.state = "Unknown" /* OnlineState.Unknown */;
|
|
21300
21852
|
/**
|
|
21301
21853
|
* A count of consecutive failures to open the stream. If it reaches the
|
|
21302
21854
|
* maximum defined by MAX_WATCH_STREAM_FAILURES, we'll set the OnlineState to
|
|
@@ -21325,12 +21877,12 @@ class OnlineStateTracker {
|
|
|
21325
21877
|
*/
|
|
21326
21878
|
handleWatchStreamStart() {
|
|
21327
21879
|
if (this.watchStreamFailures === 0) {
|
|
21328
|
-
this.setAndBroadcast("Unknown" /* Unknown */);
|
|
21329
|
-
this.onlineStateTimer = this.asyncQueue.enqueueAfterDelay("online_state_timeout" /* OnlineStateTimeout */, ONLINE_STATE_TIMEOUT_MS, () => {
|
|
21880
|
+
this.setAndBroadcast("Unknown" /* OnlineState.Unknown */);
|
|
21881
|
+
this.onlineStateTimer = this.asyncQueue.enqueueAfterDelay("online_state_timeout" /* TimerId.OnlineStateTimeout */, ONLINE_STATE_TIMEOUT_MS, () => {
|
|
21330
21882
|
this.onlineStateTimer = null;
|
|
21331
21883
|
this.logClientOfflineWarningIfNecessary(`Backend didn't respond within ${ONLINE_STATE_TIMEOUT_MS / 1000} ` +
|
|
21332
21884
|
`seconds.`);
|
|
21333
|
-
this.setAndBroadcast("Offline" /* Offline */);
|
|
21885
|
+
this.setAndBroadcast("Offline" /* OnlineState.Offline */);
|
|
21334
21886
|
// NOTE: handleWatchStreamFailure() will continue to increment
|
|
21335
21887
|
// watchStreamFailures even though we are already marked Offline,
|
|
21336
21888
|
// but this is non-harmful.
|
|
@@ -21345,8 +21897,8 @@ class OnlineStateTracker {
|
|
|
21345
21897
|
* actually transition to the 'Offline' state.
|
|
21346
21898
|
*/
|
|
21347
21899
|
handleWatchStreamFailure(error) {
|
|
21348
|
-
if (this.state === "Online" /* Online */) {
|
|
21349
|
-
this.setAndBroadcast("Unknown" /* Unknown */);
|
|
21900
|
+
if (this.state === "Online" /* OnlineState.Online */) {
|
|
21901
|
+
this.setAndBroadcast("Unknown" /* OnlineState.Unknown */);
|
|
21350
21902
|
}
|
|
21351
21903
|
else {
|
|
21352
21904
|
this.watchStreamFailures++;
|
|
@@ -21354,7 +21906,7 @@ class OnlineStateTracker {
|
|
|
21354
21906
|
this.clearOnlineStateTimer();
|
|
21355
21907
|
this.logClientOfflineWarningIfNecessary(`Connection failed ${MAX_WATCH_STREAM_FAILURES} ` +
|
|
21356
21908
|
`times. Most recent error: ${error.toString()}`);
|
|
21357
|
-
this.setAndBroadcast("Offline" /* Offline */);
|
|
21909
|
+
this.setAndBroadcast("Offline" /* OnlineState.Offline */);
|
|
21358
21910
|
}
|
|
21359
21911
|
}
|
|
21360
21912
|
}
|
|
@@ -21368,7 +21920,7 @@ class OnlineStateTracker {
|
|
|
21368
21920
|
set(newState) {
|
|
21369
21921
|
this.clearOnlineStateTimer();
|
|
21370
21922
|
this.watchStreamFailures = 0;
|
|
21371
|
-
if (newState === "Online" /* Online */) {
|
|
21923
|
+
if (newState === "Online" /* OnlineState.Online */) {
|
|
21372
21924
|
// We've connected to watch at least once. Don't warn the developer
|
|
21373
21925
|
// about being offline going forward.
|
|
21374
21926
|
this.shouldWarnClientIsOffline = false;
|
|
@@ -21495,7 +22047,7 @@ function newRemoteStore(localStore, datastore, asyncQueue, onlineStateHandler, c
|
|
|
21495
22047
|
/** Re-enables the network. Idempotent. */
|
|
21496
22048
|
function remoteStoreEnableNetwork(remoteStore) {
|
|
21497
22049
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21498
|
-
remoteStoreImpl.offlineCauses.delete(0 /* UserDisabled */);
|
|
22050
|
+
remoteStoreImpl.offlineCauses.delete(0 /* OfflineCause.UserDisabled */);
|
|
21499
22051
|
return enableNetworkInternal(remoteStoreImpl);
|
|
21500
22052
|
}
|
|
21501
22053
|
async function enableNetworkInternal(remoteStoreImpl) {
|
|
@@ -21511,10 +22063,10 @@ async function enableNetworkInternal(remoteStoreImpl) {
|
|
|
21511
22063
|
*/
|
|
21512
22064
|
async function remoteStoreDisableNetwork(remoteStore) {
|
|
21513
22065
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21514
|
-
remoteStoreImpl.offlineCauses.add(0 /* UserDisabled */);
|
|
22066
|
+
remoteStoreImpl.offlineCauses.add(0 /* OfflineCause.UserDisabled */);
|
|
21515
22067
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21516
22068
|
// Set the OnlineState to Offline so get()s return from cache, etc.
|
|
21517
|
-
remoteStoreImpl.onlineStateTracker.set("Offline" /* Offline */);
|
|
22069
|
+
remoteStoreImpl.onlineStateTracker.set("Offline" /* OnlineState.Offline */);
|
|
21518
22070
|
}
|
|
21519
22071
|
async function disableNetworkInternal(remoteStoreImpl) {
|
|
21520
22072
|
for (const networkStatusHandler of remoteStoreImpl.onNetworkStatusChange) {
|
|
@@ -21524,12 +22076,12 @@ async function disableNetworkInternal(remoteStoreImpl) {
|
|
|
21524
22076
|
async function remoteStoreShutdown(remoteStore) {
|
|
21525
22077
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21526
22078
|
logDebug(LOG_TAG$5, 'RemoteStore shutting down.');
|
|
21527
|
-
remoteStoreImpl.offlineCauses.add(5 /* Shutdown */);
|
|
22079
|
+
remoteStoreImpl.offlineCauses.add(5 /* OfflineCause.Shutdown */);
|
|
21528
22080
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21529
22081
|
remoteStoreImpl.connectivityMonitor.shutdown();
|
|
21530
22082
|
// Set the OnlineState to Unknown (rather than Offline) to avoid potentially
|
|
21531
22083
|
// triggering spurious listener events with cached data, etc.
|
|
21532
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22084
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21533
22085
|
}
|
|
21534
22086
|
/**
|
|
21535
22087
|
* Starts new listen for the given target. Uses resume token if provided. It
|
|
@@ -21569,7 +22121,7 @@ function remoteStoreUnlisten(remoteStore, targetId) {
|
|
|
21569
22121
|
// Revert to OnlineState.Unknown if the watch stream is not open and we
|
|
21570
22122
|
// have no listeners, since without any listens to send we cannot
|
|
21571
22123
|
// confirm if the stream is healthy and upgrade to OnlineState.Online.
|
|
21572
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22124
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21573
22125
|
}
|
|
21574
22126
|
}
|
|
21575
22127
|
}
|
|
@@ -21630,14 +22182,14 @@ async function onWatchStreamClose(remoteStoreImpl, error) {
|
|
|
21630
22182
|
// No need to restart watch stream because there are no active targets.
|
|
21631
22183
|
// The online state is set to unknown because there is no active attempt
|
|
21632
22184
|
// at establishing a connection
|
|
21633
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22185
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21634
22186
|
}
|
|
21635
22187
|
}
|
|
21636
22188
|
async function onWatchStreamChange(remoteStoreImpl, watchChange, snapshotVersion) {
|
|
21637
22189
|
// Mark the client as online since we got a message from the server
|
|
21638
|
-
remoteStoreImpl.onlineStateTracker.set("Online" /* Online */);
|
|
22190
|
+
remoteStoreImpl.onlineStateTracker.set("Online" /* OnlineState.Online */);
|
|
21639
22191
|
if (watchChange instanceof WatchTargetChange &&
|
|
21640
|
-
watchChange.state === 2 /* Removed */ &&
|
|
22192
|
+
watchChange.state === 2 /* WatchTargetChangeState.Removed */ &&
|
|
21641
22193
|
watchChange.cause) {
|
|
21642
22194
|
// There was an error on a target, don't wait for a consistent snapshot
|
|
21643
22195
|
// to raise events
|
|
@@ -21685,10 +22237,10 @@ async function onWatchStreamChange(remoteStoreImpl, watchChange, snapshotVersion
|
|
|
21685
22237
|
*/
|
|
21686
22238
|
async function disableNetworkUntilRecovery(remoteStoreImpl, e, op) {
|
|
21687
22239
|
if (isIndexedDbTransactionError(e)) {
|
|
21688
|
-
remoteStoreImpl.offlineCauses.add(1 /* IndexedDbFailed */);
|
|
22240
|
+
remoteStoreImpl.offlineCauses.add(1 /* OfflineCause.IndexedDbFailed */);
|
|
21689
22241
|
// Disable network and raise offline snapshots
|
|
21690
22242
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21691
|
-
remoteStoreImpl.onlineStateTracker.set("Offline" /* Offline */);
|
|
22243
|
+
remoteStoreImpl.onlineStateTracker.set("Offline" /* OnlineState.Offline */);
|
|
21692
22244
|
if (!op) {
|
|
21693
22245
|
// Use a simple read operation to determine if IndexedDB recovered.
|
|
21694
22246
|
// Ideally, we would expose a health check directly on SimpleDb, but
|
|
@@ -21699,7 +22251,7 @@ async function disableNetworkUntilRecovery(remoteStoreImpl, e, op) {
|
|
|
21699
22251
|
remoteStoreImpl.asyncQueue.enqueueRetryable(async () => {
|
|
21700
22252
|
logDebug(LOG_TAG$5, 'Retrying IndexedDB access');
|
|
21701
22253
|
await op();
|
|
21702
|
-
remoteStoreImpl.offlineCauses.delete(1 /* IndexedDbFailed */);
|
|
22254
|
+
remoteStoreImpl.offlineCauses.delete(1 /* OfflineCause.IndexedDbFailed */);
|
|
21703
22255
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21704
22256
|
});
|
|
21705
22257
|
}
|
|
@@ -21750,7 +22302,7 @@ function raiseWatchSnapshot(remoteStoreImpl, snapshotVersion) {
|
|
|
21750
22302
|
// mismatch, but don't actually retain that in listenTargets. This ensures
|
|
21751
22303
|
// that we flag the first re-listen this way without impacting future
|
|
21752
22304
|
// listens of this target (that might happen e.g. on reconnect).
|
|
21753
|
-
const requestTargetData = new TargetData(targetData.target, targetId, 1 /* ExistenceFilterMismatch */, targetData.sequenceNumber);
|
|
22305
|
+
const requestTargetData = new TargetData(targetData.target, targetId, 1 /* TargetPurpose.ExistenceFilterMismatch */, targetData.sequenceNumber);
|
|
21754
22306
|
sendWatchRequest(remoteStoreImpl, requestTargetData);
|
|
21755
22307
|
});
|
|
21756
22308
|
return remoteStoreImpl.remoteSyncer.applyRemoteEvent(remoteEvent);
|
|
@@ -21881,10 +22433,10 @@ async function handleWriteError(remoteStoreImpl, error) {
|
|
|
21881
22433
|
}
|
|
21882
22434
|
async function restartNetwork(remoteStore) {
|
|
21883
22435
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21884
|
-
remoteStoreImpl.offlineCauses.add(4 /* ConnectivityChange */);
|
|
22436
|
+
remoteStoreImpl.offlineCauses.add(4 /* OfflineCause.ConnectivityChange */);
|
|
21885
22437
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21886
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
21887
|
-
remoteStoreImpl.offlineCauses.delete(4 /* ConnectivityChange */);
|
|
22438
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
22439
|
+
remoteStoreImpl.offlineCauses.delete(4 /* OfflineCause.ConnectivityChange */);
|
|
21888
22440
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21889
22441
|
}
|
|
21890
22442
|
async function remoteStoreHandleCredentialChange(remoteStore, user) {
|
|
@@ -21895,14 +22447,14 @@ async function remoteStoreHandleCredentialChange(remoteStore, user) {
|
|
|
21895
22447
|
// Tear down and re-create our network streams. This will ensure we get a
|
|
21896
22448
|
// fresh auth token for the new user and re-fill the write pipeline with
|
|
21897
22449
|
// new mutations from the LocalStore (since mutations are per-user).
|
|
21898
|
-
remoteStoreImpl.offlineCauses.add(3 /* CredentialChange */);
|
|
22450
|
+
remoteStoreImpl.offlineCauses.add(3 /* OfflineCause.CredentialChange */);
|
|
21899
22451
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21900
22452
|
if (usesNetwork) {
|
|
21901
22453
|
// Don't set the network status to Unknown if we are offline.
|
|
21902
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22454
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21903
22455
|
}
|
|
21904
22456
|
await remoteStoreImpl.remoteSyncer.handleCredentialChange(user);
|
|
21905
|
-
remoteStoreImpl.offlineCauses.delete(3 /* CredentialChange */);
|
|
22457
|
+
remoteStoreImpl.offlineCauses.delete(3 /* OfflineCause.CredentialChange */);
|
|
21906
22458
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21907
22459
|
}
|
|
21908
22460
|
/**
|
|
@@ -21911,13 +22463,13 @@ async function remoteStoreHandleCredentialChange(remoteStore, user) {
|
|
|
21911
22463
|
async function remoteStoreApplyPrimaryState(remoteStore, isPrimary) {
|
|
21912
22464
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21913
22465
|
if (isPrimary) {
|
|
21914
|
-
remoteStoreImpl.offlineCauses.delete(2 /* IsSecondary */);
|
|
22466
|
+
remoteStoreImpl.offlineCauses.delete(2 /* OfflineCause.IsSecondary */);
|
|
21915
22467
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21916
22468
|
}
|
|
21917
22469
|
else if (!isPrimary) {
|
|
21918
|
-
remoteStoreImpl.offlineCauses.add(2 /* IsSecondary */);
|
|
22470
|
+
remoteStoreImpl.offlineCauses.add(2 /* OfflineCause.IsSecondary */);
|
|
21919
22471
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21920
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22472
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21921
22473
|
}
|
|
21922
22474
|
}
|
|
21923
22475
|
/**
|
|
@@ -21943,7 +22495,7 @@ function ensureWatchStream(remoteStoreImpl) {
|
|
|
21943
22495
|
startWatchStream(remoteStoreImpl);
|
|
21944
22496
|
}
|
|
21945
22497
|
else {
|
|
21946
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22498
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21947
22499
|
}
|
|
21948
22500
|
}
|
|
21949
22501
|
else {
|
|
@@ -22274,46 +22826,46 @@ class DocumentChangeSet {
|
|
|
22274
22826
|
return;
|
|
22275
22827
|
}
|
|
22276
22828
|
// Merge the new change with the existing change.
|
|
22277
|
-
if (change.type !== 0 /* Added */ &&
|
|
22278
|
-
oldChange.type === 3 /* Metadata */) {
|
|
22829
|
+
if (change.type !== 0 /* ChangeType.Added */ &&
|
|
22830
|
+
oldChange.type === 3 /* ChangeType.Metadata */) {
|
|
22279
22831
|
this.changeMap = this.changeMap.insert(key, change);
|
|
22280
22832
|
}
|
|
22281
|
-
else if (change.type === 3 /* Metadata */ &&
|
|
22282
|
-
oldChange.type !== 1 /* Removed */) {
|
|
22833
|
+
else if (change.type === 3 /* ChangeType.Metadata */ &&
|
|
22834
|
+
oldChange.type !== 1 /* ChangeType.Removed */) {
|
|
22283
22835
|
this.changeMap = this.changeMap.insert(key, {
|
|
22284
22836
|
type: oldChange.type,
|
|
22285
22837
|
doc: change.doc
|
|
22286
22838
|
});
|
|
22287
22839
|
}
|
|
22288
|
-
else if (change.type === 2 /* Modified */ &&
|
|
22289
|
-
oldChange.type === 2 /* Modified */) {
|
|
22840
|
+
else if (change.type === 2 /* ChangeType.Modified */ &&
|
|
22841
|
+
oldChange.type === 2 /* ChangeType.Modified */) {
|
|
22290
22842
|
this.changeMap = this.changeMap.insert(key, {
|
|
22291
|
-
type: 2 /* Modified */,
|
|
22843
|
+
type: 2 /* ChangeType.Modified */,
|
|
22292
22844
|
doc: change.doc
|
|
22293
22845
|
});
|
|
22294
22846
|
}
|
|
22295
|
-
else if (change.type === 2 /* Modified */ &&
|
|
22296
|
-
oldChange.type === 0 /* Added */) {
|
|
22847
|
+
else if (change.type === 2 /* ChangeType.Modified */ &&
|
|
22848
|
+
oldChange.type === 0 /* ChangeType.Added */) {
|
|
22297
22849
|
this.changeMap = this.changeMap.insert(key, {
|
|
22298
|
-
type: 0 /* Added */,
|
|
22850
|
+
type: 0 /* ChangeType.Added */,
|
|
22299
22851
|
doc: change.doc
|
|
22300
22852
|
});
|
|
22301
22853
|
}
|
|
22302
|
-
else if (change.type === 1 /* Removed */ &&
|
|
22303
|
-
oldChange.type === 0 /* Added */) {
|
|
22854
|
+
else if (change.type === 1 /* ChangeType.Removed */ &&
|
|
22855
|
+
oldChange.type === 0 /* ChangeType.Added */) {
|
|
22304
22856
|
this.changeMap = this.changeMap.remove(key);
|
|
22305
22857
|
}
|
|
22306
|
-
else if (change.type === 1 /* Removed */ &&
|
|
22307
|
-
oldChange.type === 2 /* Modified */) {
|
|
22858
|
+
else if (change.type === 1 /* ChangeType.Removed */ &&
|
|
22859
|
+
oldChange.type === 2 /* ChangeType.Modified */) {
|
|
22308
22860
|
this.changeMap = this.changeMap.insert(key, {
|
|
22309
|
-
type: 1 /* Removed */,
|
|
22861
|
+
type: 1 /* ChangeType.Removed */,
|
|
22310
22862
|
doc: oldChange.doc
|
|
22311
22863
|
});
|
|
22312
22864
|
}
|
|
22313
|
-
else if (change.type === 0 /* Added */ &&
|
|
22314
|
-
oldChange.type === 1 /* Removed */) {
|
|
22865
|
+
else if (change.type === 0 /* ChangeType.Added */ &&
|
|
22866
|
+
oldChange.type === 1 /* ChangeType.Removed */) {
|
|
22315
22867
|
this.changeMap = this.changeMap.insert(key, {
|
|
22316
|
-
type: 2 /* Modified */,
|
|
22868
|
+
type: 2 /* ChangeType.Modified */,
|
|
22317
22869
|
doc: change.doc
|
|
22318
22870
|
});
|
|
22319
22871
|
}
|
|
@@ -22352,7 +22904,7 @@ class ViewSnapshot {
|
|
|
22352
22904
|
static fromInitialDocuments(query, documents, mutatedKeys, fromCache, hasCachedResults) {
|
|
22353
22905
|
const changes = [];
|
|
22354
22906
|
documents.forEach(doc => {
|
|
22355
|
-
changes.push({ type: 0 /* Added */, doc });
|
|
22907
|
+
changes.push({ type: 0 /* ChangeType.Added */, doc });
|
|
22356
22908
|
});
|
|
22357
22909
|
return new ViewSnapshot(query, documents, DocumentSet.emptySet(documents), changes, mutatedKeys, fromCache,
|
|
22358
22910
|
/* syncStateChanged= */ true,
|
|
@@ -22418,7 +22970,7 @@ function newEventManager() {
|
|
|
22418
22970
|
class EventManagerImpl {
|
|
22419
22971
|
constructor() {
|
|
22420
22972
|
this.queries = new ObjectMap(q => canonifyQuery(q), queryEquals);
|
|
22421
|
-
this.onlineState = "Unknown" /* Unknown */;
|
|
22973
|
+
this.onlineState = "Unknown" /* OnlineState.Unknown */;
|
|
22422
22974
|
this.snapshotsInSyncListeners = new Set();
|
|
22423
22975
|
}
|
|
22424
22976
|
}
|
|
@@ -22549,7 +23101,7 @@ class QueryListener {
|
|
|
22549
23101
|
*/
|
|
22550
23102
|
this.raisedInitialEvent = false;
|
|
22551
23103
|
this.snap = null;
|
|
22552
|
-
this.onlineState = "Unknown" /* Unknown */;
|
|
23104
|
+
this.onlineState = "Unknown" /* OnlineState.Unknown */;
|
|
22553
23105
|
this.options = options || {};
|
|
22554
23106
|
}
|
|
22555
23107
|
/**
|
|
@@ -22563,7 +23115,7 @@ class QueryListener {
|
|
|
22563
23115
|
// Remove the metadata only changes.
|
|
22564
23116
|
const docChanges = [];
|
|
22565
23117
|
for (const docChange of snap.docChanges) {
|
|
22566
|
-
if (docChange.type !== 3 /* Metadata */) {
|
|
23118
|
+
if (docChange.type !== 3 /* ChangeType.Metadata */) {
|
|
22567
23119
|
docChanges.push(docChange);
|
|
22568
23120
|
}
|
|
22569
23121
|
}
|
|
@@ -22606,7 +23158,7 @@ class QueryListener {
|
|
|
22606
23158
|
}
|
|
22607
23159
|
// NOTE: We consider OnlineState.Unknown as online (it should become Offline
|
|
22608
23160
|
// or Online if we wait long enough).
|
|
22609
|
-
const maybeOnline = onlineState !== "Offline" /* Offline */;
|
|
23161
|
+
const maybeOnline = onlineState !== "Offline" /* OnlineState.Offline */;
|
|
22610
23162
|
// Don't raise the event if we're online, aren't synced yet (checked
|
|
22611
23163
|
// above) and are waiting for a sync.
|
|
22612
23164
|
if (this.options.waitForSyncWhenOnline && maybeOnline) {
|
|
@@ -22616,7 +23168,7 @@ class QueryListener {
|
|
|
22616
23168
|
// or we are offline.
|
|
22617
23169
|
return (!snap.docs.isEmpty() ||
|
|
22618
23170
|
snap.hasCachedResults ||
|
|
22619
|
-
onlineState === "Offline" /* Offline */);
|
|
23171
|
+
onlineState === "Offline" /* OnlineState.Offline */);
|
|
22620
23172
|
}
|
|
22621
23173
|
shouldRaiseEvent(snap) {
|
|
22622
23174
|
// We don't need to handle includeDocumentMetadataChanges here because
|
|
@@ -22675,10 +23227,10 @@ class LocalViewChanges {
|
|
|
22675
23227
|
let removedKeys = documentKeySet();
|
|
22676
23228
|
for (const docChange of viewSnapshot.docChanges) {
|
|
22677
23229
|
switch (docChange.type) {
|
|
22678
|
-
case 0 /* Added */:
|
|
23230
|
+
case 0 /* ChangeType.Added */:
|
|
22679
23231
|
addedKeys = addedKeys.add(docChange.doc.key);
|
|
22680
23232
|
break;
|
|
22681
|
-
case 1 /* Removed */:
|
|
23233
|
+
case 1 /* ChangeType.Removed */:
|
|
22682
23234
|
removedKeys = removedKeys.add(docChange.doc.key);
|
|
22683
23235
|
break;
|
|
22684
23236
|
// do nothing
|
|
@@ -22926,11 +23478,11 @@ class View {
|
|
|
22926
23478
|
//
|
|
22927
23479
|
// Note that this should never get used in a refill (when previousChanges is
|
|
22928
23480
|
// set), because there will only be adds -- no deletes or updates.
|
|
22929
|
-
const lastDocInLimit = this.query.limitType === "F" /* First */ &&
|
|
23481
|
+
const lastDocInLimit = this.query.limitType === "F" /* LimitType.First */ &&
|
|
22930
23482
|
oldDocumentSet.size === this.query.limit
|
|
22931
23483
|
? oldDocumentSet.last()
|
|
22932
23484
|
: null;
|
|
22933
|
-
const firstDocInLimit = this.query.limitType === "L" /* Last */ &&
|
|
23485
|
+
const firstDocInLimit = this.query.limitType === "L" /* LimitType.Last */ &&
|
|
22934
23486
|
oldDocumentSet.size === this.query.limit
|
|
22935
23487
|
? oldDocumentSet.first()
|
|
22936
23488
|
: null;
|
|
@@ -22953,7 +23505,7 @@ class View {
|
|
|
22953
23505
|
if (!docsEqual) {
|
|
22954
23506
|
if (!this.shouldWaitForSyncedDocument(oldDoc, newDoc)) {
|
|
22955
23507
|
changeSet.track({
|
|
22956
|
-
type: 2 /* Modified */,
|
|
23508
|
+
type: 2 /* ChangeType.Modified */,
|
|
22957
23509
|
doc: newDoc
|
|
22958
23510
|
});
|
|
22959
23511
|
changeApplied = true;
|
|
@@ -22969,16 +23521,16 @@ class View {
|
|
|
22969
23521
|
}
|
|
22970
23522
|
}
|
|
22971
23523
|
else if (oldDocHadPendingMutations !== newDocHasPendingMutations) {
|
|
22972
|
-
changeSet.track({ type: 3 /* Metadata */, doc: newDoc });
|
|
23524
|
+
changeSet.track({ type: 3 /* ChangeType.Metadata */, doc: newDoc });
|
|
22973
23525
|
changeApplied = true;
|
|
22974
23526
|
}
|
|
22975
23527
|
}
|
|
22976
23528
|
else if (!oldDoc && newDoc) {
|
|
22977
|
-
changeSet.track({ type: 0 /* Added */, doc: newDoc });
|
|
23529
|
+
changeSet.track({ type: 0 /* ChangeType.Added */, doc: newDoc });
|
|
22978
23530
|
changeApplied = true;
|
|
22979
23531
|
}
|
|
22980
23532
|
else if (oldDoc && !newDoc) {
|
|
22981
|
-
changeSet.track({ type: 1 /* Removed */, doc: oldDoc });
|
|
23533
|
+
changeSet.track({ type: 1 /* ChangeType.Removed */, doc: oldDoc });
|
|
22982
23534
|
changeApplied = true;
|
|
22983
23535
|
if (lastDocInLimit || firstDocInLimit) {
|
|
22984
23536
|
// A doc was removed from a full limit query. We'll need to
|
|
@@ -23006,12 +23558,12 @@ class View {
|
|
|
23006
23558
|
// Drop documents out to meet limit/limitToLast requirement.
|
|
23007
23559
|
if (this.query.limit !== null) {
|
|
23008
23560
|
while (newDocumentSet.size > this.query.limit) {
|
|
23009
|
-
const oldDoc = this.query.limitType === "F" /* First */
|
|
23561
|
+
const oldDoc = this.query.limitType === "F" /* LimitType.First */
|
|
23010
23562
|
? newDocumentSet.last()
|
|
23011
23563
|
: newDocumentSet.first();
|
|
23012
23564
|
newDocumentSet = newDocumentSet.delete(oldDoc.key);
|
|
23013
23565
|
newMutatedKeys = newMutatedKeys.delete(oldDoc.key);
|
|
23014
|
-
changeSet.track({ type: 1 /* Removed */, doc: oldDoc });
|
|
23566
|
+
changeSet.track({ type: 1 /* ChangeType.Removed */, doc: oldDoc });
|
|
23015
23567
|
}
|
|
23016
23568
|
}
|
|
23017
23569
|
return {
|
|
@@ -23059,7 +23611,7 @@ class View {
|
|
|
23059
23611
|
? this.updateLimboDocuments()
|
|
23060
23612
|
: [];
|
|
23061
23613
|
const synced = this.limboDocuments.size === 0 && this.current;
|
|
23062
|
-
const newSyncState = synced ? 1 /* Synced */ : 0 /* Local */;
|
|
23614
|
+
const newSyncState = synced ? 1 /* SyncState.Synced */ : 0 /* SyncState.Local */;
|
|
23063
23615
|
const syncStateChanged = newSyncState !== this.syncState;
|
|
23064
23616
|
this.syncState = newSyncState;
|
|
23065
23617
|
if (changes.length === 0 && !syncStateChanged) {
|
|
@@ -23067,7 +23619,7 @@ class View {
|
|
|
23067
23619
|
return { limboChanges };
|
|
23068
23620
|
}
|
|
23069
23621
|
else {
|
|
23070
|
-
const snap = new ViewSnapshot(this.query, docChanges.documentSet, oldDocs, changes, docChanges.mutatedKeys, newSyncState === 0 /* Local */, syncStateChanged,
|
|
23622
|
+
const snap = new ViewSnapshot(this.query, docChanges.documentSet, oldDocs, changes, docChanges.mutatedKeys, newSyncState === 0 /* SyncState.Local */, syncStateChanged,
|
|
23071
23623
|
/* excludesMetadataChanges= */ false, targetChange
|
|
23072
23624
|
? targetChange.resumeToken.approximateByteSize() > 0
|
|
23073
23625
|
: false);
|
|
@@ -23082,7 +23634,7 @@ class View {
|
|
|
23082
23634
|
* ViewChange if the view's syncState changes as a result.
|
|
23083
23635
|
*/
|
|
23084
23636
|
applyOnlineStateChange(onlineState) {
|
|
23085
|
-
if (this.current && onlineState === "Offline" /* Offline */) {
|
|
23637
|
+
if (this.current && onlineState === "Offline" /* OnlineState.Offline */) {
|
|
23086
23638
|
// If we're offline, set `current` to false and then call applyChanges()
|
|
23087
23639
|
// to refresh our syncState and generate a ViewChange as appropriate. We
|
|
23088
23640
|
// are guaranteed to get a new TargetChange that sets `current` back to
|
|
@@ -23197,22 +23749,22 @@ class View {
|
|
|
23197
23749
|
*/
|
|
23198
23750
|
// PORTING NOTE: Multi-tab only.
|
|
23199
23751
|
computeInitialSnapshot() {
|
|
23200
|
-
return ViewSnapshot.fromInitialDocuments(this.query, this.documentSet, this.mutatedKeys, this.syncState === 0 /* Local */, this.hasCachedResults);
|
|
23752
|
+
return ViewSnapshot.fromInitialDocuments(this.query, this.documentSet, this.mutatedKeys, this.syncState === 0 /* SyncState.Local */, this.hasCachedResults);
|
|
23201
23753
|
}
|
|
23202
23754
|
}
|
|
23203
23755
|
function compareChangeType(c1, c2) {
|
|
23204
23756
|
const order = (change) => {
|
|
23205
23757
|
switch (change) {
|
|
23206
|
-
case 0 /* Added */:
|
|
23758
|
+
case 0 /* ChangeType.Added */:
|
|
23207
23759
|
return 1;
|
|
23208
|
-
case 2 /* Modified */:
|
|
23760
|
+
case 2 /* ChangeType.Modified */:
|
|
23209
23761
|
return 2;
|
|
23210
|
-
case 3 /* Metadata */:
|
|
23762
|
+
case 3 /* ChangeType.Metadata */:
|
|
23211
23763
|
// A metadata change is converted to a modified change at the public
|
|
23212
23764
|
// api layer. Since we sort by document key and then change type,
|
|
23213
23765
|
// metadata and modified changes must be sorted equivalently.
|
|
23214
23766
|
return 2;
|
|
23215
|
-
case 1 /* Removed */:
|
|
23767
|
+
case 1 /* ChangeType.Removed */:
|
|
23216
23768
|
return 0;
|
|
23217
23769
|
default:
|
|
23218
23770
|
return fail();
|
|
@@ -23330,7 +23882,7 @@ class SyncEngineImpl {
|
|
|
23330
23882
|
/** Stores user callbacks waiting for all pending writes to be acknowledged. */
|
|
23331
23883
|
this.pendingWritesCallbacks = new Map();
|
|
23332
23884
|
this.limboTargetIdGenerator = TargetIdGenerator.forSyncEngine();
|
|
23333
|
-
this.onlineState = "Unknown" /* Unknown */;
|
|
23885
|
+
this.onlineState = "Unknown" /* OnlineState.Unknown */;
|
|
23334
23886
|
// The primary state is set to `true` or `false` immediately after Firestore
|
|
23335
23887
|
// startup. In the interim, a client should only be considered primary if
|
|
23336
23888
|
// `isPrimary` is true.
|
|
@@ -23394,7 +23946,7 @@ async function initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId,
|
|
|
23394
23946
|
/* usePreviousResults= */ true);
|
|
23395
23947
|
const view = new View(query, queryResult.remoteKeys);
|
|
23396
23948
|
const viewDocChanges = view.computeDocChanges(queryResult.documents);
|
|
23397
|
-
const synthesizedTargetChange = TargetChange.createSynthesizedTargetChangeForCurrentChange(targetId, current && syncEngineImpl.onlineState !== "Offline" /* Offline */, resumeToken);
|
|
23949
|
+
const synthesizedTargetChange = TargetChange.createSynthesizedTargetChangeForCurrentChange(targetId, current && syncEngineImpl.onlineState !== "Offline" /* OnlineState.Offline */, resumeToken);
|
|
23398
23950
|
const viewChange = view.applyChanges(viewDocChanges,
|
|
23399
23951
|
/* updateLimboDocuments= */ syncEngineImpl.isPrimaryClient, synthesizedTargetChange);
|
|
23400
23952
|
updateTrackedLimbos(syncEngineImpl, targetId, viewChange.limboChanges);
|
|
@@ -23520,9 +24072,9 @@ function syncEngineApplyOnlineStateChange(syncEngine, onlineState, source) {
|
|
|
23520
24072
|
// tab remains online) and only apply the primary tab's online state from
|
|
23521
24073
|
// SharedClientState.
|
|
23522
24074
|
if ((syncEngineImpl.isPrimaryClient &&
|
|
23523
|
-
source === 0 /* RemoteStore */) ||
|
|
24075
|
+
source === 0 /* OnlineStateSource.RemoteStore */) ||
|
|
23524
24076
|
(!syncEngineImpl.isPrimaryClient &&
|
|
23525
|
-
source === 1 /* SharedClientState */)) {
|
|
24077
|
+
source === 1 /* OnlineStateSource.SharedClientState */)) {
|
|
23526
24078
|
const newViewSnapshots = [];
|
|
23527
24079
|
syncEngineImpl.queryViewsByQuery.forEach((query, queryView) => {
|
|
23528
24080
|
const viewChange = queryView.view.applyOnlineStateChange(onlineState);
|
|
@@ -23790,7 +24342,7 @@ function pumpEnqueuedLimboResolutions(syncEngineImpl) {
|
|
|
23790
24342
|
syncEngineImpl.activeLimboResolutionsByTarget.set(limboTargetId, new LimboResolution(key));
|
|
23791
24343
|
syncEngineImpl.activeLimboTargetsByKey =
|
|
23792
24344
|
syncEngineImpl.activeLimboTargetsByKey.insert(key, limboTargetId);
|
|
23793
|
-
remoteStoreListen(syncEngineImpl.remoteStore, new TargetData(queryToTarget(newQueryForPath(key.path)), limboTargetId, 2 /* LimboResolution */, ListenSequence.INVALID));
|
|
24345
|
+
remoteStoreListen(syncEngineImpl.remoteStore, new TargetData(queryToTarget(newQueryForPath(key.path)), limboTargetId, 2 /* TargetPurpose.LimboResolution */, ListenSequence.INVALID));
|
|
23794
24346
|
}
|
|
23795
24347
|
}
|
|
23796
24348
|
async function syncEngineEmitNewSnapsAndNotifyLocalStore(syncEngine, changes, remoteEvent) {
|
|
@@ -24043,7 +24595,7 @@ async function synchronizeQueryViewsAndRaiseSnapshots(syncEngine, targets, trans
|
|
|
24043
24595
|
*/
|
|
24044
24596
|
// PORTING NOTE: Multi-Tab only.
|
|
24045
24597
|
function synthesizeTargetToQuery(target) {
|
|
24046
|
-
return newQuery(target.path, target.collectionGroup, target.orderBy, target.filters, target.limit, "F" /* First */, target.startAt, target.endAt);
|
|
24598
|
+
return newQuery(target.path, target.collectionGroup, target.orderBy, target.filters, target.limit, "F" /* LimitType.First */, target.startAt, target.endAt);
|
|
24047
24599
|
}
|
|
24048
24600
|
/** Returns the IDs of the clients that are currently active. */
|
|
24049
24601
|
// PORTING NOTE: Multi-Tab only.
|
|
@@ -24374,7 +24926,7 @@ class OnlineComponentProvider {
|
|
|
24374
24926
|
this.eventManager = this.createEventManager(cfg);
|
|
24375
24927
|
this.syncEngine = this.createSyncEngine(cfg,
|
|
24376
24928
|
/* startAsPrimary=*/ !offlineComponentProvider.synchronizeTabs);
|
|
24377
|
-
this.sharedClientState.onlineStateHandler = onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 1 /* SharedClientState */);
|
|
24929
|
+
this.sharedClientState.onlineStateHandler = onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 1 /* OnlineStateSource.SharedClientState */);
|
|
24378
24930
|
this.remoteStore.remoteSyncer.handleCredentialChange =
|
|
24379
24931
|
syncEngineHandleCredentialChange.bind(null, this.syncEngine);
|
|
24380
24932
|
await remoteStoreApplyPrimaryState(this.remoteStore, this.syncEngine.isPrimaryClient);
|
|
@@ -24388,7 +24940,7 @@ class OnlineComponentProvider {
|
|
|
24388
24940
|
return newDatastore(cfg.authCredentials, cfg.appCheckCredentials, connection, serializer);
|
|
24389
24941
|
}
|
|
24390
24942
|
createRemoteStore(cfg) {
|
|
24391
|
-
return newRemoteStore(this.localStore, this.datastore, cfg.asyncQueue, onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 0 /* RemoteStore */), newConnectivityMonitor());
|
|
24943
|
+
return newRemoteStore(this.localStore, this.datastore, cfg.asyncQueue, onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 0 /* OnlineStateSource.RemoteStore */), newConnectivityMonitor());
|
|
24392
24944
|
}
|
|
24393
24945
|
createSyncEngine(cfg, startAsPrimary) {
|
|
24394
24946
|
return newSyncEngine(this.localStore, this.remoteStore, this.eventManager, this.sharedClientState, cfg.initialUser, cfg.maxConcurrentLimboResolutions, startAsPrimary);
|
|
@@ -25145,7 +25697,7 @@ class TransactionRunner {
|
|
|
25145
25697
|
this.updateFunction = updateFunction;
|
|
25146
25698
|
this.deferred = deferred;
|
|
25147
25699
|
this.attemptsRemaining = options.maxAttempts;
|
|
25148
|
-
this.backoff = new ExponentialBackoff(this.asyncQueue, "transaction_retry" /* TransactionRetry */);
|
|
25700
|
+
this.backoff = new ExponentialBackoff(this.asyncQueue, "transaction_retry" /* TimerId.TransactionRetry */);
|
|
25149
25701
|
}
|
|
25150
25702
|
/** Runs the transaction and sets the result on deferred. */
|
|
25151
25703
|
run() {
|
|
@@ -26178,7 +26730,7 @@ class AsyncQueueImpl {
|
|
|
26178
26730
|
// List of TimerIds to fast-forward delays for.
|
|
26179
26731
|
this.timerIdsToSkip = [];
|
|
26180
26732
|
// Backoff timer used to schedule retries for retryable operations
|
|
26181
|
-
this.backoff = new ExponentialBackoff(this, "async_queue_retry" /* AsyncQueueRetry */);
|
|
26733
|
+
this.backoff = new ExponentialBackoff(this, "async_queue_retry" /* TimerId.AsyncQueueRetry */);
|
|
26182
26734
|
// Visibility handler that triggers an immediate retry of all retryable
|
|
26183
26735
|
// operations. Meant to speed up recovery when we regain file system access
|
|
26184
26736
|
// after page comes into foreground.
|
|
@@ -26348,7 +26900,7 @@ class AsyncQueueImpl {
|
|
|
26348
26900
|
this.delayedOperations.sort((a, b) => a.targetTimeMs - b.targetTimeMs);
|
|
26349
26901
|
for (const op of this.delayedOperations) {
|
|
26350
26902
|
op.skipDelay();
|
|
26351
|
-
if (lastTimerId !== "all" /* All */ && op.timerId === lastTimerId) {
|
|
26903
|
+
if (lastTimerId !== "all" /* TimerId.All */ && op.timerId === lastTimerId) {
|
|
26352
26904
|
break;
|
|
26353
26905
|
}
|
|
26354
26906
|
}
|
|
@@ -27261,12 +27813,12 @@ class ParsedUpdateData {
|
|
|
27261
27813
|
}
|
|
27262
27814
|
function isWrite(dataSource) {
|
|
27263
27815
|
switch (dataSource) {
|
|
27264
|
-
case 0 /* Set */: // fall through
|
|
27265
|
-
case 2 /* MergeSet */: // fall through
|
|
27266
|
-
case 1 /* Update */:
|
|
27816
|
+
case 0 /* UserDataSource.Set */: // fall through
|
|
27817
|
+
case 2 /* UserDataSource.MergeSet */: // fall through
|
|
27818
|
+
case 1 /* UserDataSource.Update */:
|
|
27267
27819
|
return true;
|
|
27268
|
-
case 3 /* Argument */:
|
|
27269
|
-
case 4 /* ArrayArgument */:
|
|
27820
|
+
case 3 /* UserDataSource.Argument */:
|
|
27821
|
+
case 4 /* UserDataSource.ArrayArgument */:
|
|
27270
27822
|
return false;
|
|
27271
27823
|
default:
|
|
27272
27824
|
throw fail();
|
|
@@ -27391,8 +27943,8 @@ function newUserDataReader(firestore) {
|
|
|
27391
27943
|
/** Parse document data from a set() call. */
|
|
27392
27944
|
function parseSetData(userDataReader, methodName, targetDoc, input, hasConverter, options = {}) {
|
|
27393
27945
|
const context = userDataReader.createContext(options.merge || options.mergeFields
|
|
27394
|
-
? 2 /* MergeSet */
|
|
27395
|
-
: 0 /* Set */, methodName, targetDoc, hasConverter);
|
|
27946
|
+
? 2 /* UserDataSource.MergeSet */
|
|
27947
|
+
: 0 /* UserDataSource.Set */, methodName, targetDoc, hasConverter);
|
|
27396
27948
|
validatePlainObject('Data must be an object, but it was:', context, input);
|
|
27397
27949
|
const updateData = parseObject(input, context);
|
|
27398
27950
|
let fieldMask;
|
|
@@ -27423,12 +27975,12 @@ function parseSetData(userDataReader, methodName, targetDoc, input, hasConverter
|
|
|
27423
27975
|
}
|
|
27424
27976
|
class DeleteFieldValueImpl extends FieldValue {
|
|
27425
27977
|
_toFieldTransform(context) {
|
|
27426
|
-
if (context.dataSource === 2 /* MergeSet */) {
|
|
27978
|
+
if (context.dataSource === 2 /* UserDataSource.MergeSet */) {
|
|
27427
27979
|
// No transform to add for a delete, but we need to add it to our
|
|
27428
27980
|
// fieldMask so it gets deleted.
|
|
27429
27981
|
context.fieldMask.push(context.path);
|
|
27430
27982
|
}
|
|
27431
|
-
else if (context.dataSource === 1 /* Update */) {
|
|
27983
|
+
else if (context.dataSource === 1 /* UserDataSource.Update */) {
|
|
27432
27984
|
throw context.createError(`${this._methodName}() can only appear at the top level ` +
|
|
27433
27985
|
'of your update data');
|
|
27434
27986
|
}
|
|
@@ -27461,7 +28013,7 @@ class DeleteFieldValueImpl extends FieldValue {
|
|
|
27461
28013
|
*/
|
|
27462
28014
|
function createSentinelChildContext(fieldValue, context, arrayElement) {
|
|
27463
28015
|
return new ParseContextImpl({
|
|
27464
|
-
dataSource: 3 /* Argument */,
|
|
28016
|
+
dataSource: 3 /* UserDataSource.Argument */,
|
|
27465
28017
|
targetDoc: context.settings.targetDoc,
|
|
27466
28018
|
methodName: fieldValue._methodName,
|
|
27467
28019
|
arrayElement
|
|
@@ -27525,7 +28077,7 @@ class NumericIncrementFieldValueImpl extends FieldValue {
|
|
|
27525
28077
|
}
|
|
27526
28078
|
/** Parse update data from an update() call. */
|
|
27527
28079
|
function parseUpdateData(userDataReader, methodName, targetDoc, input) {
|
|
27528
|
-
const context = userDataReader.createContext(1 /* Update */, methodName, targetDoc);
|
|
28080
|
+
const context = userDataReader.createContext(1 /* UserDataSource.Update */, methodName, targetDoc);
|
|
27529
28081
|
validatePlainObject('Data must be an object, but it was:', context, input);
|
|
27530
28082
|
const fieldMaskPaths = [];
|
|
27531
28083
|
const updateData = ObjectValue.empty();
|
|
@@ -27552,7 +28104,7 @@ function parseUpdateData(userDataReader, methodName, targetDoc, input) {
|
|
|
27552
28104
|
}
|
|
27553
28105
|
/** Parse update data from a list of field/value arguments. */
|
|
27554
28106
|
function parseUpdateVarargs(userDataReader, methodName, targetDoc, field, value, moreFieldsAndValues) {
|
|
27555
|
-
const context = userDataReader.createContext(1 /* Update */, methodName, targetDoc);
|
|
28107
|
+
const context = userDataReader.createContext(1 /* UserDataSource.Update */, methodName, targetDoc);
|
|
27556
28108
|
const keys = [fieldPathFromArgument$1(methodName, field, targetDoc)];
|
|
27557
28109
|
const values = [value];
|
|
27558
28110
|
if (moreFieldsAndValues.length % 2 !== 0) {
|
|
@@ -27599,7 +28151,7 @@ function parseUpdateVarargs(userDataReader, methodName, targetDoc, field, value,
|
|
|
27599
28151
|
* contain additional arrays (e.g. the operand of an `in` query).
|
|
27600
28152
|
*/
|
|
27601
28153
|
function parseQueryValue(userDataReader, methodName, input, allowArrays = false) {
|
|
27602
|
-
const context = userDataReader.createContext(allowArrays ? 4 /* ArrayArgument */ : 3 /* Argument */, methodName);
|
|
28154
|
+
const context = userDataReader.createContext(allowArrays ? 4 /* UserDataSource.ArrayArgument */ : 3 /* UserDataSource.Argument */, methodName);
|
|
27603
28155
|
const parsed = parseData(input, context);
|
|
27604
28156
|
return parsed;
|
|
27605
28157
|
}
|
|
@@ -27649,7 +28201,7 @@ function parseData(input, context) {
|
|
|
27649
28201
|
// contain additional arrays (each representing an individual field
|
|
27650
28202
|
// value), so we disable this validation.
|
|
27651
28203
|
if (context.settings.arrayElement &&
|
|
27652
|
-
context.dataSource !== 4 /* ArrayArgument */) {
|
|
28204
|
+
context.dataSource !== 4 /* UserDataSource.ArrayArgument */) {
|
|
27653
28205
|
throw context.createError('Nested arrays are not supported');
|
|
27654
28206
|
}
|
|
27655
28207
|
return parseArray(input, context);
|
|
@@ -28031,164 +28583,334 @@ function fieldPathFromArgument(methodName, arg) {
|
|
|
28031
28583
|
* limitations under the License.
|
|
28032
28584
|
*/
|
|
28033
28585
|
function validateHasExplicitOrderByForLimitToLast(query) {
|
|
28034
|
-
if (query.limitType === "L" /* Last */ &&
|
|
28586
|
+
if (query.limitType === "L" /* LimitType.Last */ &&
|
|
28035
28587
|
query.explicitOrderBy.length === 0) {
|
|
28036
28588
|
throw new FirestoreError(Code.UNIMPLEMENTED, 'limitToLast() queries require specifying at least one orderBy() clause');
|
|
28037
28589
|
}
|
|
28038
28590
|
}
|
|
28591
|
+
/**
|
|
28592
|
+
* An `AppliableConstraint` is an abstraction of a constraint that can be applied
|
|
28593
|
+
* to a Firestore query.
|
|
28594
|
+
*/
|
|
28595
|
+
class AppliableConstraint {
|
|
28596
|
+
}
|
|
28039
28597
|
/**
|
|
28040
28598
|
* A `QueryConstraint` is used to narrow the set of documents returned by a
|
|
28041
28599
|
* Firestore query. `QueryConstraint`s are created by invoking {@link where},
|
|
28042
|
-
* {@link orderBy}, {@link
|
|
28043
|
-
* endBefore
|
|
28600
|
+
* {@link orderBy}, {@link startAt}, {@link startAfter}, {@link
|
|
28601
|
+
* endBefore}, {@link endAt}, {@link limit}, {@link limitToLast} and
|
|
28044
28602
|
* can then be passed to {@link query} to create a new query instance that
|
|
28045
28603
|
* also contains this `QueryConstraint`.
|
|
28046
28604
|
*/
|
|
28047
|
-
class QueryConstraint {
|
|
28605
|
+
class QueryConstraint extends AppliableConstraint {
|
|
28048
28606
|
}
|
|
28049
|
-
|
|
28050
|
-
|
|
28051
|
-
|
|
28052
|
-
|
|
28053
|
-
|
|
28054
|
-
|
|
28055
|
-
|
|
28056
|
-
* existing or new constraints.
|
|
28057
|
-
*/
|
|
28058
|
-
function query(query, ...queryConstraints) {
|
|
28607
|
+
function query(query, queryConstraint, ...additionalQueryConstraints) {
|
|
28608
|
+
let queryConstraints = [];
|
|
28609
|
+
if (queryConstraint instanceof AppliableConstraint) {
|
|
28610
|
+
queryConstraints.push(queryConstraint);
|
|
28611
|
+
}
|
|
28612
|
+
queryConstraints = queryConstraints.concat(additionalQueryConstraints);
|
|
28613
|
+
validateQueryConstraintArray(queryConstraints);
|
|
28059
28614
|
for (const constraint of queryConstraints) {
|
|
28060
28615
|
query = constraint._apply(query);
|
|
28061
28616
|
}
|
|
28062
28617
|
return query;
|
|
28063
28618
|
}
|
|
28064
|
-
|
|
28619
|
+
/**
|
|
28620
|
+
* A `QueryFieldFilterConstraint` is used to narrow the set of documents returned by
|
|
28621
|
+
* a Firestore query by filtering on one or more document fields.
|
|
28622
|
+
* `QueryFieldFilterConstraint`s are created by invoking {@link where} and can then
|
|
28623
|
+
* be passed to {@link query} to create a new query instance that also contains
|
|
28624
|
+
* this `QueryFieldFilterConstraint`.
|
|
28625
|
+
*/
|
|
28626
|
+
class QueryFieldFilterConstraint extends QueryConstraint {
|
|
28627
|
+
/**
|
|
28628
|
+
* @internal
|
|
28629
|
+
*/
|
|
28065
28630
|
constructor(_field, _op, _value) {
|
|
28066
28631
|
super();
|
|
28067
28632
|
this._field = _field;
|
|
28068
28633
|
this._op = _op;
|
|
28069
28634
|
this._value = _value;
|
|
28635
|
+
/** The type of this query constraint */
|
|
28070
28636
|
this.type = 'where';
|
|
28071
28637
|
}
|
|
28638
|
+
static _create(_field, _op, _value) {
|
|
28639
|
+
return new QueryFieldFilterConstraint(_field, _op, _value);
|
|
28640
|
+
}
|
|
28072
28641
|
_apply(query) {
|
|
28642
|
+
const filter = this._parse(query);
|
|
28643
|
+
validateNewFieldFilter(query._query, filter);
|
|
28644
|
+
return new Query(query.firestore, query.converter, queryWithAddedFilter(query._query, filter));
|
|
28645
|
+
}
|
|
28646
|
+
_parse(query) {
|
|
28073
28647
|
const reader = newUserDataReader(query.firestore);
|
|
28074
28648
|
const filter = newQueryFilter(query._query, 'where', reader, query.firestore._databaseId, this._field, this._op, this._value);
|
|
28075
|
-
return
|
|
28649
|
+
return filter;
|
|
28076
28650
|
}
|
|
28077
28651
|
}
|
|
28078
28652
|
/**
|
|
28079
|
-
* Creates a {@link
|
|
28080
|
-
* specified field and that the value should satisfy the
|
|
28081
|
-
* provided.
|
|
28653
|
+
* Creates a {@link QueryFieldFilterConstraint} that enforces that documents
|
|
28654
|
+
* must contain the specified field and that the value should satisfy the
|
|
28655
|
+
* relation constraint provided.
|
|
28082
28656
|
*
|
|
28083
28657
|
* @param fieldPath - The path to compare
|
|
28084
28658
|
* @param opStr - The operation string (e.g "<", "<=", "==", "<",
|
|
28085
28659
|
* "<=", "!=").
|
|
28086
28660
|
* @param value - The value for comparison
|
|
28087
|
-
* @returns The created {@link
|
|
28661
|
+
* @returns The created {@link QueryFieldFilterConstraint}.
|
|
28088
28662
|
*/
|
|
28089
28663
|
function where(fieldPath, opStr, value) {
|
|
28090
28664
|
const op = opStr;
|
|
28091
28665
|
const field = fieldPathFromArgument('where', fieldPath);
|
|
28092
|
-
return
|
|
28666
|
+
return QueryFieldFilterConstraint._create(field, op, value);
|
|
28667
|
+
}
|
|
28668
|
+
/**
|
|
28669
|
+
* A `QueryCompositeFilterConstraint` is used to narrow the set of documents
|
|
28670
|
+
* returned by a Firestore query by performing the logical OR or AND of multiple
|
|
28671
|
+
* {@link QueryFieldFilterConstraint}s or {@link QueryCompositeFilterConstraint}s.
|
|
28672
|
+
* `QueryCompositeFilterConstraint`s are created by invoking {@link or} or
|
|
28673
|
+
* {@link and} and can then be passed to {@link query} to create a new query
|
|
28674
|
+
* instance that also contains the `QueryCompositeFilterConstraint`.
|
|
28675
|
+
* @internal TODO remove this internal tag with OR Query support in the server
|
|
28676
|
+
*/
|
|
28677
|
+
class QueryCompositeFilterConstraint extends AppliableConstraint {
|
|
28678
|
+
/**
|
|
28679
|
+
* @internal
|
|
28680
|
+
*/
|
|
28681
|
+
constructor(
|
|
28682
|
+
/** The type of this query constraint */
|
|
28683
|
+
type, _queryConstraints) {
|
|
28684
|
+
super();
|
|
28685
|
+
this.type = type;
|
|
28686
|
+
this._queryConstraints = _queryConstraints;
|
|
28687
|
+
}
|
|
28688
|
+
static _create(type, _queryConstraints) {
|
|
28689
|
+
return new QueryCompositeFilterConstraint(type, _queryConstraints);
|
|
28690
|
+
}
|
|
28691
|
+
_parse(query) {
|
|
28692
|
+
const parsedFilters = this._queryConstraints
|
|
28693
|
+
.map(queryConstraint => {
|
|
28694
|
+
return queryConstraint._parse(query);
|
|
28695
|
+
})
|
|
28696
|
+
.filter(parsedFilter => parsedFilter.getFilters().length > 0);
|
|
28697
|
+
if (parsedFilters.length === 1) {
|
|
28698
|
+
return parsedFilters[0];
|
|
28699
|
+
}
|
|
28700
|
+
return CompositeFilter.create(parsedFilters, this._getOperator());
|
|
28701
|
+
}
|
|
28702
|
+
_apply(query) {
|
|
28703
|
+
const parsedFilter = this._parse(query);
|
|
28704
|
+
if (parsedFilter.getFilters().length === 0) {
|
|
28705
|
+
// Return the existing query if not adding any more filters (e.g. an empty
|
|
28706
|
+
// composite filter).
|
|
28707
|
+
return query;
|
|
28708
|
+
}
|
|
28709
|
+
validateNewFilter(query._query, parsedFilter);
|
|
28710
|
+
return new Query(query.firestore, query.converter, queryWithAddedFilter(query._query, parsedFilter));
|
|
28711
|
+
}
|
|
28712
|
+
_getQueryConstraints() {
|
|
28713
|
+
return this._queryConstraints;
|
|
28714
|
+
}
|
|
28715
|
+
_getOperator() {
|
|
28716
|
+
return this.type === 'and' ? "and" /* CompositeOperator.AND */ : "or" /* CompositeOperator.OR */;
|
|
28717
|
+
}
|
|
28718
|
+
}
|
|
28719
|
+
/**
|
|
28720
|
+
* Creates a {@link QueryCompositeFilterConstraint} that performs a logical OR
|
|
28721
|
+
* of all the provided {@link QueryFilterConstraint}s.
|
|
28722
|
+
*
|
|
28723
|
+
* @param queryConstraints - Optional. The {@link QueryFilterConstraint}s
|
|
28724
|
+
* for OR operation. These must be created with calls to {@link where},
|
|
28725
|
+
* {@link or}, or {@link and}.
|
|
28726
|
+
* @returns The created {@link QueryCompositeFilterConstraint}.
|
|
28727
|
+
* @internal TODO remove this internal tag with OR Query support in the server
|
|
28728
|
+
*/
|
|
28729
|
+
function or(...queryConstraints) {
|
|
28730
|
+
// Only support QueryFilterConstraints
|
|
28731
|
+
queryConstraints.forEach(queryConstraint => validateQueryFilterConstraint('or', queryConstraint));
|
|
28732
|
+
return QueryCompositeFilterConstraint._create("or" /* CompositeOperator.OR */, queryConstraints);
|
|
28733
|
+
}
|
|
28734
|
+
/**
|
|
28735
|
+
* Creates a {@link QueryCompositeFilterConstraint} that performs a logical AND
|
|
28736
|
+
* of all the provided {@link QueryFilterConstraint}s.
|
|
28737
|
+
*
|
|
28738
|
+
* @param queryConstraints - Optional. The {@link QueryFilterConstraint}s
|
|
28739
|
+
* for AND operation. These must be created with calls to {@link where},
|
|
28740
|
+
* {@link or}, or {@link and}.
|
|
28741
|
+
* @returns The created {@link QueryCompositeFilterConstraint}.
|
|
28742
|
+
* @internal TODO remove this internal tag with OR Query support in the server
|
|
28743
|
+
*/
|
|
28744
|
+
function and(...queryConstraints) {
|
|
28745
|
+
// Only support QueryFilterConstraints
|
|
28746
|
+
queryConstraints.forEach(queryConstraint => validateQueryFilterConstraint('and', queryConstraint));
|
|
28747
|
+
return QueryCompositeFilterConstraint._create("and" /* CompositeOperator.AND */, queryConstraints);
|
|
28093
28748
|
}
|
|
28749
|
+
/**
|
|
28750
|
+
* A `QueryOrderByConstraint` is used to sort the set of documents returned by a
|
|
28751
|
+
* Firestore query. `QueryOrderByConstraint`s are created by invoking
|
|
28752
|
+
* {@link orderBy} and can then be passed to {@link query} to create a new query
|
|
28753
|
+
* instance that also contains this `QueryOrderByConstraint`.
|
|
28754
|
+
*
|
|
28755
|
+
* Note: Documents that do not contain the orderBy field will not be present in
|
|
28756
|
+
* the query result.
|
|
28757
|
+
*/
|
|
28094
28758
|
class QueryOrderByConstraint extends QueryConstraint {
|
|
28759
|
+
/**
|
|
28760
|
+
* @internal
|
|
28761
|
+
*/
|
|
28095
28762
|
constructor(_field, _direction) {
|
|
28096
28763
|
super();
|
|
28097
28764
|
this._field = _field;
|
|
28098
28765
|
this._direction = _direction;
|
|
28766
|
+
/** The type of this query constraint */
|
|
28099
28767
|
this.type = 'orderBy';
|
|
28100
28768
|
}
|
|
28769
|
+
static _create(_field, _direction) {
|
|
28770
|
+
return new QueryOrderByConstraint(_field, _direction);
|
|
28771
|
+
}
|
|
28101
28772
|
_apply(query) {
|
|
28102
28773
|
const orderBy = newQueryOrderBy(query._query, this._field, this._direction);
|
|
28103
28774
|
return new Query(query.firestore, query.converter, queryWithAddedOrderBy(query._query, orderBy));
|
|
28104
28775
|
}
|
|
28105
28776
|
}
|
|
28106
28777
|
/**
|
|
28107
|
-
* Creates a {@link
|
|
28778
|
+
* Creates a {@link QueryOrderByConstraint} that sorts the query result by the
|
|
28108
28779
|
* specified field, optionally in descending order instead of ascending.
|
|
28109
28780
|
*
|
|
28781
|
+
* Note: Documents that do not contain the specified field will not be present
|
|
28782
|
+
* in the query result.
|
|
28783
|
+
*
|
|
28110
28784
|
* @param fieldPath - The field to sort by.
|
|
28111
28785
|
* @param directionStr - Optional direction to sort by ('asc' or 'desc'). If
|
|
28112
28786
|
* not specified, order will be ascending.
|
|
28113
|
-
* @returns The created {@link
|
|
28787
|
+
* @returns The created {@link QueryOrderByConstraint}.
|
|
28114
28788
|
*/
|
|
28115
28789
|
function orderBy(fieldPath, directionStr = 'asc') {
|
|
28116
28790
|
const direction = directionStr;
|
|
28117
28791
|
const path = fieldPathFromArgument('orderBy', fieldPath);
|
|
28118
|
-
return
|
|
28792
|
+
return QueryOrderByConstraint._create(path, direction);
|
|
28119
28793
|
}
|
|
28794
|
+
/**
|
|
28795
|
+
* A `QueryLimitConstraint` is used to limit the number of documents returned by
|
|
28796
|
+
* a Firestore query.
|
|
28797
|
+
* `QueryLimitConstraint`s are created by invoking {@link limit} or
|
|
28798
|
+
* {@link limitToLast} and can then be passed to {@link query} to create a new
|
|
28799
|
+
* query instance that also contains this `QueryLimitConstraint`.
|
|
28800
|
+
*/
|
|
28120
28801
|
class QueryLimitConstraint extends QueryConstraint {
|
|
28121
|
-
|
|
28802
|
+
/**
|
|
28803
|
+
* @internal
|
|
28804
|
+
*/
|
|
28805
|
+
constructor(
|
|
28806
|
+
/** The type of this query constraint */
|
|
28807
|
+
type, _limit, _limitType) {
|
|
28122
28808
|
super();
|
|
28123
28809
|
this.type = type;
|
|
28124
28810
|
this._limit = _limit;
|
|
28125
28811
|
this._limitType = _limitType;
|
|
28126
28812
|
}
|
|
28813
|
+
static _create(type, _limit, _limitType) {
|
|
28814
|
+
return new QueryLimitConstraint(type, _limit, _limitType);
|
|
28815
|
+
}
|
|
28127
28816
|
_apply(query) {
|
|
28128
28817
|
return new Query(query.firestore, query.converter, queryWithLimit(query._query, this._limit, this._limitType));
|
|
28129
28818
|
}
|
|
28130
28819
|
}
|
|
28131
28820
|
/**
|
|
28132
|
-
* Creates a {@link
|
|
28821
|
+
* Creates a {@link QueryLimitConstraint} that only returns the first matching
|
|
28822
|
+
* documents.
|
|
28133
28823
|
*
|
|
28134
28824
|
* @param limit - The maximum number of items to return.
|
|
28135
|
-
* @returns The created {@link
|
|
28825
|
+
* @returns The created {@link QueryLimitConstraint}.
|
|
28136
28826
|
*/
|
|
28137
28827
|
function limit(limit) {
|
|
28138
28828
|
validatePositiveNumber('limit', limit);
|
|
28139
|
-
return
|
|
28829
|
+
return QueryLimitConstraint._create('limit', limit, "F" /* LimitType.First */);
|
|
28140
28830
|
}
|
|
28141
28831
|
/**
|
|
28142
|
-
* Creates a {@link
|
|
28832
|
+
* Creates a {@link QueryLimitConstraint} that only returns the last matching
|
|
28833
|
+
* documents.
|
|
28143
28834
|
*
|
|
28144
28835
|
* You must specify at least one `orderBy` clause for `limitToLast` queries,
|
|
28145
28836
|
* otherwise an exception will be thrown during execution.
|
|
28146
28837
|
*
|
|
28147
28838
|
* @param limit - The maximum number of items to return.
|
|
28148
|
-
* @returns The created {@link
|
|
28839
|
+
* @returns The created {@link QueryLimitConstraint}.
|
|
28149
28840
|
*/
|
|
28150
28841
|
function limitToLast(limit) {
|
|
28151
28842
|
validatePositiveNumber('limitToLast', limit);
|
|
28152
|
-
return
|
|
28843
|
+
return QueryLimitConstraint._create('limitToLast', limit, "L" /* LimitType.Last */);
|
|
28153
28844
|
}
|
|
28845
|
+
/**
|
|
28846
|
+
* A `QueryStartAtConstraint` is used to exclude documents from the start of a
|
|
28847
|
+
* result set returned by a Firestore query.
|
|
28848
|
+
* `QueryStartAtConstraint`s are created by invoking {@link (startAt:1)} or
|
|
28849
|
+
* {@link (startAfter:1)} and can then be passed to {@link query} to create a
|
|
28850
|
+
* new query instance that also contains this `QueryStartAtConstraint`.
|
|
28851
|
+
*/
|
|
28154
28852
|
class QueryStartAtConstraint extends QueryConstraint {
|
|
28155
|
-
|
|
28853
|
+
/**
|
|
28854
|
+
* @internal
|
|
28855
|
+
*/
|
|
28856
|
+
constructor(
|
|
28857
|
+
/** The type of this query constraint */
|
|
28858
|
+
type, _docOrFields, _inclusive) {
|
|
28156
28859
|
super();
|
|
28157
28860
|
this.type = type;
|
|
28158
28861
|
this._docOrFields = _docOrFields;
|
|
28159
28862
|
this._inclusive = _inclusive;
|
|
28160
28863
|
}
|
|
28864
|
+
static _create(type, _docOrFields, _inclusive) {
|
|
28865
|
+
return new QueryStartAtConstraint(type, _docOrFields, _inclusive);
|
|
28866
|
+
}
|
|
28161
28867
|
_apply(query) {
|
|
28162
28868
|
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
|
|
28163
28869
|
return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
|
|
28164
28870
|
}
|
|
28165
28871
|
}
|
|
28166
28872
|
function startAt(...docOrFields) {
|
|
28167
|
-
return
|
|
28873
|
+
return QueryStartAtConstraint._create('startAt', docOrFields,
|
|
28168
28874
|
/*inclusive=*/ true);
|
|
28169
28875
|
}
|
|
28170
28876
|
function startAfter(...docOrFields) {
|
|
28171
|
-
return
|
|
28877
|
+
return QueryStartAtConstraint._create('startAfter', docOrFields,
|
|
28172
28878
|
/*inclusive=*/ false);
|
|
28173
28879
|
}
|
|
28880
|
+
/**
|
|
28881
|
+
* A `QueryEndAtConstraint` is used to exclude documents from the end of a
|
|
28882
|
+
* result set returned by a Firestore query.
|
|
28883
|
+
* `QueryEndAtConstraint`s are created by invoking {@link (endAt:1)} or
|
|
28884
|
+
* {@link (endBefore:1)} and can then be passed to {@link query} to create a new
|
|
28885
|
+
* query instance that also contains this `QueryEndAtConstraint`.
|
|
28886
|
+
*/
|
|
28174
28887
|
class QueryEndAtConstraint extends QueryConstraint {
|
|
28175
|
-
|
|
28888
|
+
/**
|
|
28889
|
+
* @internal
|
|
28890
|
+
*/
|
|
28891
|
+
constructor(
|
|
28892
|
+
/** The type of this query constraint */
|
|
28893
|
+
type, _docOrFields, _inclusive) {
|
|
28176
28894
|
super();
|
|
28177
28895
|
this.type = type;
|
|
28178
28896
|
this._docOrFields = _docOrFields;
|
|
28179
28897
|
this._inclusive = _inclusive;
|
|
28180
28898
|
}
|
|
28899
|
+
static _create(type, _docOrFields, _inclusive) {
|
|
28900
|
+
return new QueryEndAtConstraint(type, _docOrFields, _inclusive);
|
|
28901
|
+
}
|
|
28181
28902
|
_apply(query) {
|
|
28182
28903
|
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
|
|
28183
28904
|
return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
|
|
28184
28905
|
}
|
|
28185
28906
|
}
|
|
28186
28907
|
function endBefore(...docOrFields) {
|
|
28187
|
-
return
|
|
28908
|
+
return QueryEndAtConstraint._create('endBefore', docOrFields,
|
|
28188
28909
|
/*inclusive=*/ false);
|
|
28189
28910
|
}
|
|
28190
28911
|
function endAt(...docOrFields) {
|
|
28191
|
-
return
|
|
28912
|
+
return QueryEndAtConstraint._create('endAt', docOrFields,
|
|
28913
|
+
/*inclusive=*/ true);
|
|
28192
28914
|
}
|
|
28193
28915
|
/** Helper function to create a bound from a document or fields */
|
|
28194
28916
|
function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
|
|
@@ -28204,10 +28926,10 @@ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive)
|
|
|
28204
28926
|
function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
|
|
28205
28927
|
let fieldValue;
|
|
28206
28928
|
if (fieldPath.isKeyField()) {
|
|
28207
|
-
if (op === "array-contains" /* ARRAY_CONTAINS */ || op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
28929
|
+
if (op === "array-contains" /* Operator.ARRAY_CONTAINS */ || op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
28208
28930
|
throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid Query. You can't perform '${op}' queries on documentId().`);
|
|
28209
28931
|
}
|
|
28210
|
-
else if (op === "in" /* IN */ || op === "not-in" /* NOT_IN */) {
|
|
28932
|
+
else if (op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */) {
|
|
28211
28933
|
validateDisjunctiveFilterElements(value, op);
|
|
28212
28934
|
const referenceList = [];
|
|
28213
28935
|
for (const arrayValue of value) {
|
|
@@ -28220,16 +28942,15 @@ function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op
|
|
|
28220
28942
|
}
|
|
28221
28943
|
}
|
|
28222
28944
|
else {
|
|
28223
|
-
if (op === "in" /* IN */ ||
|
|
28224
|
-
op === "not-in" /* NOT_IN */ ||
|
|
28225
|
-
op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
28945
|
+
if (op === "in" /* Operator.IN */ ||
|
|
28946
|
+
op === "not-in" /* Operator.NOT_IN */ ||
|
|
28947
|
+
op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
28226
28948
|
validateDisjunctiveFilterElements(value, op);
|
|
28227
28949
|
}
|
|
28228
28950
|
fieldValue = parseQueryValue(dataReader, methodName, value,
|
|
28229
|
-
/* allowArrays= */ op === "in" /* IN */ || op === "not-in" /* NOT_IN */);
|
|
28951
|
+
/* allowArrays= */ op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */);
|
|
28230
28952
|
}
|
|
28231
28953
|
const filter = FieldFilter.create(fieldPath, op, fieldValue);
|
|
28232
|
-
validateNewFilter(query, filter);
|
|
28233
28954
|
return filter;
|
|
28234
28955
|
}
|
|
28235
28956
|
function newQueryOrderBy(query, fieldPath, direction) {
|
|
@@ -28399,62 +29120,84 @@ function validateDisjunctiveFilterElements(value, operator) {
|
|
|
28399
29120
|
*/
|
|
28400
29121
|
function conflictingOps(op) {
|
|
28401
29122
|
switch (op) {
|
|
28402
|
-
case "!=" /* NOT_EQUAL */:
|
|
28403
|
-
return ["!=" /* NOT_EQUAL */, "not-in" /* NOT_IN */];
|
|
28404
|
-
case "array-contains" /* ARRAY_CONTAINS */:
|
|
29123
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
29124
|
+
return ["!=" /* Operator.NOT_EQUAL */, "not-in" /* Operator.NOT_IN */];
|
|
29125
|
+
case "array-contains" /* Operator.ARRAY_CONTAINS */:
|
|
28405
29126
|
return [
|
|
28406
|
-
"array-contains" /* ARRAY_CONTAINS */,
|
|
28407
|
-
"array-contains-any" /* ARRAY_CONTAINS_ANY */,
|
|
28408
|
-
"not-in" /* NOT_IN */
|
|
29127
|
+
"array-contains" /* Operator.ARRAY_CONTAINS */,
|
|
29128
|
+
"array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */,
|
|
29129
|
+
"not-in" /* Operator.NOT_IN */
|
|
28409
29130
|
];
|
|
28410
|
-
case "in" /* IN */:
|
|
28411
|
-
return ["array-contains-any" /* ARRAY_CONTAINS_ANY */, "in" /* IN */, "not-in" /* NOT_IN */];
|
|
28412
|
-
case "array-contains-any" /* ARRAY_CONTAINS_ANY */:
|
|
29131
|
+
case "in" /* Operator.IN */:
|
|
29132
|
+
return ["array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */, "in" /* Operator.IN */, "not-in" /* Operator.NOT_IN */];
|
|
29133
|
+
case "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */:
|
|
28413
29134
|
return [
|
|
28414
|
-
"array-contains" /* ARRAY_CONTAINS */,
|
|
28415
|
-
"array-contains-any" /* ARRAY_CONTAINS_ANY */,
|
|
28416
|
-
"in" /* IN */,
|
|
28417
|
-
"not-in" /* NOT_IN */
|
|
29135
|
+
"array-contains" /* Operator.ARRAY_CONTAINS */,
|
|
29136
|
+
"array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */,
|
|
29137
|
+
"in" /* Operator.IN */,
|
|
29138
|
+
"not-in" /* Operator.NOT_IN */
|
|
28418
29139
|
];
|
|
28419
|
-
case "not-in" /* NOT_IN */:
|
|
29140
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
28420
29141
|
return [
|
|
28421
|
-
"array-contains" /* ARRAY_CONTAINS */,
|
|
28422
|
-
"array-contains-any" /* ARRAY_CONTAINS_ANY */,
|
|
28423
|
-
"in" /* IN */,
|
|
28424
|
-
"not-in" /* NOT_IN */,
|
|
28425
|
-
"!=" /* NOT_EQUAL */
|
|
29142
|
+
"array-contains" /* Operator.ARRAY_CONTAINS */,
|
|
29143
|
+
"array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */,
|
|
29144
|
+
"in" /* Operator.IN */,
|
|
29145
|
+
"not-in" /* Operator.NOT_IN */,
|
|
29146
|
+
"!=" /* Operator.NOT_EQUAL */
|
|
28426
29147
|
];
|
|
28427
29148
|
default:
|
|
28428
29149
|
return [];
|
|
28429
29150
|
}
|
|
28430
29151
|
}
|
|
28431
|
-
function
|
|
28432
|
-
if (
|
|
28433
|
-
const
|
|
28434
|
-
|
|
29152
|
+
function validateNewFieldFilter(query, fieldFilter) {
|
|
29153
|
+
if (fieldFilter.isInequality()) {
|
|
29154
|
+
const existingInequality = getInequalityFilterField(query);
|
|
29155
|
+
const newInequality = fieldFilter.field;
|
|
29156
|
+
if (existingInequality !== null &&
|
|
29157
|
+
!existingInequality.isEqual(newInequality)) {
|
|
28435
29158
|
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Invalid query. All where filters with an inequality' +
|
|
28436
29159
|
' (<, <=, !=, not-in, >, or >=) must be on the same field. But you have' +
|
|
28437
|
-
` inequality filters on '${
|
|
28438
|
-
` and '${
|
|
29160
|
+
` inequality filters on '${existingInequality.toString()}'` +
|
|
29161
|
+
` and '${newInequality.toString()}'`);
|
|
28439
29162
|
}
|
|
28440
29163
|
const firstOrderByField = getFirstOrderByField(query);
|
|
28441
29164
|
if (firstOrderByField !== null) {
|
|
28442
|
-
validateOrderByAndInequalityMatch(query,
|
|
29165
|
+
validateOrderByAndInequalityMatch(query, newInequality, firstOrderByField);
|
|
28443
29166
|
}
|
|
28444
29167
|
}
|
|
28445
|
-
const conflictingOp =
|
|
29168
|
+
const conflictingOp = findOpInsideFilters(query.filters, conflictingOps(fieldFilter.op));
|
|
28446
29169
|
if (conflictingOp !== null) {
|
|
28447
29170
|
// Special case when it's a duplicate op to give a slightly clearer error message.
|
|
28448
|
-
if (conflictingOp ===
|
|
29171
|
+
if (conflictingOp === fieldFilter.op) {
|
|
28449
29172
|
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Invalid query. You cannot use more than one ' +
|
|
28450
|
-
`'${
|
|
29173
|
+
`'${fieldFilter.op.toString()}' filter.`);
|
|
28451
29174
|
}
|
|
28452
29175
|
else {
|
|
28453
|
-
throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid query. You cannot use '${
|
|
29176
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid query. You cannot use '${fieldFilter.op.toString()}' filters ` +
|
|
28454
29177
|
`with '${conflictingOp.toString()}' filters.`);
|
|
28455
29178
|
}
|
|
28456
29179
|
}
|
|
28457
29180
|
}
|
|
29181
|
+
function validateNewFilter(query, filter) {
|
|
29182
|
+
let testQuery = query;
|
|
29183
|
+
const subFilters = filter.getFlattenedFilters();
|
|
29184
|
+
for (const subFilter of subFilters) {
|
|
29185
|
+
validateNewFieldFilter(testQuery, subFilter);
|
|
29186
|
+
testQuery = queryWithAddedFilter(testQuery, subFilter);
|
|
29187
|
+
}
|
|
29188
|
+
}
|
|
29189
|
+
// Checks if any of the provided filter operators are included in the given list of filters and
|
|
29190
|
+
// returns the first one that is, or null if none are.
|
|
29191
|
+
function findOpInsideFilters(filters, operators) {
|
|
29192
|
+
for (const filter of filters) {
|
|
29193
|
+
for (const fieldFilter of filter.getFlattenedFilters()) {
|
|
29194
|
+
if (operators.indexOf(fieldFilter.op) >= 0) {
|
|
29195
|
+
return fieldFilter.op;
|
|
29196
|
+
}
|
|
29197
|
+
}
|
|
29198
|
+
}
|
|
29199
|
+
return null;
|
|
29200
|
+
}
|
|
28458
29201
|
function validateNewOrderBy(query, orderBy) {
|
|
28459
29202
|
if (getFirstOrderByField(query) === null) {
|
|
28460
29203
|
// This is the first order by. It must match any inequality.
|
|
@@ -28472,6 +29215,24 @@ function validateOrderByAndInequalityMatch(baseQuery, inequality, orderBy) {
|
|
|
28472
29215
|
`as your first argument to orderBy(), but your first orderBy() ` +
|
|
28473
29216
|
`is on field '${orderBy.toString()}' instead.`);
|
|
28474
29217
|
}
|
|
29218
|
+
}
|
|
29219
|
+
function validateQueryFilterConstraint(functionName, queryConstraint) {
|
|
29220
|
+
if (!(queryConstraint instanceof QueryFieldFilterConstraint) &&
|
|
29221
|
+
!(queryConstraint instanceof QueryCompositeFilterConstraint)) {
|
|
29222
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, `Function ${functionName}() requires AppliableConstraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`);
|
|
29223
|
+
}
|
|
29224
|
+
}
|
|
29225
|
+
function validateQueryConstraintArray(queryConstraint) {
|
|
29226
|
+
const compositeFilterCount = queryConstraint.filter(filter => filter instanceof QueryCompositeFilterConstraint).length;
|
|
29227
|
+
const fieldFilterCount = queryConstraint.filter(filter => filter instanceof QueryFieldFilterConstraint).length;
|
|
29228
|
+
if (compositeFilterCount > 1 ||
|
|
29229
|
+
(compositeFilterCount > 0 && fieldFilterCount > 0)) {
|
|
29230
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, 'InvalidQuery. When using composite filters, you cannot use ' +
|
|
29231
|
+
'more than one filter at the top level. Consider nesting the multiple ' +
|
|
29232
|
+
'filters within an `and(...)` statement. For example: ' +
|
|
29233
|
+
'change `query(query, where(...), or(...))` to ' +
|
|
29234
|
+
'`query(query, and(where(...), or(...)))`.');
|
|
29235
|
+
}
|
|
28475
29236
|
}
|
|
28476
29237
|
|
|
28477
29238
|
/**
|
|
@@ -28499,27 +29260,27 @@ function validateOrderByAndInequalityMatch(baseQuery, inequality, orderBy) {
|
|
|
28499
29260
|
class AbstractUserDataWriter {
|
|
28500
29261
|
convertValue(value, serverTimestampBehavior = 'none') {
|
|
28501
29262
|
switch (typeOrder(value)) {
|
|
28502
|
-
case 0 /* NullValue */:
|
|
29263
|
+
case 0 /* TypeOrder.NullValue */:
|
|
28503
29264
|
return null;
|
|
28504
|
-
case 1 /* BooleanValue */:
|
|
29265
|
+
case 1 /* TypeOrder.BooleanValue */:
|
|
28505
29266
|
return value.booleanValue;
|
|
28506
|
-
case 2 /* NumberValue */:
|
|
29267
|
+
case 2 /* TypeOrder.NumberValue */:
|
|
28507
29268
|
return normalizeNumber(value.integerValue || value.doubleValue);
|
|
28508
|
-
case 3 /* TimestampValue */:
|
|
29269
|
+
case 3 /* TypeOrder.TimestampValue */:
|
|
28509
29270
|
return this.convertTimestamp(value.timestampValue);
|
|
28510
|
-
case 4 /* ServerTimestampValue */:
|
|
29271
|
+
case 4 /* TypeOrder.ServerTimestampValue */:
|
|
28511
29272
|
return this.convertServerTimestamp(value, serverTimestampBehavior);
|
|
28512
|
-
case 5 /* StringValue */:
|
|
29273
|
+
case 5 /* TypeOrder.StringValue */:
|
|
28513
29274
|
return value.stringValue;
|
|
28514
|
-
case 6 /* BlobValue */:
|
|
29275
|
+
case 6 /* TypeOrder.BlobValue */:
|
|
28515
29276
|
return this.convertBytes(normalizeByteString(value.bytesValue));
|
|
28516
|
-
case 7 /* RefValue */:
|
|
29277
|
+
case 7 /* TypeOrder.RefValue */:
|
|
28517
29278
|
return this.convertReference(value.referenceValue);
|
|
28518
|
-
case 8 /* GeoPointValue */:
|
|
29279
|
+
case 8 /* TypeOrder.GeoPointValue */:
|
|
28519
29280
|
return this.convertGeoPoint(value.geoPointValue);
|
|
28520
|
-
case 9 /* ArrayValue */:
|
|
29281
|
+
case 9 /* TypeOrder.ArrayValue */:
|
|
28521
29282
|
return this.convertArray(value.arrayValue, serverTimestampBehavior);
|
|
28522
|
-
case 10 /* ObjectValue */:
|
|
29283
|
+
case 10 /* TypeOrder.ObjectValue */:
|
|
28523
29284
|
return this.convertObject(value.mapValue, serverTimestampBehavior);
|
|
28524
29285
|
default:
|
|
28525
29286
|
throw fail();
|
|
@@ -28861,16 +29622,16 @@ function changesFromSnapshot(querySnapshot, includeMetadataChanges) {
|
|
|
28861
29622
|
// to lookup the index of a document.
|
|
28862
29623
|
let indexTracker = querySnapshot._snapshot.oldDocs;
|
|
28863
29624
|
return querySnapshot._snapshot.docChanges
|
|
28864
|
-
.filter(change => includeMetadataChanges || change.type !== 3 /* Metadata */)
|
|
29625
|
+
.filter(change => includeMetadataChanges || change.type !== 3 /* ChangeType.Metadata */)
|
|
28865
29626
|
.map(change => {
|
|
28866
29627
|
const doc = new QueryDocumentSnapshot(querySnapshot._firestore, querySnapshot._userDataWriter, change.doc.key, change.doc, new SnapshotMetadata(querySnapshot._snapshot.mutatedKeys.has(change.doc.key), querySnapshot._snapshot.fromCache), querySnapshot.query.converter);
|
|
28867
29628
|
let oldIndex = -1;
|
|
28868
29629
|
let newIndex = -1;
|
|
28869
|
-
if (change.type !== 0 /* Added */) {
|
|
29630
|
+
if (change.type !== 0 /* ChangeType.Added */) {
|
|
28870
29631
|
oldIndex = indexTracker.indexOf(change.doc.key);
|
|
28871
29632
|
indexTracker = indexTracker.delete(change.doc.key);
|
|
28872
29633
|
}
|
|
28873
|
-
if (change.type !== 1 /* Removed */) {
|
|
29634
|
+
if (change.type !== 1 /* ChangeType.Removed */) {
|
|
28874
29635
|
indexTracker = indexTracker.add(change.doc);
|
|
28875
29636
|
newIndex = indexTracker.indexOf(change.doc.key);
|
|
28876
29637
|
}
|
|
@@ -28885,12 +29646,12 @@ function changesFromSnapshot(querySnapshot, includeMetadataChanges) {
|
|
|
28885
29646
|
}
|
|
28886
29647
|
function resultChangeType(type) {
|
|
28887
29648
|
switch (type) {
|
|
28888
|
-
case 0 /* Added */:
|
|
29649
|
+
case 0 /* ChangeType.Added */:
|
|
28889
29650
|
return 'added';
|
|
28890
|
-
case 2 /* Modified */:
|
|
28891
|
-
case 3 /* Metadata */:
|
|
29651
|
+
case 2 /* ChangeType.Modified */:
|
|
29652
|
+
case 3 /* ChangeType.Metadata */:
|
|
28892
29653
|
return 'modified';
|
|
28893
|
-
case 1 /* Removed */:
|
|
29654
|
+
case 1 /* ChangeType.Removed */:
|
|
28894
29655
|
return 'removed';
|
|
28895
29656
|
default:
|
|
28896
29657
|
return fail();
|
|
@@ -29724,13 +30485,13 @@ function parseIndexes(jsonOrConfiguration) {
|
|
|
29724
30485
|
const fieldPathString = tryGetString(field, 'fieldPath');
|
|
29725
30486
|
const fieldPath = fieldPathFromDotSeparatedString('setIndexConfiguration', fieldPathString);
|
|
29726
30487
|
if (field.arrayConfig === 'CONTAINS') {
|
|
29727
|
-
segments.push(new IndexSegment(fieldPath, 2 /* CONTAINS */));
|
|
30488
|
+
segments.push(new IndexSegment(fieldPath, 2 /* IndexKind.CONTAINS */));
|
|
29728
30489
|
}
|
|
29729
30490
|
else if (field.order === 'ASCENDING') {
|
|
29730
|
-
segments.push(new IndexSegment(fieldPath, 0 /* ASCENDING */));
|
|
30491
|
+
segments.push(new IndexSegment(fieldPath, 0 /* IndexKind.ASCENDING */));
|
|
29731
30492
|
}
|
|
29732
30493
|
else if (field.order === 'DESCENDING') {
|
|
29733
|
-
segments.push(new IndexSegment(fieldPath, 1 /* DESCENDING */));
|
|
30494
|
+
segments.push(new IndexSegment(fieldPath, 1 /* IndexKind.DESCENDING */));
|
|
29734
30495
|
}
|
|
29735
30496
|
}
|
|
29736
30497
|
}
|
|
@@ -29740,12 +30501,11 @@ function parseIndexes(jsonOrConfiguration) {
|
|
|
29740
30501
|
return parsedIndexes;
|
|
29741
30502
|
}
|
|
29742
30503
|
function tryParseJson(json) {
|
|
29743
|
-
var _a;
|
|
29744
30504
|
try {
|
|
29745
30505
|
return JSON.parse(json);
|
|
29746
30506
|
}
|
|
29747
30507
|
catch (e) {
|
|
29748
|
-
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Failed to parse JSON: ' + (
|
|
30508
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Failed to parse JSON: ' + (e === null || e === void 0 ? void 0 : e.message));
|
|
29749
30509
|
}
|
|
29750
30510
|
}
|
|
29751
30511
|
function tryGetString(data, property) {
|
|
@@ -29773,5 +30533,5 @@ function tryGetString(data, property) {
|
|
|
29773
30533
|
*/
|
|
29774
30534
|
registerFirestore('node');
|
|
29775
30535
|
|
|
29776
|
-
export { AbstractUserDataWriter, AggregateField, AggregateQuerySnapshot, Bytes, CACHE_SIZE_UNLIMITED, CollectionReference, DocumentReference, DocumentSnapshot, FieldPath, FieldValue, Firestore, FirestoreError, GeoPoint, LoadBundleTask, Query, QueryConstraint, QueryDocumentSnapshot, QuerySnapshot, SnapshotMetadata, Timestamp, Transaction, WriteBatch, DatabaseId as _DatabaseId, DocumentKey as _DocumentKey, EmptyAppCheckTokenProvider as _EmptyAppCheckTokenProvider, EmptyAuthCredentialsProvider as _EmptyAuthCredentialsProvider, FieldPath$1 as _FieldPath, cast as _cast, debugAssert as _debugAssert, isBase64Available as _isBase64Available, logWarn as _logWarn, validateIsNotUsedTogether as _validateIsNotUsedTogether, addDoc, aggregateQuerySnapshotEqual, arrayRemove, arrayUnion, clearIndexedDbPersistence, collection, collectionGroup, connectFirestoreEmulator, deleteDoc, deleteField, disableNetwork, doc, documentId, enableIndexedDbPersistence, enableMultiTabIndexedDbPersistence, enableNetwork, endAt, endBefore, ensureFirestoreConfigured, executeWrite, getCountFromServer, getDoc, getDocFromCache, getDocFromServer, getDocs, getDocsFromCache, getDocsFromServer, getFirestore, increment, initializeFirestore, limit, limitToLast, loadBundle, namedQuery, onSnapshot, onSnapshotsInSync, orderBy, query, queryEqual, refEqual, runTransaction, serverTimestamp, setDoc, setIndexConfiguration, setLogLevel, snapshotEqual, startAfter, startAt, terminate, updateDoc, waitForPendingWrites, where, writeBatch };
|
|
30536
|
+
export { AbstractUserDataWriter, AggregateField, AggregateQuerySnapshot, Bytes, CACHE_SIZE_UNLIMITED, CollectionReference, DocumentReference, DocumentSnapshot, FieldPath, FieldValue, Firestore, FirestoreError, GeoPoint, LoadBundleTask, Query, QueryCompositeFilterConstraint, QueryConstraint, QueryDocumentSnapshot, QueryEndAtConstraint, QueryFieldFilterConstraint, QueryLimitConstraint, QueryOrderByConstraint, QuerySnapshot, QueryStartAtConstraint, SnapshotMetadata, Timestamp, Transaction, WriteBatch, DatabaseId as _DatabaseId, DocumentKey as _DocumentKey, EmptyAppCheckTokenProvider as _EmptyAppCheckTokenProvider, EmptyAuthCredentialsProvider as _EmptyAuthCredentialsProvider, FieldPath$1 as _FieldPath, cast as _cast, debugAssert as _debugAssert, isBase64Available as _isBase64Available, logWarn as _logWarn, validateIsNotUsedTogether as _validateIsNotUsedTogether, addDoc, aggregateQuerySnapshotEqual, and, arrayRemove, arrayUnion, clearIndexedDbPersistence, collection, collectionGroup, connectFirestoreEmulator, deleteDoc, deleteField, disableNetwork, doc, documentId, enableIndexedDbPersistence, enableMultiTabIndexedDbPersistence, enableNetwork, endAt, endBefore, ensureFirestoreConfigured, executeWrite, getCountFromServer, getDoc, getDocFromCache, getDocFromServer, getDocs, getDocsFromCache, getDocsFromServer, getFirestore, increment, initializeFirestore, limit, limitToLast, loadBundle, namedQuery, onSnapshot, onSnapshotsInSync, or, orderBy, query, queryEqual, refEqual, runTransaction, serverTimestamp, setDoc, setIndexConfiguration, setLogLevel, snapshotEqual, startAfter, startAt, terminate, updateDoc, waitForPendingWrites, where, writeBatch };
|
|
29777
30537
|
//# sourceMappingURL=index.node.mjs.map
|