@firebase/firestore 3.7.3-canary.e9fb4037f → 3.7.3-canary.fde5adf63
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/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/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 +1 -1
- package/dist/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/firestore/test/util/helpers.d.ts +5 -1
- package/dist/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/index.d.ts +138 -62
- package/dist/index.esm2017.js +4271 -3734
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +4959 -4404
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +1609 -874
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/index.node.mjs +1602 -875
- package/dist/index.node.mjs.map +1 -1
- package/dist/index.rn.js +4496 -3959
- package/dist/index.rn.js.map +1 -1
- package/dist/internal.d.ts +320 -65
- 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/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 +1 -1
- package/dist/lite/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/lite/firestore/test/util/helpers.d.ts +5 -1
- package/dist/lite/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/lite/index.browser.esm2017.js +2059 -1779
- package/dist/lite/index.browser.esm2017.js.map +1 -1
- package/dist/lite/index.browser.esm5.js +2218 -1997
- 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 +2165 -1788
- package/dist/lite/index.node.cjs.js.map +1 -1
- package/dist/lite/index.node.mjs +2158 -1789
- package/dist/lite/index.node.mjs.map +1 -1
- package/dist/lite/index.rn.esm2017.js +2203 -1922
- package/dist/lite/index.rn.esm2017.js.map +1 -1
- package/dist/lite/internal.d.ts +320 -65
- 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/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 +1 -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 +5 -1
- package/dist/lite/packages/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/lite/private.d.ts +232 -65
- 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/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 +1 -1
- package/dist/packages/firestore/test/unit/util/logic_utils.test.d.ts +17 -0
- package/dist/packages/firestore/test/util/helpers.d.ts +5 -1
- package/dist/packages/firestore/test/util/test_platform.d.ts +2 -2
- package/dist/private.d.ts +232 -65
- package/package.json +13 -11
package/dist/index.node.cjs.js
CHANGED
|
@@ -33,7 +33,7 @@ var grpc__namespace = /*#__PURE__*/_interopNamespace(grpc);
|
|
|
33
33
|
var protoLoader__namespace = /*#__PURE__*/_interopNamespace(protoLoader);
|
|
34
34
|
|
|
35
35
|
const name = "@firebase/firestore";
|
|
36
|
-
const version$1 = "3.7.3-canary.
|
|
36
|
+
const version$1 = "3.7.3-canary.fde5adf63";
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* @license
|
|
@@ -86,7 +86,7 @@ User.GOOGLE_CREDENTIALS = new User('google-credentials-uid');
|
|
|
86
86
|
User.FIRST_PARTY = new User('first-party-uid');
|
|
87
87
|
User.MOCK_USER = new User('mock-user');
|
|
88
88
|
|
|
89
|
-
const version = "9.14.0-canary.
|
|
89
|
+
const version = "9.14.0-canary.fde5adf63";
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* @license
|
|
@@ -1524,11 +1524,11 @@ class FieldIndex {
|
|
|
1524
1524
|
FieldIndex.UNKNOWN_ID = -1;
|
|
1525
1525
|
/** Returns the ArrayContains/ArrayContainsAny segment for this index. */
|
|
1526
1526
|
function fieldIndexGetArraySegment(fieldIndex) {
|
|
1527
|
-
return fieldIndex.fields.find(s => s.kind === 2 /* CONTAINS */);
|
|
1527
|
+
return fieldIndex.fields.find(s => s.kind === 2 /* IndexKind.CONTAINS */);
|
|
1528
1528
|
}
|
|
1529
1529
|
/** Returns all directional (ascending/descending) segments for this index. */
|
|
1530
1530
|
function fieldIndexGetDirectionalSegments(fieldIndex) {
|
|
1531
|
-
return fieldIndex.fields.filter(s => s.kind !== 2 /* CONTAINS */);
|
|
1531
|
+
return fieldIndex.fields.filter(s => s.kind !== 2 /* IndexKind.CONTAINS */);
|
|
1532
1532
|
}
|
|
1533
1533
|
/**
|
|
1534
1534
|
* Returns the order of the document key component for the given index.
|
|
@@ -1538,7 +1538,7 @@ function fieldIndexGetDirectionalSegments(fieldIndex) {
|
|
|
1538
1538
|
function fieldIndexGetKeyOrder(fieldIndex) {
|
|
1539
1539
|
const directionalSegments = fieldIndexGetDirectionalSegments(fieldIndex);
|
|
1540
1540
|
return directionalSegments.length === 0
|
|
1541
|
-
? 0 /* ASCENDING */
|
|
1541
|
+
? 0 /* IndexKind.ASCENDING */
|
|
1542
1542
|
: directionalSegments[directionalSegments.length - 1].kind;
|
|
1543
1543
|
}
|
|
1544
1544
|
/**
|
|
@@ -2652,7 +2652,7 @@ class IndexBackfillerScheduler {
|
|
|
2652
2652
|
}
|
|
2653
2653
|
schedule(delay) {
|
|
2654
2654
|
logDebug(LOG_TAG$h, `Scheduled in ${delay}ms`);
|
|
2655
|
-
this.task = this.asyncQueue.enqueueAfterDelay("index_backfill" /* IndexBackfill */, delay, async () => {
|
|
2655
|
+
this.task = this.asyncQueue.enqueueAfterDelay("index_backfill" /* TimerId.IndexBackfill */, delay, async () => {
|
|
2656
2656
|
this.task = null;
|
|
2657
2657
|
try {
|
|
2658
2658
|
const documentsProcessed = await this.backfiller.backfill();
|
|
@@ -4448,40 +4448,40 @@ const MIN_VALUE = {
|
|
|
4448
4448
|
/** Extracts the backend's type order for the provided value. */
|
|
4449
4449
|
function typeOrder(value) {
|
|
4450
4450
|
if ('nullValue' in value) {
|
|
4451
|
-
return 0 /* NullValue */;
|
|
4451
|
+
return 0 /* TypeOrder.NullValue */;
|
|
4452
4452
|
}
|
|
4453
4453
|
else if ('booleanValue' in value) {
|
|
4454
|
-
return 1 /* BooleanValue */;
|
|
4454
|
+
return 1 /* TypeOrder.BooleanValue */;
|
|
4455
4455
|
}
|
|
4456
4456
|
else if ('integerValue' in value || 'doubleValue' in value) {
|
|
4457
|
-
return 2 /* NumberValue */;
|
|
4457
|
+
return 2 /* TypeOrder.NumberValue */;
|
|
4458
4458
|
}
|
|
4459
4459
|
else if ('timestampValue' in value) {
|
|
4460
|
-
return 3 /* TimestampValue */;
|
|
4460
|
+
return 3 /* TypeOrder.TimestampValue */;
|
|
4461
4461
|
}
|
|
4462
4462
|
else if ('stringValue' in value) {
|
|
4463
|
-
return 5 /* StringValue */;
|
|
4463
|
+
return 5 /* TypeOrder.StringValue */;
|
|
4464
4464
|
}
|
|
4465
4465
|
else if ('bytesValue' in value) {
|
|
4466
|
-
return 6 /* BlobValue */;
|
|
4466
|
+
return 6 /* TypeOrder.BlobValue */;
|
|
4467
4467
|
}
|
|
4468
4468
|
else if ('referenceValue' in value) {
|
|
4469
|
-
return 7 /* RefValue */;
|
|
4469
|
+
return 7 /* TypeOrder.RefValue */;
|
|
4470
4470
|
}
|
|
4471
4471
|
else if ('geoPointValue' in value) {
|
|
4472
|
-
return 8 /* GeoPointValue */;
|
|
4472
|
+
return 8 /* TypeOrder.GeoPointValue */;
|
|
4473
4473
|
}
|
|
4474
4474
|
else if ('arrayValue' in value) {
|
|
4475
|
-
return 9 /* ArrayValue */;
|
|
4475
|
+
return 9 /* TypeOrder.ArrayValue */;
|
|
4476
4476
|
}
|
|
4477
4477
|
else if ('mapValue' in value) {
|
|
4478
4478
|
if (isServerTimestamp(value)) {
|
|
4479
|
-
return 4 /* ServerTimestampValue */;
|
|
4479
|
+
return 4 /* TypeOrder.ServerTimestampValue */;
|
|
4480
4480
|
}
|
|
4481
4481
|
else if (isMaxValue(value)) {
|
|
4482
|
-
return 9007199254740991 /* MaxValue */;
|
|
4482
|
+
return 9007199254740991 /* TypeOrder.MaxValue */;
|
|
4483
4483
|
}
|
|
4484
|
-
return 10 /* ObjectValue */;
|
|
4484
|
+
return 10 /* TypeOrder.ObjectValue */;
|
|
4485
4485
|
}
|
|
4486
4486
|
else {
|
|
4487
4487
|
return fail();
|
|
@@ -4498,29 +4498,29 @@ function valueEquals(left, right) {
|
|
|
4498
4498
|
return false;
|
|
4499
4499
|
}
|
|
4500
4500
|
switch (leftType) {
|
|
4501
|
-
case 0 /* NullValue */:
|
|
4501
|
+
case 0 /* TypeOrder.NullValue */:
|
|
4502
4502
|
return true;
|
|
4503
|
-
case 1 /* BooleanValue */:
|
|
4503
|
+
case 1 /* TypeOrder.BooleanValue */:
|
|
4504
4504
|
return left.booleanValue === right.booleanValue;
|
|
4505
|
-
case 4 /* ServerTimestampValue */:
|
|
4505
|
+
case 4 /* TypeOrder.ServerTimestampValue */:
|
|
4506
4506
|
return getLocalWriteTime(left).isEqual(getLocalWriteTime(right));
|
|
4507
|
-
case 3 /* TimestampValue */:
|
|
4507
|
+
case 3 /* TypeOrder.TimestampValue */:
|
|
4508
4508
|
return timestampEquals(left, right);
|
|
4509
|
-
case 5 /* StringValue */:
|
|
4509
|
+
case 5 /* TypeOrder.StringValue */:
|
|
4510
4510
|
return left.stringValue === right.stringValue;
|
|
4511
|
-
case 6 /* BlobValue */:
|
|
4511
|
+
case 6 /* TypeOrder.BlobValue */:
|
|
4512
4512
|
return blobEquals(left, right);
|
|
4513
|
-
case 7 /* RefValue */:
|
|
4513
|
+
case 7 /* TypeOrder.RefValue */:
|
|
4514
4514
|
return left.referenceValue === right.referenceValue;
|
|
4515
|
-
case 8 /* GeoPointValue */:
|
|
4515
|
+
case 8 /* TypeOrder.GeoPointValue */:
|
|
4516
4516
|
return geoPointEquals(left, right);
|
|
4517
|
-
case 2 /* NumberValue */:
|
|
4517
|
+
case 2 /* TypeOrder.NumberValue */:
|
|
4518
4518
|
return numberEquals(left, right);
|
|
4519
|
-
case 9 /* ArrayValue */:
|
|
4519
|
+
case 9 /* TypeOrder.ArrayValue */:
|
|
4520
4520
|
return arrayEquals(left.arrayValue.values || [], right.arrayValue.values || [], valueEquals);
|
|
4521
|
-
case 10 /* ObjectValue */:
|
|
4521
|
+
case 10 /* TypeOrder.ObjectValue */:
|
|
4522
4522
|
return objectEquals(left, right);
|
|
4523
|
-
case 9007199254740991 /* MaxValue */:
|
|
4523
|
+
case 9007199254740991 /* TypeOrder.MaxValue */:
|
|
4524
4524
|
return true;
|
|
4525
4525
|
default:
|
|
4526
4526
|
return fail();
|
|
@@ -4593,28 +4593,28 @@ function valueCompare(left, right) {
|
|
|
4593
4593
|
return primitiveComparator(leftType, rightType);
|
|
4594
4594
|
}
|
|
4595
4595
|
switch (leftType) {
|
|
4596
|
-
case 0 /* NullValue */:
|
|
4597
|
-
case 9007199254740991 /* MaxValue */:
|
|
4596
|
+
case 0 /* TypeOrder.NullValue */:
|
|
4597
|
+
case 9007199254740991 /* TypeOrder.MaxValue */:
|
|
4598
4598
|
return 0;
|
|
4599
|
-
case 1 /* BooleanValue */:
|
|
4599
|
+
case 1 /* TypeOrder.BooleanValue */:
|
|
4600
4600
|
return primitiveComparator(left.booleanValue, right.booleanValue);
|
|
4601
|
-
case 2 /* NumberValue */:
|
|
4601
|
+
case 2 /* TypeOrder.NumberValue */:
|
|
4602
4602
|
return compareNumbers(left, right);
|
|
4603
|
-
case 3 /* TimestampValue */:
|
|
4603
|
+
case 3 /* TypeOrder.TimestampValue */:
|
|
4604
4604
|
return compareTimestamps(left.timestampValue, right.timestampValue);
|
|
4605
|
-
case 4 /* ServerTimestampValue */:
|
|
4605
|
+
case 4 /* TypeOrder.ServerTimestampValue */:
|
|
4606
4606
|
return compareTimestamps(getLocalWriteTime(left), getLocalWriteTime(right));
|
|
4607
|
-
case 5 /* StringValue */:
|
|
4607
|
+
case 5 /* TypeOrder.StringValue */:
|
|
4608
4608
|
return primitiveComparator(left.stringValue, right.stringValue);
|
|
4609
|
-
case 6 /* BlobValue */:
|
|
4609
|
+
case 6 /* TypeOrder.BlobValue */:
|
|
4610
4610
|
return compareBlobs(left.bytesValue, right.bytesValue);
|
|
4611
|
-
case 7 /* RefValue */:
|
|
4611
|
+
case 7 /* TypeOrder.RefValue */:
|
|
4612
4612
|
return compareReferences(left.referenceValue, right.referenceValue);
|
|
4613
|
-
case 8 /* GeoPointValue */:
|
|
4613
|
+
case 8 /* TypeOrder.GeoPointValue */:
|
|
4614
4614
|
return compareGeoPoints(left.geoPointValue, right.geoPointValue);
|
|
4615
|
-
case 9 /* ArrayValue */:
|
|
4615
|
+
case 9 /* TypeOrder.ArrayValue */:
|
|
4616
4616
|
return compareArrays(left.arrayValue, right.arrayValue);
|
|
4617
|
-
case 10 /* ObjectValue */:
|
|
4617
|
+
case 10 /* TypeOrder.ObjectValue */:
|
|
4618
4618
|
return compareMaps(left.mapValue, right.mapValue);
|
|
4619
4619
|
default:
|
|
4620
4620
|
throw fail();
|
|
@@ -5180,18 +5180,18 @@ class MutableDocument {
|
|
|
5180
5180
|
* base document for mutations.
|
|
5181
5181
|
*/
|
|
5182
5182
|
static newInvalidDocument(documentKey) {
|
|
5183
|
-
return new MutableDocument(documentKey, 0 /* INVALID */, SnapshotVersion.min(), SnapshotVersion.min(), ObjectValue.empty(), 0 /* SYNCED */);
|
|
5183
|
+
return new MutableDocument(documentKey, 0 /* DocumentType.INVALID */, SnapshotVersion.min(), SnapshotVersion.min(), ObjectValue.empty(), 0 /* DocumentState.SYNCED */);
|
|
5184
5184
|
}
|
|
5185
5185
|
/**
|
|
5186
5186
|
* Creates a new document that is known to exist with the given data at the
|
|
5187
5187
|
* given version.
|
|
5188
5188
|
*/
|
|
5189
5189
|
static newFoundDocument(documentKey, version, value) {
|
|
5190
|
-
return new MutableDocument(documentKey, 1 /* FOUND_DOCUMENT */, version, SnapshotVersion.min(), value, 0 /* SYNCED */);
|
|
5190
|
+
return new MutableDocument(documentKey, 1 /* DocumentType.FOUND_DOCUMENT */, version, SnapshotVersion.min(), value, 0 /* DocumentState.SYNCED */);
|
|
5191
5191
|
}
|
|
5192
5192
|
/** Creates a new document that is known to not exist at the given version. */
|
|
5193
5193
|
static newNoDocument(documentKey, version) {
|
|
5194
|
-
return new MutableDocument(documentKey, 2 /* NO_DOCUMENT */, version, SnapshotVersion.min(), ObjectValue.empty(), 0 /* SYNCED */);
|
|
5194
|
+
return new MutableDocument(documentKey, 2 /* DocumentType.NO_DOCUMENT */, version, SnapshotVersion.min(), ObjectValue.empty(), 0 /* DocumentState.SYNCED */);
|
|
5195
5195
|
}
|
|
5196
5196
|
/**
|
|
5197
5197
|
* Creates a new document that is known to exist at the given version but
|
|
@@ -5199,7 +5199,7 @@ class MutableDocument {
|
|
|
5199
5199
|
* base document).
|
|
5200
5200
|
*/
|
|
5201
5201
|
static newUnknownDocument(documentKey, version) {
|
|
5202
|
-
return new MutableDocument(documentKey, 3 /* UNKNOWN_DOCUMENT */, version, SnapshotVersion.min(), ObjectValue.empty(), 2 /* HAS_COMMITTED_MUTATIONS */);
|
|
5202
|
+
return new MutableDocument(documentKey, 3 /* DocumentType.UNKNOWN_DOCUMENT */, version, SnapshotVersion.min(), ObjectValue.empty(), 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */);
|
|
5203
5203
|
}
|
|
5204
5204
|
/**
|
|
5205
5205
|
* Changes the document type to indicate that it exists and that its version
|
|
@@ -5207,9 +5207,9 @@ class MutableDocument {
|
|
|
5207
5207
|
*/
|
|
5208
5208
|
convertToFoundDocument(version, value) {
|
|
5209
5209
|
this.version = version;
|
|
5210
|
-
this.documentType = 1 /* FOUND_DOCUMENT */;
|
|
5210
|
+
this.documentType = 1 /* DocumentType.FOUND_DOCUMENT */;
|
|
5211
5211
|
this.data = value;
|
|
5212
|
-
this.documentState = 0 /* SYNCED */;
|
|
5212
|
+
this.documentState = 0 /* DocumentState.SYNCED */;
|
|
5213
5213
|
return this;
|
|
5214
5214
|
}
|
|
5215
5215
|
/**
|
|
@@ -5218,9 +5218,9 @@ class MutableDocument {
|
|
|
5218
5218
|
*/
|
|
5219
5219
|
convertToNoDocument(version) {
|
|
5220
5220
|
this.version = version;
|
|
5221
|
-
this.documentType = 2 /* NO_DOCUMENT */;
|
|
5221
|
+
this.documentType = 2 /* DocumentType.NO_DOCUMENT */;
|
|
5222
5222
|
this.data = ObjectValue.empty();
|
|
5223
|
-
this.documentState = 0 /* SYNCED */;
|
|
5223
|
+
this.documentState = 0 /* DocumentState.SYNCED */;
|
|
5224
5224
|
return this;
|
|
5225
5225
|
}
|
|
5226
5226
|
/**
|
|
@@ -5230,17 +5230,17 @@ class MutableDocument {
|
|
|
5230
5230
|
*/
|
|
5231
5231
|
convertToUnknownDocument(version) {
|
|
5232
5232
|
this.version = version;
|
|
5233
|
-
this.documentType = 3 /* UNKNOWN_DOCUMENT */;
|
|
5233
|
+
this.documentType = 3 /* DocumentType.UNKNOWN_DOCUMENT */;
|
|
5234
5234
|
this.data = ObjectValue.empty();
|
|
5235
|
-
this.documentState = 2 /* HAS_COMMITTED_MUTATIONS */;
|
|
5235
|
+
this.documentState = 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */;
|
|
5236
5236
|
return this;
|
|
5237
5237
|
}
|
|
5238
5238
|
setHasCommittedMutations() {
|
|
5239
|
-
this.documentState = 2 /* HAS_COMMITTED_MUTATIONS */;
|
|
5239
|
+
this.documentState = 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */;
|
|
5240
5240
|
return this;
|
|
5241
5241
|
}
|
|
5242
5242
|
setHasLocalMutations() {
|
|
5243
|
-
this.documentState = 1 /* HAS_LOCAL_MUTATIONS */;
|
|
5243
|
+
this.documentState = 1 /* DocumentState.HAS_LOCAL_MUTATIONS */;
|
|
5244
5244
|
this.version = SnapshotVersion.min();
|
|
5245
5245
|
return this;
|
|
5246
5246
|
}
|
|
@@ -5249,25 +5249,25 @@ class MutableDocument {
|
|
|
5249
5249
|
return this;
|
|
5250
5250
|
}
|
|
5251
5251
|
get hasLocalMutations() {
|
|
5252
|
-
return this.documentState === 1 /* HAS_LOCAL_MUTATIONS */;
|
|
5252
|
+
return this.documentState === 1 /* DocumentState.HAS_LOCAL_MUTATIONS */;
|
|
5253
5253
|
}
|
|
5254
5254
|
get hasCommittedMutations() {
|
|
5255
|
-
return this.documentState === 2 /* HAS_COMMITTED_MUTATIONS */;
|
|
5255
|
+
return this.documentState === 2 /* DocumentState.HAS_COMMITTED_MUTATIONS */;
|
|
5256
5256
|
}
|
|
5257
5257
|
get hasPendingWrites() {
|
|
5258
5258
|
return this.hasLocalMutations || this.hasCommittedMutations;
|
|
5259
5259
|
}
|
|
5260
5260
|
isValidDocument() {
|
|
5261
|
-
return this.documentType !== 0 /* INVALID */;
|
|
5261
|
+
return this.documentType !== 0 /* DocumentType.INVALID */;
|
|
5262
5262
|
}
|
|
5263
5263
|
isFoundDocument() {
|
|
5264
|
-
return this.documentType === 1 /* FOUND_DOCUMENT */;
|
|
5264
|
+
return this.documentType === 1 /* DocumentType.FOUND_DOCUMENT */;
|
|
5265
5265
|
}
|
|
5266
5266
|
isNoDocument() {
|
|
5267
|
-
return this.documentType === 2 /* NO_DOCUMENT */;
|
|
5267
|
+
return this.documentType === 2 /* DocumentType.NO_DOCUMENT */;
|
|
5268
5268
|
}
|
|
5269
5269
|
isUnknownDocument() {
|
|
5270
|
-
return this.documentType === 3 /* UNKNOWN_DOCUMENT */;
|
|
5270
|
+
return this.documentType === 3 /* DocumentType.UNKNOWN_DOCUMENT */;
|
|
5271
5271
|
}
|
|
5272
5272
|
isEqual(other) {
|
|
5273
5273
|
return (other instanceof MutableDocument &&
|
|
@@ -5303,7 +5303,7 @@ function compareDocumentsByField(field, d1, d2) {
|
|
|
5303
5303
|
|
|
5304
5304
|
/**
|
|
5305
5305
|
* @license
|
|
5306
|
-
* Copyright
|
|
5306
|
+
* Copyright 2022 Google LLC
|
|
5307
5307
|
*
|
|
5308
5308
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5309
5309
|
* you may not use this file except in compliance with the License.
|
|
@@ -5317,453 +5317,344 @@ function compareDocumentsByField(field, d1, d2) {
|
|
|
5317
5317
|
* See the License for the specific language governing permissions and
|
|
5318
5318
|
* limitations under the License.
|
|
5319
5319
|
*/
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5320
|
+
/**
|
|
5321
|
+
* Represents a bound of a query.
|
|
5322
|
+
*
|
|
5323
|
+
* The bound is specified with the given components representing a position and
|
|
5324
|
+
* whether it's just before or just after the position (relative to whatever the
|
|
5325
|
+
* query order is).
|
|
5326
|
+
*
|
|
5327
|
+
* The position represents a logical index position for a query. It's a prefix
|
|
5328
|
+
* of values for the (potentially implicit) order by clauses of a query.
|
|
5329
|
+
*
|
|
5330
|
+
* Bound provides a function to determine whether a document comes before or
|
|
5331
|
+
* after a bound. This is influenced by whether the position is just before or
|
|
5332
|
+
* just after the provided values.
|
|
5333
|
+
*/
|
|
5334
|
+
class Bound {
|
|
5335
|
+
constructor(position, inclusive) {
|
|
5336
|
+
this.position = position;
|
|
5337
|
+
this.inclusive = inclusive;
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
function boundCompareToDocument(bound, orderBy, doc) {
|
|
5341
|
+
let comparison = 0;
|
|
5342
|
+
for (let i = 0; i < bound.position.length; i++) {
|
|
5343
|
+
const orderByComponent = orderBy[i];
|
|
5344
|
+
const component = bound.position[i];
|
|
5345
|
+
if (orderByComponent.field.isKeyField()) {
|
|
5346
|
+
comparison = DocumentKey.comparator(DocumentKey.fromName(component.referenceValue), doc.key);
|
|
5347
|
+
}
|
|
5348
|
+
else {
|
|
5349
|
+
const docValue = doc.data.field(orderByComponent.field);
|
|
5350
|
+
comparison = valueCompare(component, docValue);
|
|
5351
|
+
}
|
|
5352
|
+
if (orderByComponent.dir === "desc" /* Direction.DESCENDING */) {
|
|
5353
|
+
comparison = comparison * -1;
|
|
5354
|
+
}
|
|
5355
|
+
if (comparison !== 0) {
|
|
5356
|
+
break;
|
|
5357
|
+
}
|
|
5331
5358
|
}
|
|
5359
|
+
return comparison;
|
|
5332
5360
|
}
|
|
5333
5361
|
/**
|
|
5334
|
-
*
|
|
5335
|
-
*
|
|
5362
|
+
* Returns true if a document sorts after a bound using the provided sort
|
|
5363
|
+
* order.
|
|
5364
|
+
*/
|
|
5365
|
+
function boundSortsAfterDocument(bound, orderBy, doc) {
|
|
5366
|
+
const comparison = boundCompareToDocument(bound, orderBy, doc);
|
|
5367
|
+
return bound.inclusive ? comparison >= 0 : comparison > 0;
|
|
5368
|
+
}
|
|
5369
|
+
/**
|
|
5370
|
+
* Returns true if a document sorts before a bound using the provided sort
|
|
5371
|
+
* order.
|
|
5372
|
+
*/
|
|
5373
|
+
function boundSortsBeforeDocument(bound, orderBy, doc) {
|
|
5374
|
+
const comparison = boundCompareToDocument(bound, orderBy, doc);
|
|
5375
|
+
return bound.inclusive ? comparison <= 0 : comparison < 0;
|
|
5376
|
+
}
|
|
5377
|
+
function boundEquals(left, right) {
|
|
5378
|
+
if (left === null) {
|
|
5379
|
+
return right === null;
|
|
5380
|
+
}
|
|
5381
|
+
else if (right === null) {
|
|
5382
|
+
return false;
|
|
5383
|
+
}
|
|
5384
|
+
if (left.inclusive !== right.inclusive ||
|
|
5385
|
+
left.position.length !== right.position.length) {
|
|
5386
|
+
return false;
|
|
5387
|
+
}
|
|
5388
|
+
for (let i = 0; i < left.position.length; i++) {
|
|
5389
|
+
const leftPosition = left.position[i];
|
|
5390
|
+
const rightPosition = right.position[i];
|
|
5391
|
+
if (!valueEquals(leftPosition, rightPosition)) {
|
|
5392
|
+
return false;
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
return true;
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
/**
|
|
5399
|
+
* @license
|
|
5400
|
+
* Copyright 2022 Google LLC
|
|
5336
5401
|
*
|
|
5337
|
-
*
|
|
5338
|
-
*
|
|
5339
|
-
*
|
|
5402
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5403
|
+
* you may not use this file except in compliance with the License.
|
|
5404
|
+
* You may obtain a copy of the License at
|
|
5405
|
+
*
|
|
5406
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5407
|
+
*
|
|
5408
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
5409
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
5410
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5411
|
+
* See the License for the specific language governing permissions and
|
|
5412
|
+
* limitations under the License.
|
|
5340
5413
|
*/
|
|
5341
|
-
|
|
5342
|
-
return new TargetImpl(path, collectionGroup, orderBy, filters, limit, startAt, endAt);
|
|
5414
|
+
class Filter {
|
|
5343
5415
|
}
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5416
|
+
class FieldFilter extends Filter {
|
|
5417
|
+
constructor(field, op, value) {
|
|
5418
|
+
super();
|
|
5419
|
+
this.field = field;
|
|
5420
|
+
this.op = op;
|
|
5421
|
+
this.value = value;
|
|
5422
|
+
}
|
|
5423
|
+
/**
|
|
5424
|
+
* Creates a filter based on the provided arguments.
|
|
5425
|
+
*/
|
|
5426
|
+
static create(field, op, value) {
|
|
5427
|
+
if (field.isKeyField()) {
|
|
5428
|
+
if (op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */) {
|
|
5429
|
+
return this.createKeyFieldInFilter(field, op, value);
|
|
5430
|
+
}
|
|
5431
|
+
else {
|
|
5432
|
+
return new KeyFieldFilter(field, op, value);
|
|
5433
|
+
}
|
|
5350
5434
|
}
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
str += '|ob:';
|
|
5354
|
-
str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
|
|
5355
|
-
if (!isNullOrUndefined(targetImpl.limit)) {
|
|
5356
|
-
str += '|l:';
|
|
5357
|
-
str += targetImpl.limit;
|
|
5435
|
+
else if (op === "array-contains" /* Operator.ARRAY_CONTAINS */) {
|
|
5436
|
+
return new ArrayContainsFilter(field, value);
|
|
5358
5437
|
}
|
|
5359
|
-
if (
|
|
5360
|
-
|
|
5361
|
-
str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
|
|
5362
|
-
str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5438
|
+
else if (op === "in" /* Operator.IN */) {
|
|
5439
|
+
return new InFilter(field, value);
|
|
5363
5440
|
}
|
|
5364
|
-
if (
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5441
|
+
else if (op === "not-in" /* Operator.NOT_IN */) {
|
|
5442
|
+
return new NotInFilter(field, value);
|
|
5443
|
+
}
|
|
5444
|
+
else if (op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
5445
|
+
return new ArrayContainsAnyFilter(field, value);
|
|
5446
|
+
}
|
|
5447
|
+
else {
|
|
5448
|
+
return new FieldFilter(field, op, value);
|
|
5368
5449
|
}
|
|
5369
|
-
targetImpl.memoizedCanonicalId = str;
|
|
5370
5450
|
}
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
if (target.collectionGroup !== null) {
|
|
5376
|
-
str += ' collectionGroup=' + target.collectionGroup;
|
|
5451
|
+
static createKeyFieldInFilter(field, op, value) {
|
|
5452
|
+
return op === "in" /* Operator.IN */
|
|
5453
|
+
? new KeyFieldInFilter(field, value)
|
|
5454
|
+
: new KeyFieldNotInFilter(field, value);
|
|
5377
5455
|
}
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5456
|
+
matches(doc) {
|
|
5457
|
+
const other = doc.data.field(this.field);
|
|
5458
|
+
// Types do not have to match in NOT_EQUAL filters.
|
|
5459
|
+
if (this.op === "!=" /* Operator.NOT_EQUAL */) {
|
|
5460
|
+
return (other !== null &&
|
|
5461
|
+
this.matchesComparison(valueCompare(other, this.value)));
|
|
5462
|
+
}
|
|
5463
|
+
// Only compare types with matching backend order (such as double and int).
|
|
5464
|
+
return (other !== null &&
|
|
5465
|
+
typeOrder(this.value) === typeOrder(other) &&
|
|
5466
|
+
this.matchesComparison(valueCompare(other, this.value)));
|
|
5382
5467
|
}
|
|
5383
|
-
|
|
5384
|
-
|
|
5468
|
+
matchesComparison(comparison) {
|
|
5469
|
+
switch (this.op) {
|
|
5470
|
+
case "<" /* Operator.LESS_THAN */:
|
|
5471
|
+
return comparison < 0;
|
|
5472
|
+
case "<=" /* Operator.LESS_THAN_OR_EQUAL */:
|
|
5473
|
+
return comparison <= 0;
|
|
5474
|
+
case "==" /* Operator.EQUAL */:
|
|
5475
|
+
return comparison === 0;
|
|
5476
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
5477
|
+
return comparison !== 0;
|
|
5478
|
+
case ">" /* Operator.GREATER_THAN */:
|
|
5479
|
+
return comparison > 0;
|
|
5480
|
+
case ">=" /* Operator.GREATER_THAN_OR_EQUAL */:
|
|
5481
|
+
return comparison >= 0;
|
|
5482
|
+
default:
|
|
5483
|
+
return fail();
|
|
5484
|
+
}
|
|
5385
5485
|
}
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
.
|
|
5389
|
-
.
|
|
5486
|
+
isInequality() {
|
|
5487
|
+
return ([
|
|
5488
|
+
"<" /* Operator.LESS_THAN */,
|
|
5489
|
+
"<=" /* Operator.LESS_THAN_OR_EQUAL */,
|
|
5490
|
+
">" /* Operator.GREATER_THAN */,
|
|
5491
|
+
">=" /* Operator.GREATER_THAN_OR_EQUAL */,
|
|
5492
|
+
"!=" /* Operator.NOT_EQUAL */,
|
|
5493
|
+
"not-in" /* Operator.NOT_IN */
|
|
5494
|
+
].indexOf(this.op) >= 0);
|
|
5390
5495
|
}
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
str += target.startAt.inclusive ? 'b:' : 'a:';
|
|
5394
|
-
str += target.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5496
|
+
getFlattenedFilters() {
|
|
5497
|
+
return [this];
|
|
5395
5498
|
}
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5499
|
+
getFilters() {
|
|
5500
|
+
return [this];
|
|
5501
|
+
}
|
|
5502
|
+
getFirstInequalityField() {
|
|
5503
|
+
if (this.isInequality()) {
|
|
5504
|
+
return this.field;
|
|
5505
|
+
}
|
|
5506
|
+
return null;
|
|
5400
5507
|
}
|
|
5401
|
-
return `Target(${str})`;
|
|
5402
5508
|
}
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5509
|
+
class CompositeFilter extends Filter {
|
|
5510
|
+
constructor(filters, op) {
|
|
5511
|
+
super();
|
|
5512
|
+
this.filters = filters;
|
|
5513
|
+
this.op = op;
|
|
5514
|
+
this.memoizedFlattenedFilters = null;
|
|
5406
5515
|
}
|
|
5407
|
-
|
|
5408
|
-
|
|
5516
|
+
/**
|
|
5517
|
+
* Creates a filter based on the provided arguments.
|
|
5518
|
+
*/
|
|
5519
|
+
static create(filters, op) {
|
|
5520
|
+
return new CompositeFilter(filters, op);
|
|
5409
5521
|
}
|
|
5410
|
-
|
|
5411
|
-
if (
|
|
5412
|
-
return false
|
|
5522
|
+
matches(doc) {
|
|
5523
|
+
if (compositeFilterIsConjunction(this)) {
|
|
5524
|
+
// For conjunctions, all filters must match, so return false if any filter doesn't match.
|
|
5525
|
+
return this.filters.find(filter => !filter.matches(doc)) === undefined;
|
|
5526
|
+
}
|
|
5527
|
+
else {
|
|
5528
|
+
// For disjunctions, at least one filter should match.
|
|
5529
|
+
return this.filters.find(filter => filter.matches(doc)) !== undefined;
|
|
5413
5530
|
}
|
|
5414
5531
|
}
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
for (let i = 0; i < left.filters.length; i++) {
|
|
5419
|
-
if (!filterEquals(left.filters[i], right.filters[i])) {
|
|
5420
|
-
return false;
|
|
5532
|
+
getFlattenedFilters() {
|
|
5533
|
+
if (this.memoizedFlattenedFilters !== null) {
|
|
5534
|
+
return this.memoizedFlattenedFilters;
|
|
5421
5535
|
}
|
|
5536
|
+
this.memoizedFlattenedFilters = this.filters.reduce((result, subfilter) => {
|
|
5537
|
+
return result.concat(subfilter.getFlattenedFilters());
|
|
5538
|
+
}, []);
|
|
5539
|
+
return this.memoizedFlattenedFilters;
|
|
5422
5540
|
}
|
|
5423
|
-
|
|
5424
|
-
|
|
5541
|
+
// Returns a mutable copy of `this.filters`
|
|
5542
|
+
getFilters() {
|
|
5543
|
+
return Object.assign([], this.filters);
|
|
5425
5544
|
}
|
|
5426
|
-
|
|
5427
|
-
|
|
5545
|
+
getFirstInequalityField() {
|
|
5546
|
+
const found = this.findFirstMatchingFilter(filter => filter.isInequality());
|
|
5547
|
+
if (found !== null) {
|
|
5548
|
+
return found.field;
|
|
5549
|
+
}
|
|
5550
|
+
return null;
|
|
5428
5551
|
}
|
|
5429
|
-
|
|
5430
|
-
|
|
5552
|
+
// Performs a depth-first search to find and return the first FieldFilter in the composite filter
|
|
5553
|
+
// that satisfies the predicate. Returns `null` if none of the FieldFilters satisfy the
|
|
5554
|
+
// predicate.
|
|
5555
|
+
findFirstMatchingFilter(predicate) {
|
|
5556
|
+
for (const fieldFilter of this.getFlattenedFilters()) {
|
|
5557
|
+
if (predicate(fieldFilter)) {
|
|
5558
|
+
return fieldFilter;
|
|
5559
|
+
}
|
|
5560
|
+
}
|
|
5561
|
+
return null;
|
|
5431
5562
|
}
|
|
5432
|
-
return boundEquals(left.endAt, right.endAt);
|
|
5433
5563
|
}
|
|
5434
|
-
function
|
|
5435
|
-
return
|
|
5436
|
-
target.collectionGroup === null &&
|
|
5437
|
-
target.filters.length === 0);
|
|
5564
|
+
function compositeFilterIsConjunction(compositeFilter) {
|
|
5565
|
+
return compositeFilter.op === "and" /* CompositeOperator.AND */;
|
|
5438
5566
|
}
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
return target.filters.filter(f => f instanceof FieldFilter && f.field.isEqual(path));
|
|
5567
|
+
function compositeFilterIsDisjunction(compositeFilter) {
|
|
5568
|
+
return compositeFilter.op === "or" /* CompositeOperator.OR */;
|
|
5442
5569
|
}
|
|
5443
5570
|
/**
|
|
5444
|
-
* Returns
|
|
5445
|
-
* filters. Returns `null` if there are no such filters.
|
|
5571
|
+
* Returns true if this filter is a conjunction of field filters only. Returns false otherwise.
|
|
5446
5572
|
*/
|
|
5447
|
-
function
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
return null;
|
|
5451
|
-
}
|
|
5452
|
-
for (const fieldFilter of targetGetFieldFiltersForPath(target, segment.fieldPath)) {
|
|
5453
|
-
switch (fieldFilter.op) {
|
|
5454
|
-
case "array-contains-any" /* ARRAY_CONTAINS_ANY */:
|
|
5455
|
-
return fieldFilter.value.arrayValue.values || [];
|
|
5456
|
-
case "array-contains" /* ARRAY_CONTAINS */:
|
|
5457
|
-
return [fieldFilter.value];
|
|
5458
|
-
// Remaining filters are not array filters.
|
|
5459
|
-
}
|
|
5460
|
-
}
|
|
5461
|
-
return null;
|
|
5573
|
+
function compositeFilterIsFlatConjunction(compositeFilter) {
|
|
5574
|
+
return (compositeFilterIsFlat(compositeFilter) &&
|
|
5575
|
+
compositeFilterIsConjunction(compositeFilter));
|
|
5462
5576
|
}
|
|
5463
5577
|
/**
|
|
5464
|
-
* Returns
|
|
5465
|
-
* `null` if there are no such filters.
|
|
5578
|
+
* Returns true if this filter does not contain any composite filters. Returns false otherwise.
|
|
5466
5579
|
*/
|
|
5467
|
-
function
|
|
5468
|
-
const
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
switch (fieldFilter.op) {
|
|
5472
|
-
case "==" /* EQUAL */:
|
|
5473
|
-
case "in" /* IN */:
|
|
5474
|
-
// Encode equality prefix, which is encoded in the index value before
|
|
5475
|
-
// the inequality (e.g. `a == 'a' && b != 'b'` is encoded to
|
|
5476
|
-
// `value != 'ab'`).
|
|
5477
|
-
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5478
|
-
break;
|
|
5479
|
-
case "not-in" /* NOT_IN */:
|
|
5480
|
-
case "!=" /* NOT_EQUAL */:
|
|
5481
|
-
// NotIn/NotEqual is always a suffix. There cannot be any remaining
|
|
5482
|
-
// segments and hence we can return early here.
|
|
5483
|
-
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5484
|
-
return Array.from(values.values());
|
|
5485
|
-
// Remaining filters cannot be used as notIn bounds.
|
|
5486
|
-
}
|
|
5580
|
+
function compositeFilterIsFlat(compositeFilter) {
|
|
5581
|
+
for (const filter of compositeFilter.filters) {
|
|
5582
|
+
if (filter instanceof CompositeFilter) {
|
|
5583
|
+
return false;
|
|
5487
5584
|
}
|
|
5488
5585
|
}
|
|
5489
|
-
return
|
|
5586
|
+
return true;
|
|
5490
5587
|
}
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
// For each segment, retrieve a lower bound if there is a suitable filter or
|
|
5500
|
-
// startAt.
|
|
5501
|
-
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5502
|
-
const segmentBound = segment.kind === 0 /* ASCENDING */
|
|
5503
|
-
? targetGetAscendingBound(target, segment.fieldPath, target.startAt)
|
|
5504
|
-
: targetGetDescendingBound(target, segment.fieldPath, target.startAt);
|
|
5505
|
-
values.push(segmentBound.value);
|
|
5506
|
-
inclusive && (inclusive = segmentBound.inclusive);
|
|
5588
|
+
function canonifyFilter(filter) {
|
|
5589
|
+
if (filter instanceof FieldFilter) {
|
|
5590
|
+
// TODO(b/29183165): Technically, this won't be unique if two values have
|
|
5591
|
+
// the same description, such as the int 3 and the string "3". So we should
|
|
5592
|
+
// add the types in here somehow, too.
|
|
5593
|
+
return (filter.field.canonicalString() +
|
|
5594
|
+
filter.op.toString() +
|
|
5595
|
+
canonicalId(filter.value));
|
|
5507
5596
|
}
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
*/
|
|
5515
|
-
function targetGetUpperBound(target, fieldIndex) {
|
|
5516
|
-
const values = [];
|
|
5517
|
-
let inclusive = true;
|
|
5518
|
-
// For each segment, retrieve an upper bound if there is a suitable filter or
|
|
5519
|
-
// endAt.
|
|
5520
|
-
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5521
|
-
const segmentBound = segment.kind === 0 /* ASCENDING */
|
|
5522
|
-
? targetGetDescendingBound(target, segment.fieldPath, target.endAt)
|
|
5523
|
-
: targetGetAscendingBound(target, segment.fieldPath, target.endAt);
|
|
5524
|
-
values.push(segmentBound.value);
|
|
5525
|
-
inclusive && (inclusive = segmentBound.inclusive);
|
|
5597
|
+
else {
|
|
5598
|
+
// filter instanceof CompositeFilter
|
|
5599
|
+
const canonicalIdsString = filter.filters
|
|
5600
|
+
.map(filter => canonifyFilter(filter))
|
|
5601
|
+
.join(',');
|
|
5602
|
+
return `${filter.op}(${canonicalIdsString})`;
|
|
5526
5603
|
}
|
|
5527
|
-
return new Bound(values, inclusive);
|
|
5528
5604
|
}
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
*/
|
|
5533
|
-
function targetGetAscendingBound(target, fieldPath, bound) {
|
|
5534
|
-
let value = MIN_VALUE;
|
|
5535
|
-
let inclusive = true;
|
|
5536
|
-
// Process all filters to find a value for the current field segment
|
|
5537
|
-
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
5538
|
-
let filterValue = MIN_VALUE;
|
|
5539
|
-
let filterInclusive = true;
|
|
5540
|
-
switch (fieldFilter.op) {
|
|
5541
|
-
case "<" /* LESS_THAN */:
|
|
5542
|
-
case "<=" /* LESS_THAN_OR_EQUAL */:
|
|
5543
|
-
filterValue = valuesGetLowerBound(fieldFilter.value);
|
|
5544
|
-
break;
|
|
5545
|
-
case "==" /* EQUAL */:
|
|
5546
|
-
case "in" /* IN */:
|
|
5547
|
-
case ">=" /* GREATER_THAN_OR_EQUAL */:
|
|
5548
|
-
filterValue = fieldFilter.value;
|
|
5549
|
-
break;
|
|
5550
|
-
case ">" /* GREATER_THAN */:
|
|
5551
|
-
filterValue = fieldFilter.value;
|
|
5552
|
-
filterInclusive = false;
|
|
5553
|
-
break;
|
|
5554
|
-
case "!=" /* NOT_EQUAL */:
|
|
5555
|
-
case "not-in" /* NOT_IN */:
|
|
5556
|
-
filterValue = MIN_VALUE;
|
|
5557
|
-
break;
|
|
5558
|
-
// Remaining filters cannot be used as lower bounds.
|
|
5559
|
-
}
|
|
5560
|
-
if (lowerBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) < 0) {
|
|
5561
|
-
value = filterValue;
|
|
5562
|
-
inclusive = filterInclusive;
|
|
5563
|
-
}
|
|
5564
|
-
}
|
|
5565
|
-
// If there is an additional bound, compare the values against the existing
|
|
5566
|
-
// range to see if we can narrow the scope.
|
|
5567
|
-
if (bound !== null) {
|
|
5568
|
-
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
5569
|
-
const orderBy = target.orderBy[i];
|
|
5570
|
-
if (orderBy.field.isEqual(fieldPath)) {
|
|
5571
|
-
const cursorValue = bound.position[i];
|
|
5572
|
-
if (lowerBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) < 0) {
|
|
5573
|
-
value = cursorValue;
|
|
5574
|
-
inclusive = bound.inclusive;
|
|
5575
|
-
}
|
|
5576
|
-
break;
|
|
5577
|
-
}
|
|
5578
|
-
}
|
|
5605
|
+
function filterEquals(f1, f2) {
|
|
5606
|
+
if (f1 instanceof FieldFilter) {
|
|
5607
|
+
return fieldFilterEquals(f1, f2);
|
|
5579
5608
|
}
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
/**
|
|
5583
|
-
* Returns the value to use as the upper bound for ascending index segment at
|
|
5584
|
-
* the provided `fieldPath` (or the lower bound for a descending segment).
|
|
5585
|
-
*/
|
|
5586
|
-
function targetGetDescendingBound(target, fieldPath, bound) {
|
|
5587
|
-
let value = MAX_VALUE;
|
|
5588
|
-
let inclusive = true;
|
|
5589
|
-
// Process all filters to find a value for the current field segment
|
|
5590
|
-
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
5591
|
-
let filterValue = MAX_VALUE;
|
|
5592
|
-
let filterInclusive = true;
|
|
5593
|
-
switch (fieldFilter.op) {
|
|
5594
|
-
case ">=" /* GREATER_THAN_OR_EQUAL */:
|
|
5595
|
-
case ">" /* GREATER_THAN */:
|
|
5596
|
-
filterValue = valuesGetUpperBound(fieldFilter.value);
|
|
5597
|
-
filterInclusive = false;
|
|
5598
|
-
break;
|
|
5599
|
-
case "==" /* EQUAL */:
|
|
5600
|
-
case "in" /* IN */:
|
|
5601
|
-
case "<=" /* LESS_THAN_OR_EQUAL */:
|
|
5602
|
-
filterValue = fieldFilter.value;
|
|
5603
|
-
break;
|
|
5604
|
-
case "<" /* LESS_THAN */:
|
|
5605
|
-
filterValue = fieldFilter.value;
|
|
5606
|
-
filterInclusive = false;
|
|
5607
|
-
break;
|
|
5608
|
-
case "!=" /* NOT_EQUAL */:
|
|
5609
|
-
case "not-in" /* NOT_IN */:
|
|
5610
|
-
filterValue = MAX_VALUE;
|
|
5611
|
-
break;
|
|
5612
|
-
// Remaining filters cannot be used as upper bounds.
|
|
5613
|
-
}
|
|
5614
|
-
if (upperBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) > 0) {
|
|
5615
|
-
value = filterValue;
|
|
5616
|
-
inclusive = filterInclusive;
|
|
5617
|
-
}
|
|
5609
|
+
else if (f1 instanceof CompositeFilter) {
|
|
5610
|
+
return compositeFilterEquals(f1, f2);
|
|
5618
5611
|
}
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
if (bound !== null) {
|
|
5622
|
-
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
5623
|
-
const orderBy = target.orderBy[i];
|
|
5624
|
-
if (orderBy.field.isEqual(fieldPath)) {
|
|
5625
|
-
const cursorValue = bound.position[i];
|
|
5626
|
-
if (upperBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) > 0) {
|
|
5627
|
-
value = cursorValue;
|
|
5628
|
-
inclusive = bound.inclusive;
|
|
5629
|
-
}
|
|
5630
|
-
break;
|
|
5631
|
-
}
|
|
5632
|
-
}
|
|
5612
|
+
else {
|
|
5613
|
+
fail();
|
|
5633
5614
|
}
|
|
5634
|
-
return { value, inclusive };
|
|
5635
5615
|
}
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
// ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filters must be counted separately.
|
|
5649
|
-
// For instance, it is possible to have an index for "a ARRAY a ASC". Even
|
|
5650
|
-
// though these are on the same field, they should be counted as two
|
|
5651
|
-
// separate segments in an index.
|
|
5652
|
-
if (fieldFilter.op === "array-contains" /* ARRAY_CONTAINS */ ||
|
|
5653
|
-
fieldFilter.op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
5654
|
-
hasArraySegment = true;
|
|
5655
|
-
}
|
|
5656
|
-
else {
|
|
5657
|
-
fields = fields.add(fieldFilter.field);
|
|
5658
|
-
}
|
|
5659
|
-
}
|
|
5660
|
-
for (const orderBy of target.orderBy) {
|
|
5661
|
-
// __name__ is not an explicit segment of any index, so we don't need to
|
|
5662
|
-
// count it.
|
|
5663
|
-
if (!orderBy.field.isKeyField()) {
|
|
5664
|
-
fields = fields.add(orderBy.field);
|
|
5665
|
-
}
|
|
5616
|
+
function fieldFilterEquals(f1, f2) {
|
|
5617
|
+
return (f2 instanceof FieldFilter &&
|
|
5618
|
+
f1.op === f2.op &&
|
|
5619
|
+
f1.field.isEqual(f2.field) &&
|
|
5620
|
+
valueEquals(f1.value, f2.value));
|
|
5621
|
+
}
|
|
5622
|
+
function compositeFilterEquals(f1, f2) {
|
|
5623
|
+
if (f2 instanceof CompositeFilter &&
|
|
5624
|
+
f1.op === f2.op &&
|
|
5625
|
+
f1.filters.length === f2.filters.length) {
|
|
5626
|
+
const subFiltersMatch = f1.filters.reduce((result, f1Filter, index) => result && filterEquals(f1Filter, f2.filters[index]), true);
|
|
5627
|
+
return subFiltersMatch;
|
|
5666
5628
|
}
|
|
5667
|
-
return
|
|
5629
|
+
return false;
|
|
5668
5630
|
}
|
|
5669
|
-
|
|
5631
|
+
/**
|
|
5632
|
+
* Returns a new composite filter that contains all filter from
|
|
5633
|
+
* `compositeFilter` plus all the given filters in `otherFilters`.
|
|
5634
|
+
*/
|
|
5635
|
+
function compositeFilterWithAddedFilters(compositeFilter, otherFilters) {
|
|
5636
|
+
const mergedFilters = compositeFilter.filters.concat(otherFilters);
|
|
5637
|
+
return CompositeFilter.create(mergedFilters, compositeFilter.op);
|
|
5670
5638
|
}
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
this.op = op;
|
|
5676
|
-
this.value = value;
|
|
5677
|
-
}
|
|
5678
|
-
/**
|
|
5679
|
-
* Creates a filter based on the provided arguments.
|
|
5680
|
-
*/
|
|
5681
|
-
static create(field, op, value) {
|
|
5682
|
-
if (field.isKeyField()) {
|
|
5683
|
-
if (op === "in" /* IN */ || op === "not-in" /* NOT_IN */) {
|
|
5684
|
-
return this.createKeyFieldInFilter(field, op, value);
|
|
5685
|
-
}
|
|
5686
|
-
else {
|
|
5687
|
-
return new KeyFieldFilter(field, op, value);
|
|
5688
|
-
}
|
|
5689
|
-
}
|
|
5690
|
-
else if (op === "array-contains" /* ARRAY_CONTAINS */) {
|
|
5691
|
-
return new ArrayContainsFilter(field, value);
|
|
5692
|
-
}
|
|
5693
|
-
else if (op === "in" /* IN */) {
|
|
5694
|
-
return new InFilter(field, value);
|
|
5695
|
-
}
|
|
5696
|
-
else if (op === "not-in" /* NOT_IN */) {
|
|
5697
|
-
return new NotInFilter(field, value);
|
|
5698
|
-
}
|
|
5699
|
-
else if (op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
5700
|
-
return new ArrayContainsAnyFilter(field, value);
|
|
5701
|
-
}
|
|
5702
|
-
else {
|
|
5703
|
-
return new FieldFilter(field, op, value);
|
|
5704
|
-
}
|
|
5705
|
-
}
|
|
5706
|
-
static createKeyFieldInFilter(field, op, value) {
|
|
5707
|
-
return op === "in" /* IN */
|
|
5708
|
-
? new KeyFieldInFilter(field, value)
|
|
5709
|
-
: new KeyFieldNotInFilter(field, value);
|
|
5710
|
-
}
|
|
5711
|
-
matches(doc) {
|
|
5712
|
-
const other = doc.data.field(this.field);
|
|
5713
|
-
// Types do not have to match in NOT_EQUAL filters.
|
|
5714
|
-
if (this.op === "!=" /* NOT_EQUAL */) {
|
|
5715
|
-
return (other !== null &&
|
|
5716
|
-
this.matchesComparison(valueCompare(other, this.value)));
|
|
5717
|
-
}
|
|
5718
|
-
// Only compare types with matching backend order (such as double and int).
|
|
5719
|
-
return (other !== null &&
|
|
5720
|
-
typeOrder(this.value) === typeOrder(other) &&
|
|
5721
|
-
this.matchesComparison(valueCompare(other, this.value)));
|
|
5639
|
+
/** Returns a debug description for `filter`. */
|
|
5640
|
+
function stringifyFilter(filter) {
|
|
5641
|
+
if (filter instanceof FieldFilter) {
|
|
5642
|
+
return stringifyFieldFilter(filter);
|
|
5722
5643
|
}
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
case "<" /* LESS_THAN */:
|
|
5726
|
-
return comparison < 0;
|
|
5727
|
-
case "<=" /* LESS_THAN_OR_EQUAL */:
|
|
5728
|
-
return comparison <= 0;
|
|
5729
|
-
case "==" /* EQUAL */:
|
|
5730
|
-
return comparison === 0;
|
|
5731
|
-
case "!=" /* NOT_EQUAL */:
|
|
5732
|
-
return comparison !== 0;
|
|
5733
|
-
case ">" /* GREATER_THAN */:
|
|
5734
|
-
return comparison > 0;
|
|
5735
|
-
case ">=" /* GREATER_THAN_OR_EQUAL */:
|
|
5736
|
-
return comparison >= 0;
|
|
5737
|
-
default:
|
|
5738
|
-
return fail();
|
|
5739
|
-
}
|
|
5644
|
+
else if (filter instanceof CompositeFilter) {
|
|
5645
|
+
return stringifyCompositeFilter(filter);
|
|
5740
5646
|
}
|
|
5741
|
-
|
|
5742
|
-
return
|
|
5743
|
-
"<" /* LESS_THAN */,
|
|
5744
|
-
"<=" /* LESS_THAN_OR_EQUAL */,
|
|
5745
|
-
">" /* GREATER_THAN */,
|
|
5746
|
-
">=" /* GREATER_THAN_OR_EQUAL */,
|
|
5747
|
-
"!=" /* NOT_EQUAL */,
|
|
5748
|
-
"not-in" /* NOT_IN */
|
|
5749
|
-
].indexOf(this.op) >= 0);
|
|
5647
|
+
else {
|
|
5648
|
+
return 'Filter';
|
|
5750
5649
|
}
|
|
5751
5650
|
}
|
|
5752
|
-
function
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
filter.op.toString() +
|
|
5758
|
-
canonicalId(filter.value));
|
|
5759
|
-
}
|
|
5760
|
-
function filterEquals(f1, f2) {
|
|
5761
|
-
return (f1.op === f2.op &&
|
|
5762
|
-
f1.field.isEqual(f2.field) &&
|
|
5763
|
-
valueEquals(f1.value, f2.value));
|
|
5651
|
+
function stringifyCompositeFilter(filter) {
|
|
5652
|
+
return (filter.op.toString() +
|
|
5653
|
+
` {` +
|
|
5654
|
+
filter.getFilters().map(stringifyFilter).join(' ,') +
|
|
5655
|
+
'}');
|
|
5764
5656
|
}
|
|
5765
|
-
|
|
5766
|
-
function stringifyFilter(filter) {
|
|
5657
|
+
function stringifyFieldFilter(filter) {
|
|
5767
5658
|
return `${filter.field.canonicalString()} ${filter.op} ${canonicalId(filter.value)}`;
|
|
5768
5659
|
}
|
|
5769
5660
|
/** Filter that matches on key fields (i.e. '__name__'). */
|
|
@@ -5780,8 +5671,8 @@ class KeyFieldFilter extends FieldFilter {
|
|
|
5780
5671
|
/** Filter that matches on key fields within an array. */
|
|
5781
5672
|
class KeyFieldInFilter extends FieldFilter {
|
|
5782
5673
|
constructor(field, value) {
|
|
5783
|
-
super(field, "in" /* IN */, value);
|
|
5784
|
-
this.keys = extractDocumentKeysFromArrayValue("in" /* IN */, value);
|
|
5674
|
+
super(field, "in" /* Operator.IN */, value);
|
|
5675
|
+
this.keys = extractDocumentKeysFromArrayValue("in" /* Operator.IN */, value);
|
|
5785
5676
|
}
|
|
5786
5677
|
matches(doc) {
|
|
5787
5678
|
return this.keys.some(key => key.isEqual(doc.key));
|
|
@@ -5790,8 +5681,8 @@ class KeyFieldInFilter extends FieldFilter {
|
|
|
5790
5681
|
/** Filter that matches on key fields not present within an array. */
|
|
5791
5682
|
class KeyFieldNotInFilter extends FieldFilter {
|
|
5792
5683
|
constructor(field, value) {
|
|
5793
|
-
super(field, "not-in" /* NOT_IN */, value);
|
|
5794
|
-
this.keys = extractDocumentKeysFromArrayValue("not-in" /* NOT_IN */, value);
|
|
5684
|
+
super(field, "not-in" /* Operator.NOT_IN */, value);
|
|
5685
|
+
this.keys = extractDocumentKeysFromArrayValue("not-in" /* Operator.NOT_IN */, value);
|
|
5795
5686
|
}
|
|
5796
5687
|
matches(doc) {
|
|
5797
5688
|
return !this.keys.some(key => key.isEqual(doc.key));
|
|
@@ -5806,7 +5697,7 @@ function extractDocumentKeysFromArrayValue(op, value) {
|
|
|
5806
5697
|
/** A Filter that implements the array-contains operator. */
|
|
5807
5698
|
class ArrayContainsFilter extends FieldFilter {
|
|
5808
5699
|
constructor(field, value) {
|
|
5809
|
-
super(field, "array-contains" /* ARRAY_CONTAINS */, value);
|
|
5700
|
+
super(field, "array-contains" /* Operator.ARRAY_CONTAINS */, value);
|
|
5810
5701
|
}
|
|
5811
5702
|
matches(doc) {
|
|
5812
5703
|
const other = doc.data.field(this.field);
|
|
@@ -5816,7 +5707,7 @@ class ArrayContainsFilter extends FieldFilter {
|
|
|
5816
5707
|
/** A Filter that implements the IN operator. */
|
|
5817
5708
|
class InFilter extends FieldFilter {
|
|
5818
5709
|
constructor(field, value) {
|
|
5819
|
-
super(field, "in" /* IN */, value);
|
|
5710
|
+
super(field, "in" /* Operator.IN */, value);
|
|
5820
5711
|
}
|
|
5821
5712
|
matches(doc) {
|
|
5822
5713
|
const other = doc.data.field(this.field);
|
|
@@ -5826,7 +5717,7 @@ class InFilter extends FieldFilter {
|
|
|
5826
5717
|
/** A Filter that implements the not-in operator. */
|
|
5827
5718
|
class NotInFilter extends FieldFilter {
|
|
5828
5719
|
constructor(field, value) {
|
|
5829
|
-
super(field, "not-in" /* NOT_IN */, value);
|
|
5720
|
+
super(field, "not-in" /* Operator.NOT_IN */, value);
|
|
5830
5721
|
}
|
|
5831
5722
|
matches(doc) {
|
|
5832
5723
|
if (arrayValueContains(this.value.arrayValue, { nullValue: 'NULL_VALUE' })) {
|
|
@@ -5839,7 +5730,7 @@ class NotInFilter extends FieldFilter {
|
|
|
5839
5730
|
/** A Filter that implements the array-contains-any operator. */
|
|
5840
5731
|
class ArrayContainsAnyFilter extends FieldFilter {
|
|
5841
5732
|
constructor(field, value) {
|
|
5842
|
-
super(field, "array-contains-any" /* ARRAY_CONTAINS_ANY */, value);
|
|
5733
|
+
super(field, "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */, value);
|
|
5843
5734
|
}
|
|
5844
5735
|
matches(doc) {
|
|
5845
5736
|
const other = doc.data.field(this.field);
|
|
@@ -5848,32 +5739,29 @@ class ArrayContainsAnyFilter extends FieldFilter {
|
|
|
5848
5739
|
}
|
|
5849
5740
|
return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
|
|
5850
5741
|
}
|
|
5851
|
-
}
|
|
5742
|
+
}
|
|
5743
|
+
|
|
5852
5744
|
/**
|
|
5853
|
-
*
|
|
5745
|
+
* @license
|
|
5746
|
+
* Copyright 2022 Google LLC
|
|
5854
5747
|
*
|
|
5855
|
-
*
|
|
5856
|
-
*
|
|
5857
|
-
*
|
|
5748
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5749
|
+
* you may not use this file except in compliance with the License.
|
|
5750
|
+
* You may obtain a copy of the License at
|
|
5858
5751
|
*
|
|
5859
|
-
*
|
|
5860
|
-
* of values for the (potentially implicit) order by clauses of a query.
|
|
5752
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5861
5753
|
*
|
|
5862
|
-
*
|
|
5863
|
-
*
|
|
5864
|
-
*
|
|
5754
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
5755
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
5756
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5757
|
+
* See the License for the specific language governing permissions and
|
|
5758
|
+
* limitations under the License.
|
|
5865
5759
|
*/
|
|
5866
|
-
class Bound {
|
|
5867
|
-
constructor(position, inclusive) {
|
|
5868
|
-
this.position = position;
|
|
5869
|
-
this.inclusive = inclusive;
|
|
5870
|
-
}
|
|
5871
|
-
}
|
|
5872
5760
|
/**
|
|
5873
5761
|
* An ordering on a field, in some Direction. Direction defaults to ASCENDING.
|
|
5874
5762
|
*/
|
|
5875
5763
|
class OrderBy {
|
|
5876
|
-
constructor(field, dir = "asc" /* ASCENDING */) {
|
|
5764
|
+
constructor(field, dir = "asc" /* Direction.ASCENDING */) {
|
|
5877
5765
|
this.field = field;
|
|
5878
5766
|
this.dir = dir;
|
|
5879
5767
|
}
|
|
@@ -5887,63 +5775,375 @@ function stringifyOrderBy(orderBy) {
|
|
|
5887
5775
|
}
|
|
5888
5776
|
function orderByEquals(left, right) {
|
|
5889
5777
|
return left.dir === right.dir && left.field.isEqual(right.field);
|
|
5778
|
+
}
|
|
5779
|
+
|
|
5780
|
+
/**
|
|
5781
|
+
* @license
|
|
5782
|
+
* Copyright 2019 Google LLC
|
|
5783
|
+
*
|
|
5784
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5785
|
+
* you may not use this file except in compliance with the License.
|
|
5786
|
+
* You may obtain a copy of the License at
|
|
5787
|
+
*
|
|
5788
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5789
|
+
*
|
|
5790
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
5791
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
5792
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5793
|
+
* See the License for the specific language governing permissions and
|
|
5794
|
+
* limitations under the License.
|
|
5795
|
+
*/
|
|
5796
|
+
// Visible for testing
|
|
5797
|
+
class TargetImpl {
|
|
5798
|
+
constructor(path, collectionGroup = null, orderBy = [], filters = [], limit = null, startAt = null, endAt = null) {
|
|
5799
|
+
this.path = path;
|
|
5800
|
+
this.collectionGroup = collectionGroup;
|
|
5801
|
+
this.orderBy = orderBy;
|
|
5802
|
+
this.filters = filters;
|
|
5803
|
+
this.limit = limit;
|
|
5804
|
+
this.startAt = startAt;
|
|
5805
|
+
this.endAt = endAt;
|
|
5806
|
+
this.memoizedCanonicalId = null;
|
|
5807
|
+
}
|
|
5890
5808
|
}
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5809
|
+
/**
|
|
5810
|
+
* Initializes a Target with a path and optional additional query constraints.
|
|
5811
|
+
* Path must currently be empty if this is a collection group query.
|
|
5812
|
+
*
|
|
5813
|
+
* NOTE: you should always construct `Target` from `Query.toTarget` instead of
|
|
5814
|
+
* using this factory method, because `Query` provides an implicit `orderBy`
|
|
5815
|
+
* property.
|
|
5816
|
+
*/
|
|
5817
|
+
function newTarget(path, collectionGroup = null, orderBy = [], filters = [], limit = null, startAt = null, endAt = null) {
|
|
5818
|
+
return new TargetImpl(path, collectionGroup, orderBy, filters, limit, startAt, endAt);
|
|
5819
|
+
}
|
|
5820
|
+
function canonifyTarget(target) {
|
|
5821
|
+
const targetImpl = debugCast(target);
|
|
5822
|
+
if (targetImpl.memoizedCanonicalId === null) {
|
|
5823
|
+
let str = targetImpl.path.canonicalString();
|
|
5824
|
+
if (targetImpl.collectionGroup !== null) {
|
|
5825
|
+
str += '|cg:' + targetImpl.collectionGroup;
|
|
5898
5826
|
}
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5827
|
+
str += '|f:';
|
|
5828
|
+
str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
|
|
5829
|
+
str += '|ob:';
|
|
5830
|
+
str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
|
|
5831
|
+
if (!isNullOrUndefined(targetImpl.limit)) {
|
|
5832
|
+
str += '|l:';
|
|
5833
|
+
str += targetImpl.limit;
|
|
5902
5834
|
}
|
|
5903
|
-
if (
|
|
5904
|
-
|
|
5835
|
+
if (targetImpl.startAt) {
|
|
5836
|
+
str += '|lb:';
|
|
5837
|
+
str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
|
|
5838
|
+
str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5905
5839
|
}
|
|
5906
|
-
if (
|
|
5907
|
-
|
|
5840
|
+
if (targetImpl.endAt) {
|
|
5841
|
+
str += '|ub:';
|
|
5842
|
+
str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
|
|
5843
|
+
str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
|
|
5908
5844
|
}
|
|
5845
|
+
targetImpl.memoizedCanonicalId = str;
|
|
5909
5846
|
}
|
|
5910
|
-
return
|
|
5847
|
+
return targetImpl.memoizedCanonicalId;
|
|
5848
|
+
}
|
|
5849
|
+
function stringifyTarget(target) {
|
|
5850
|
+
let str = target.path.canonicalString();
|
|
5851
|
+
if (target.collectionGroup !== null) {
|
|
5852
|
+
str += ' collectionGroup=' + target.collectionGroup;
|
|
5853
|
+
}
|
|
5854
|
+
if (target.filters.length > 0) {
|
|
5855
|
+
str += `, filters: [${target.filters
|
|
5856
|
+
.map(f => stringifyFilter(f))
|
|
5857
|
+
.join(', ')}]`;
|
|
5858
|
+
}
|
|
5859
|
+
if (!isNullOrUndefined(target.limit)) {
|
|
5860
|
+
str += ', limit: ' + target.limit;
|
|
5861
|
+
}
|
|
5862
|
+
if (target.orderBy.length > 0) {
|
|
5863
|
+
str += `, orderBy: [${target.orderBy
|
|
5864
|
+
.map(o => stringifyOrderBy(o))
|
|
5865
|
+
.join(', ')}]`;
|
|
5866
|
+
}
|
|
5867
|
+
if (target.startAt) {
|
|
5868
|
+
str += ', startAt: ';
|
|
5869
|
+
str += target.startAt.inclusive ? 'b:' : 'a:';
|
|
5870
|
+
str += target.startAt.position.map(p => canonicalId(p)).join(',');
|
|
5871
|
+
}
|
|
5872
|
+
if (target.endAt) {
|
|
5873
|
+
str += ', endAt: ';
|
|
5874
|
+
str += target.endAt.inclusive ? 'a:' : 'b:';
|
|
5875
|
+
str += target.endAt.position.map(p => canonicalId(p)).join(',');
|
|
5876
|
+
}
|
|
5877
|
+
return `Target(${str})`;
|
|
5878
|
+
}
|
|
5879
|
+
function targetEquals(left, right) {
|
|
5880
|
+
if (left.limit !== right.limit) {
|
|
5881
|
+
return false;
|
|
5882
|
+
}
|
|
5883
|
+
if (left.orderBy.length !== right.orderBy.length) {
|
|
5884
|
+
return false;
|
|
5885
|
+
}
|
|
5886
|
+
for (let i = 0; i < left.orderBy.length; i++) {
|
|
5887
|
+
if (!orderByEquals(left.orderBy[i], right.orderBy[i])) {
|
|
5888
|
+
return false;
|
|
5889
|
+
}
|
|
5890
|
+
}
|
|
5891
|
+
if (left.filters.length !== right.filters.length) {
|
|
5892
|
+
return false;
|
|
5893
|
+
}
|
|
5894
|
+
for (let i = 0; i < left.filters.length; i++) {
|
|
5895
|
+
if (!filterEquals(left.filters[i], right.filters[i])) {
|
|
5896
|
+
return false;
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5899
|
+
if (left.collectionGroup !== right.collectionGroup) {
|
|
5900
|
+
return false;
|
|
5901
|
+
}
|
|
5902
|
+
if (!left.path.isEqual(right.path)) {
|
|
5903
|
+
return false;
|
|
5904
|
+
}
|
|
5905
|
+
if (!boundEquals(left.startAt, right.startAt)) {
|
|
5906
|
+
return false;
|
|
5907
|
+
}
|
|
5908
|
+
return boundEquals(left.endAt, right.endAt);
|
|
5909
|
+
}
|
|
5910
|
+
function targetIsDocumentTarget(target) {
|
|
5911
|
+
return (DocumentKey.isDocumentKey(target.path) &&
|
|
5912
|
+
target.collectionGroup === null &&
|
|
5913
|
+
target.filters.length === 0);
|
|
5914
|
+
}
|
|
5915
|
+
/** Returns the field filters that target the given field path. */
|
|
5916
|
+
function targetGetFieldFiltersForPath(target, path) {
|
|
5917
|
+
return target.filters.filter(f => f instanceof FieldFilter && f.field.isEqual(path));
|
|
5911
5918
|
}
|
|
5912
5919
|
/**
|
|
5913
|
-
* Returns
|
|
5914
|
-
*
|
|
5920
|
+
* Returns the values that are used in ARRAY_CONTAINS or ARRAY_CONTAINS_ANY
|
|
5921
|
+
* filters. Returns `null` if there are no such filters.
|
|
5915
5922
|
*/
|
|
5916
|
-
function
|
|
5917
|
-
const
|
|
5918
|
-
|
|
5923
|
+
function targetGetArrayValues(target, fieldIndex) {
|
|
5924
|
+
const segment = fieldIndexGetArraySegment(fieldIndex);
|
|
5925
|
+
if (segment === undefined) {
|
|
5926
|
+
return null;
|
|
5927
|
+
}
|
|
5928
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, segment.fieldPath)) {
|
|
5929
|
+
switch (fieldFilter.op) {
|
|
5930
|
+
case "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */:
|
|
5931
|
+
return fieldFilter.value.arrayValue.values || [];
|
|
5932
|
+
case "array-contains" /* Operator.ARRAY_CONTAINS */:
|
|
5933
|
+
return [fieldFilter.value];
|
|
5934
|
+
// Remaining filters are not array filters.
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
return null;
|
|
5919
5938
|
}
|
|
5920
5939
|
/**
|
|
5921
|
-
* Returns
|
|
5922
|
-
*
|
|
5940
|
+
* Returns the list of values that are used in != or NOT_IN filters. Returns
|
|
5941
|
+
* `null` if there are no such filters.
|
|
5923
5942
|
*/
|
|
5924
|
-
function
|
|
5925
|
-
const
|
|
5926
|
-
|
|
5943
|
+
function targetGetNotInValues(target, fieldIndex) {
|
|
5944
|
+
const values = new Map();
|
|
5945
|
+
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5946
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, segment.fieldPath)) {
|
|
5947
|
+
switch (fieldFilter.op) {
|
|
5948
|
+
case "==" /* Operator.EQUAL */:
|
|
5949
|
+
case "in" /* Operator.IN */:
|
|
5950
|
+
// Encode equality prefix, which is encoded in the index value before
|
|
5951
|
+
// the inequality (e.g. `a == 'a' && b != 'b'` is encoded to
|
|
5952
|
+
// `value != 'ab'`).
|
|
5953
|
+
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5954
|
+
break;
|
|
5955
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
5956
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
5957
|
+
// NotIn/NotEqual is always a suffix. There cannot be any remaining
|
|
5958
|
+
// segments and hence we can return early here.
|
|
5959
|
+
values.set(segment.fieldPath.canonicalString(), fieldFilter.value);
|
|
5960
|
+
return Array.from(values.values());
|
|
5961
|
+
// Remaining filters cannot be used as notIn bounds.
|
|
5962
|
+
}
|
|
5963
|
+
}
|
|
5964
|
+
}
|
|
5965
|
+
return null;
|
|
5927
5966
|
}
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5967
|
+
/**
|
|
5968
|
+
* Returns a lower bound of field values that can be used as a starting point to
|
|
5969
|
+
* scan the index defined by `fieldIndex`. Returns `MIN_VALUE` if no lower bound
|
|
5970
|
+
* exists.
|
|
5971
|
+
*/
|
|
5972
|
+
function targetGetLowerBound(target, fieldIndex) {
|
|
5973
|
+
const values = [];
|
|
5974
|
+
let inclusive = true;
|
|
5975
|
+
// For each segment, retrieve a lower bound if there is a suitable filter or
|
|
5976
|
+
// startAt.
|
|
5977
|
+
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5978
|
+
const segmentBound = segment.kind === 0 /* IndexKind.ASCENDING */
|
|
5979
|
+
? targetGetAscendingBound(target, segment.fieldPath, target.startAt)
|
|
5980
|
+
: targetGetDescendingBound(target, segment.fieldPath, target.startAt);
|
|
5981
|
+
values.push(segmentBound.value);
|
|
5982
|
+
inclusive && (inclusive = segmentBound.inclusive);
|
|
5983
|
+
}
|
|
5984
|
+
return new Bound(values, inclusive);
|
|
5985
|
+
}
|
|
5986
|
+
/**
|
|
5987
|
+
* Returns an upper bound of field values that can be used as an ending point
|
|
5988
|
+
* when scanning the index defined by `fieldIndex`. Returns `MAX_VALUE` if no
|
|
5989
|
+
* upper bound exists.
|
|
5990
|
+
*/
|
|
5991
|
+
function targetGetUpperBound(target, fieldIndex) {
|
|
5992
|
+
const values = [];
|
|
5993
|
+
let inclusive = true;
|
|
5994
|
+
// For each segment, retrieve an upper bound if there is a suitable filter or
|
|
5995
|
+
// endAt.
|
|
5996
|
+
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
5997
|
+
const segmentBound = segment.kind === 0 /* IndexKind.ASCENDING */
|
|
5998
|
+
? targetGetDescendingBound(target, segment.fieldPath, target.endAt)
|
|
5999
|
+
: targetGetAscendingBound(target, segment.fieldPath, target.endAt);
|
|
6000
|
+
values.push(segmentBound.value);
|
|
6001
|
+
inclusive && (inclusive = segmentBound.inclusive);
|
|
6002
|
+
}
|
|
6003
|
+
return new Bound(values, inclusive);
|
|
6004
|
+
}
|
|
6005
|
+
/**
|
|
6006
|
+
* Returns the value to use as the lower bound for ascending index segment at
|
|
6007
|
+
* the provided `fieldPath` (or the upper bound for an descending segment).
|
|
6008
|
+
*/
|
|
6009
|
+
function targetGetAscendingBound(target, fieldPath, bound) {
|
|
6010
|
+
let value = MIN_VALUE;
|
|
6011
|
+
let inclusive = true;
|
|
6012
|
+
// Process all filters to find a value for the current field segment
|
|
6013
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
6014
|
+
let filterValue = MIN_VALUE;
|
|
6015
|
+
let filterInclusive = true;
|
|
6016
|
+
switch (fieldFilter.op) {
|
|
6017
|
+
case "<" /* Operator.LESS_THAN */:
|
|
6018
|
+
case "<=" /* Operator.LESS_THAN_OR_EQUAL */:
|
|
6019
|
+
filterValue = valuesGetLowerBound(fieldFilter.value);
|
|
6020
|
+
break;
|
|
6021
|
+
case "==" /* Operator.EQUAL */:
|
|
6022
|
+
case "in" /* Operator.IN */:
|
|
6023
|
+
case ">=" /* Operator.GREATER_THAN_OR_EQUAL */:
|
|
6024
|
+
filterValue = fieldFilter.value;
|
|
6025
|
+
break;
|
|
6026
|
+
case ">" /* Operator.GREATER_THAN */:
|
|
6027
|
+
filterValue = fieldFilter.value;
|
|
6028
|
+
filterInclusive = false;
|
|
6029
|
+
break;
|
|
6030
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
6031
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
6032
|
+
filterValue = MIN_VALUE;
|
|
6033
|
+
break;
|
|
6034
|
+
// Remaining filters cannot be used as lower bounds.
|
|
6035
|
+
}
|
|
6036
|
+
if (lowerBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) < 0) {
|
|
6037
|
+
value = filterValue;
|
|
6038
|
+
inclusive = filterInclusive;
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
// If there is an additional bound, compare the values against the existing
|
|
6042
|
+
// range to see if we can narrow the scope.
|
|
6043
|
+
if (bound !== null) {
|
|
6044
|
+
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
6045
|
+
const orderBy = target.orderBy[i];
|
|
6046
|
+
if (orderBy.field.isEqual(fieldPath)) {
|
|
6047
|
+
const cursorValue = bound.position[i];
|
|
6048
|
+
if (lowerBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) < 0) {
|
|
6049
|
+
value = cursorValue;
|
|
6050
|
+
inclusive = bound.inclusive;
|
|
6051
|
+
}
|
|
6052
|
+
break;
|
|
6053
|
+
}
|
|
6054
|
+
}
|
|
6055
|
+
}
|
|
6056
|
+
return { value, inclusive };
|
|
6057
|
+
}
|
|
6058
|
+
/**
|
|
6059
|
+
* Returns the value to use as the upper bound for ascending index segment at
|
|
6060
|
+
* the provided `fieldPath` (or the lower bound for a descending segment).
|
|
6061
|
+
*/
|
|
6062
|
+
function targetGetDescendingBound(target, fieldPath, bound) {
|
|
6063
|
+
let value = MAX_VALUE;
|
|
6064
|
+
let inclusive = true;
|
|
6065
|
+
// Process all filters to find a value for the current field segment
|
|
6066
|
+
for (const fieldFilter of targetGetFieldFiltersForPath(target, fieldPath)) {
|
|
6067
|
+
let filterValue = MAX_VALUE;
|
|
6068
|
+
let filterInclusive = true;
|
|
6069
|
+
switch (fieldFilter.op) {
|
|
6070
|
+
case ">=" /* Operator.GREATER_THAN_OR_EQUAL */:
|
|
6071
|
+
case ">" /* Operator.GREATER_THAN */:
|
|
6072
|
+
filterValue = valuesGetUpperBound(fieldFilter.value);
|
|
6073
|
+
filterInclusive = false;
|
|
6074
|
+
break;
|
|
6075
|
+
case "==" /* Operator.EQUAL */:
|
|
6076
|
+
case "in" /* Operator.IN */:
|
|
6077
|
+
case "<=" /* Operator.LESS_THAN_OR_EQUAL */:
|
|
6078
|
+
filterValue = fieldFilter.value;
|
|
6079
|
+
break;
|
|
6080
|
+
case "<" /* Operator.LESS_THAN */:
|
|
6081
|
+
filterValue = fieldFilter.value;
|
|
6082
|
+
filterInclusive = false;
|
|
6083
|
+
break;
|
|
6084
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
6085
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
6086
|
+
filterValue = MAX_VALUE;
|
|
6087
|
+
break;
|
|
6088
|
+
// Remaining filters cannot be used as upper bounds.
|
|
6089
|
+
}
|
|
6090
|
+
if (upperBoundCompare({ value, inclusive }, { value: filterValue, inclusive: filterInclusive }) > 0) {
|
|
6091
|
+
value = filterValue;
|
|
6092
|
+
inclusive = filterInclusive;
|
|
6093
|
+
}
|
|
5931
6094
|
}
|
|
5932
|
-
|
|
5933
|
-
|
|
6095
|
+
// If there is an additional bound, compare the values against the existing
|
|
6096
|
+
// range to see if we can narrow the scope.
|
|
6097
|
+
if (bound !== null) {
|
|
6098
|
+
for (let i = 0; i < target.orderBy.length; ++i) {
|
|
6099
|
+
const orderBy = target.orderBy[i];
|
|
6100
|
+
if (orderBy.field.isEqual(fieldPath)) {
|
|
6101
|
+
const cursorValue = bound.position[i];
|
|
6102
|
+
if (upperBoundCompare({ value, inclusive }, { value: cursorValue, inclusive: bound.inclusive }) > 0) {
|
|
6103
|
+
value = cursorValue;
|
|
6104
|
+
inclusive = bound.inclusive;
|
|
6105
|
+
}
|
|
6106
|
+
break;
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
5934
6109
|
}
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
6110
|
+
return { value, inclusive };
|
|
6111
|
+
}
|
|
6112
|
+
/** Returns the number of segments of a perfect index for this target. */
|
|
6113
|
+
function targetGetSegmentCount(target) {
|
|
6114
|
+
let fields = new SortedSet(FieldPath$1.comparator);
|
|
6115
|
+
let hasArraySegment = false;
|
|
6116
|
+
for (const filter of target.filters) {
|
|
6117
|
+
for (const subFilter of filter.getFlattenedFilters()) {
|
|
6118
|
+
// __name__ is not an explicit segment of any index, so we don't need to
|
|
6119
|
+
// count it.
|
|
6120
|
+
if (subFilter.field.isKeyField()) {
|
|
6121
|
+
continue;
|
|
6122
|
+
}
|
|
6123
|
+
// ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filters must be counted separately.
|
|
6124
|
+
// For instance, it is possible to have an index for "a ARRAY a ASC". Even
|
|
6125
|
+
// though these are on the same field, they should be counted as two
|
|
6126
|
+
// separate segments in an index.
|
|
6127
|
+
if (subFilter.op === "array-contains" /* Operator.ARRAY_CONTAINS */ ||
|
|
6128
|
+
subFilter.op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
6129
|
+
hasArraySegment = true;
|
|
6130
|
+
}
|
|
6131
|
+
else {
|
|
6132
|
+
fields = fields.add(subFilter.field);
|
|
6133
|
+
}
|
|
6134
|
+
}
|
|
5938
6135
|
}
|
|
5939
|
-
for (
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
if (!
|
|
5943
|
-
|
|
6136
|
+
for (const orderBy of target.orderBy) {
|
|
6137
|
+
// __name__ is not an explicit segment of any index, so we don't need to
|
|
6138
|
+
// count it.
|
|
6139
|
+
if (!orderBy.field.isKeyField()) {
|
|
6140
|
+
fields = fields.add(orderBy.field);
|
|
5944
6141
|
}
|
|
5945
6142
|
}
|
|
5946
|
-
return
|
|
6143
|
+
return fields.size + (hasArraySegment ? 1 : 0);
|
|
6144
|
+
}
|
|
6145
|
+
function targetHasLimit(target) {
|
|
6146
|
+
return target.limit !== null;
|
|
5947
6147
|
}
|
|
5948
6148
|
|
|
5949
6149
|
/**
|
|
@@ -5974,7 +6174,7 @@ class QueryImpl {
|
|
|
5974
6174
|
* Initializes a Query with a path and optional additional query constraints.
|
|
5975
6175
|
* Path must currently be empty if this is a collection group query.
|
|
5976
6176
|
*/
|
|
5977
|
-
constructor(path, collectionGroup = null, explicitOrderBy = [], filters = [], limit = null, limitType = "F" /* First */, startAt = null, endAt = null) {
|
|
6177
|
+
constructor(path, collectionGroup = null, explicitOrderBy = [], filters = [], limit = null, limitType = "F" /* LimitType.First */, startAt = null, endAt = null) {
|
|
5978
6178
|
this.path = path;
|
|
5979
6179
|
this.collectionGroup = collectionGroup;
|
|
5980
6180
|
this.explicitOrderBy = explicitOrderBy;
|
|
@@ -6028,20 +6228,9 @@ function getFirstOrderByField(query) {
|
|
|
6028
6228
|
}
|
|
6029
6229
|
function getInequalityFilterField(query) {
|
|
6030
6230
|
for (const filter of query.filters) {
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
}
|
|
6035
|
-
return null;
|
|
6036
|
-
}
|
|
6037
|
-
/**
|
|
6038
|
-
* Checks if any of the provided Operators are included in the query and
|
|
6039
|
-
* returns the first one that is, or null if none are.
|
|
6040
|
-
*/
|
|
6041
|
-
function findFilterOperator(query, operators) {
|
|
6042
|
-
for (const filter of query.filters) {
|
|
6043
|
-
if (operators.indexOf(filter.op) >= 0) {
|
|
6044
|
-
return filter.op;
|
|
6231
|
+
const result = filter.getFirstInequalityField();
|
|
6232
|
+
if (result !== null) {
|
|
6233
|
+
return result;
|
|
6045
6234
|
}
|
|
6046
6235
|
}
|
|
6047
6236
|
return null;
|
|
@@ -6087,7 +6276,7 @@ function queryOrderBy(query) {
|
|
|
6087
6276
|
if (!inequalityField.isKeyField()) {
|
|
6088
6277
|
queryImpl.memoizedOrderBy.push(new OrderBy(inequalityField));
|
|
6089
6278
|
}
|
|
6090
|
-
queryImpl.memoizedOrderBy.push(new OrderBy(FieldPath$1.keyField(), "asc" /* ASCENDING */));
|
|
6279
|
+
queryImpl.memoizedOrderBy.push(new OrderBy(FieldPath$1.keyField(), "asc" /* Direction.ASCENDING */));
|
|
6091
6280
|
}
|
|
6092
6281
|
else {
|
|
6093
6282
|
let foundKeyOrdering = false;
|
|
@@ -6103,7 +6292,7 @@ function queryOrderBy(query) {
|
|
|
6103
6292
|
const lastDirection = queryImpl.explicitOrderBy.length > 0
|
|
6104
6293
|
? queryImpl.explicitOrderBy[queryImpl.explicitOrderBy.length - 1]
|
|
6105
6294
|
.dir
|
|
6106
|
-
: "asc" /* ASCENDING */;
|
|
6295
|
+
: "asc" /* Direction.ASCENDING */;
|
|
6107
6296
|
queryImpl.memoizedOrderBy.push(new OrderBy(FieldPath$1.keyField(), lastDirection));
|
|
6108
6297
|
}
|
|
6109
6298
|
}
|
|
@@ -6116,16 +6305,16 @@ function queryOrderBy(query) {
|
|
|
6116
6305
|
function queryToTarget(query) {
|
|
6117
6306
|
const queryImpl = debugCast(query);
|
|
6118
6307
|
if (!queryImpl.memoizedTarget) {
|
|
6119
|
-
if (queryImpl.limitType === "F" /* First */) {
|
|
6308
|
+
if (queryImpl.limitType === "F" /* LimitType.First */) {
|
|
6120
6309
|
queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, queryOrderBy(queryImpl), queryImpl.filters, queryImpl.limit, queryImpl.startAt, queryImpl.endAt);
|
|
6121
6310
|
}
|
|
6122
6311
|
else {
|
|
6123
6312
|
// Flip the orderBy directions since we want the last results
|
|
6124
6313
|
const orderBys = [];
|
|
6125
6314
|
for (const orderBy of queryOrderBy(queryImpl)) {
|
|
6126
|
-
const dir = orderBy.dir === "desc" /* DESCENDING */
|
|
6127
|
-
? "asc" /* ASCENDING */
|
|
6128
|
-
: "desc" /* DESCENDING */;
|
|
6315
|
+
const dir = orderBy.dir === "desc" /* Direction.DESCENDING */
|
|
6316
|
+
? "asc" /* Direction.ASCENDING */
|
|
6317
|
+
: "desc" /* Direction.DESCENDING */;
|
|
6129
6318
|
orderBys.push(new OrderBy(orderBy.field, dir));
|
|
6130
6319
|
}
|
|
6131
6320
|
// We need to swap the cursors to match the now-flipped query ordering.
|
|
@@ -6142,6 +6331,8 @@ function queryToTarget(query) {
|
|
|
6142
6331
|
return queryImpl.memoizedTarget;
|
|
6143
6332
|
}
|
|
6144
6333
|
function queryWithAddedFilter(query, filter) {
|
|
6334
|
+
filter.getFirstInequalityField();
|
|
6335
|
+
getInequalityFilterField(query);
|
|
6145
6336
|
const newFilters = query.filters.concat([filter]);
|
|
6146
6337
|
return new QueryImpl(query.path, query.collectionGroup, query.explicitOrderBy.slice(), newFilters, query.limit, query.limitType, query.startAt, query.endAt);
|
|
6147
6338
|
}
|
|
@@ -6202,7 +6393,13 @@ function queryMatchesPathAndCollectionGroup(query, doc) {
|
|
|
6202
6393
|
* in the results.
|
|
6203
6394
|
*/
|
|
6204
6395
|
function queryMatchesOrderBy(query, doc) {
|
|
6205
|
-
|
|
6396
|
+
// We must use `queryOrderBy()` to get the list of all orderBys (both implicit and explicit).
|
|
6397
|
+
// Note that for OR queries, orderBy applies to all disjunction terms and implicit orderBys must
|
|
6398
|
+
// be taken into account. For example, the query "a > 1 || b==1" has an implicit "orderBy a" due
|
|
6399
|
+
// to the inequality, and is evaluated as "a > 1 orderBy a || b==1 orderBy a".
|
|
6400
|
+
// A document with content of {b:1} matches the filters, but does not match the orderBy because
|
|
6401
|
+
// it's missing the field 'a'.
|
|
6402
|
+
for (const orderBy of queryOrderBy(query)) {
|
|
6206
6403
|
// order by key always matches
|
|
6207
6404
|
if (!orderBy.field.isKeyField() && doc.data.field(orderBy.field) === null) {
|
|
6208
6405
|
return false;
|
|
@@ -6264,9 +6461,9 @@ function compareDocs(orderBy, d1, d2) {
|
|
|
6264
6461
|
? DocumentKey.comparator(d1.key, d2.key)
|
|
6265
6462
|
: compareDocumentsByField(orderBy.field, d1, d2);
|
|
6266
6463
|
switch (orderBy.dir) {
|
|
6267
|
-
case "asc" /* ASCENDING */:
|
|
6464
|
+
case "asc" /* Direction.ASCENDING */:
|
|
6268
6465
|
return comparison;
|
|
6269
|
-
case "desc" /* DESCENDING */:
|
|
6466
|
+
case "desc" /* Direction.DESCENDING */:
|
|
6270
6467
|
return -1 * comparison;
|
|
6271
6468
|
default:
|
|
6272
6469
|
return fail();
|
|
@@ -6952,10 +7149,10 @@ function mutationEquals(left, right) {
|
|
|
6952
7149
|
if (!fieldTransformsAreEqual(left.fieldTransforms, right.fieldTransforms)) {
|
|
6953
7150
|
return false;
|
|
6954
7151
|
}
|
|
6955
|
-
if (left.type === 0 /* Set */) {
|
|
7152
|
+
if (left.type === 0 /* MutationType.Set */) {
|
|
6956
7153
|
return left.value.isEqual(right.value);
|
|
6957
7154
|
}
|
|
6958
|
-
if (left.type === 1 /* Patch */) {
|
|
7155
|
+
if (left.type === 1 /* MutationType.Patch */) {
|
|
6959
7156
|
return (left.data.isEqual(right.data) &&
|
|
6960
7157
|
left.fieldMask.isEqual(right.fieldMask));
|
|
6961
7158
|
}
|
|
@@ -6972,7 +7169,7 @@ class SetMutation extends Mutation {
|
|
|
6972
7169
|
this.value = value;
|
|
6973
7170
|
this.precondition = precondition;
|
|
6974
7171
|
this.fieldTransforms = fieldTransforms;
|
|
6975
|
-
this.type = 0 /* Set */;
|
|
7172
|
+
this.type = 0 /* MutationType.Set */;
|
|
6976
7173
|
}
|
|
6977
7174
|
getFieldMask() {
|
|
6978
7175
|
return null;
|
|
@@ -7024,7 +7221,7 @@ class PatchMutation extends Mutation {
|
|
|
7024
7221
|
this.fieldMask = fieldMask;
|
|
7025
7222
|
this.precondition = precondition;
|
|
7026
7223
|
this.fieldTransforms = fieldTransforms;
|
|
7027
|
-
this.type = 1 /* Patch */;
|
|
7224
|
+
this.type = 1 /* MutationType.Patch */;
|
|
7028
7225
|
}
|
|
7029
7226
|
getFieldMask() {
|
|
7030
7227
|
return this.fieldMask;
|
|
@@ -7126,7 +7323,7 @@ class DeleteMutation extends Mutation {
|
|
|
7126
7323
|
super();
|
|
7127
7324
|
this.key = key;
|
|
7128
7325
|
this.precondition = precondition;
|
|
7129
|
-
this.type = 2 /* Delete */;
|
|
7326
|
+
this.type = 2 /* MutationType.Delete */;
|
|
7130
7327
|
this.fieldTransforms = [];
|
|
7131
7328
|
}
|
|
7132
7329
|
getFieldMask() {
|
|
@@ -7160,7 +7357,7 @@ class VerifyMutation extends Mutation {
|
|
|
7160
7357
|
super();
|
|
7161
7358
|
this.key = key;
|
|
7162
7359
|
this.precondition = precondition;
|
|
7163
|
-
this.type = 3 /* Verify */;
|
|
7360
|
+
this.type = 3 /* MutationType.Verify */;
|
|
7164
7361
|
this.fieldTransforms = [];
|
|
7165
7362
|
}
|
|
7166
7363
|
getFieldMask() {
|
|
@@ -7789,13 +7986,13 @@ class TargetState {
|
|
|
7789
7986
|
let removedDocuments = documentKeySet();
|
|
7790
7987
|
this.documentChanges.forEach((key, changeType) => {
|
|
7791
7988
|
switch (changeType) {
|
|
7792
|
-
case 0 /* Added */:
|
|
7989
|
+
case 0 /* ChangeType.Added */:
|
|
7793
7990
|
addedDocuments = addedDocuments.add(key);
|
|
7794
7991
|
break;
|
|
7795
|
-
case 2 /* Modified */:
|
|
7992
|
+
case 2 /* ChangeType.Modified */:
|
|
7796
7993
|
modifiedDocuments = modifiedDocuments.add(key);
|
|
7797
7994
|
break;
|
|
7798
|
-
case 1 /* Removed */:
|
|
7995
|
+
case 1 /* ChangeType.Removed */:
|
|
7799
7996
|
removedDocuments = removedDocuments.add(key);
|
|
7800
7997
|
break;
|
|
7801
7998
|
default:
|
|
@@ -7871,12 +8068,12 @@ class WatchChangeAggregator {
|
|
|
7871
8068
|
this.forEachTarget(targetChange, targetId => {
|
|
7872
8069
|
const targetState = this.ensureTargetState(targetId);
|
|
7873
8070
|
switch (targetChange.state) {
|
|
7874
|
-
case 0 /* NoChange */:
|
|
8071
|
+
case 0 /* WatchTargetChangeState.NoChange */:
|
|
7875
8072
|
if (this.isActiveTarget(targetId)) {
|
|
7876
8073
|
targetState.updateResumeToken(targetChange.resumeToken);
|
|
7877
8074
|
}
|
|
7878
8075
|
break;
|
|
7879
|
-
case 1 /* Added */:
|
|
8076
|
+
case 1 /* WatchTargetChangeState.Added */:
|
|
7880
8077
|
// We need to decrement the number of pending acks needed from watch
|
|
7881
8078
|
// for this targetId.
|
|
7882
8079
|
targetState.recordTargetResponse();
|
|
@@ -7888,7 +8085,7 @@ class WatchChangeAggregator {
|
|
|
7888
8085
|
}
|
|
7889
8086
|
targetState.updateResumeToken(targetChange.resumeToken);
|
|
7890
8087
|
break;
|
|
7891
|
-
case 2 /* Removed */:
|
|
8088
|
+
case 2 /* WatchTargetChangeState.Removed */:
|
|
7892
8089
|
// We need to keep track of removed targets to we can post-filter and
|
|
7893
8090
|
// remove any target changes.
|
|
7894
8091
|
// We need to decrement the number of pending acks needed from watch
|
|
@@ -7898,13 +8095,13 @@ class WatchChangeAggregator {
|
|
|
7898
8095
|
this.removeTarget(targetId);
|
|
7899
8096
|
}
|
|
7900
8097
|
break;
|
|
7901
|
-
case 3 /* Current */:
|
|
8098
|
+
case 3 /* WatchTargetChangeState.Current */:
|
|
7902
8099
|
if (this.isActiveTarget(targetId)) {
|
|
7903
8100
|
targetState.markCurrent();
|
|
7904
8101
|
targetState.updateResumeToken(targetChange.resumeToken);
|
|
7905
8102
|
}
|
|
7906
8103
|
break;
|
|
7907
|
-
case 4 /* Reset */:
|
|
8104
|
+
case 4 /* WatchTargetChangeState.Reset */:
|
|
7908
8105
|
if (this.isActiveTarget(targetId)) {
|
|
7909
8106
|
// Reset the target and synthesizes removes for all existing
|
|
7910
8107
|
// documents. The backend will re-add any documents that still
|
|
@@ -8014,7 +8211,7 @@ class WatchChangeAggregator {
|
|
|
8014
8211
|
targets.forEachWhile(targetId => {
|
|
8015
8212
|
const targetData = this.targetDataForActiveTarget(targetId);
|
|
8016
8213
|
if (targetData &&
|
|
8017
|
-
targetData.purpose !== 2 /* LimboResolution */) {
|
|
8214
|
+
targetData.purpose !== 2 /* TargetPurpose.LimboResolution */) {
|
|
8018
8215
|
isOnlyLimboTarget = false;
|
|
8019
8216
|
return false;
|
|
8020
8217
|
}
|
|
@@ -8041,8 +8238,8 @@ class WatchChangeAggregator {
|
|
|
8041
8238
|
return;
|
|
8042
8239
|
}
|
|
8043
8240
|
const changeType = this.targetContainsDocument(targetId, document.key)
|
|
8044
|
-
? 2 /* Modified */
|
|
8045
|
-
: 0 /* Added */;
|
|
8241
|
+
? 2 /* ChangeType.Modified */
|
|
8242
|
+
: 0 /* ChangeType.Added */;
|
|
8046
8243
|
const targetState = this.ensureTargetState(targetId);
|
|
8047
8244
|
targetState.addDocumentChange(document.key, changeType);
|
|
8048
8245
|
this.pendingDocumentUpdates = this.pendingDocumentUpdates.insert(document.key, document);
|
|
@@ -8063,7 +8260,7 @@ class WatchChangeAggregator {
|
|
|
8063
8260
|
}
|
|
8064
8261
|
const targetState = this.ensureTargetState(targetId);
|
|
8065
8262
|
if (this.targetContainsDocument(targetId, key)) {
|
|
8066
|
-
targetState.addDocumentChange(key, 1 /* Removed */);
|
|
8263
|
+
targetState.addDocumentChange(key, 1 /* ChangeType.Removed */);
|
|
8067
8264
|
}
|
|
8068
8265
|
else {
|
|
8069
8266
|
// The document may have entered and left the target before we raised a
|
|
@@ -8188,22 +8385,28 @@ function snapshotChangesMap() {
|
|
|
8188
8385
|
*/
|
|
8189
8386
|
const DIRECTIONS = (() => {
|
|
8190
8387
|
const dirs = {};
|
|
8191
|
-
dirs["asc" /* ASCENDING */] = 'ASCENDING';
|
|
8192
|
-
dirs["desc" /* DESCENDING */] = 'DESCENDING';
|
|
8388
|
+
dirs["asc" /* Direction.ASCENDING */] = 'ASCENDING';
|
|
8389
|
+
dirs["desc" /* Direction.DESCENDING */] = 'DESCENDING';
|
|
8193
8390
|
return dirs;
|
|
8194
8391
|
})();
|
|
8195
8392
|
const OPERATORS = (() => {
|
|
8196
8393
|
const ops = {};
|
|
8197
|
-
ops["<" /* LESS_THAN */] = 'LESS_THAN';
|
|
8198
|
-
ops["<=" /* LESS_THAN_OR_EQUAL */] = 'LESS_THAN_OR_EQUAL';
|
|
8199
|
-
ops[">" /* GREATER_THAN */] = 'GREATER_THAN';
|
|
8200
|
-
ops[">=" /* GREATER_THAN_OR_EQUAL */] = 'GREATER_THAN_OR_EQUAL';
|
|
8201
|
-
ops["==" /* EQUAL */] = 'EQUAL';
|
|
8202
|
-
ops["!=" /* NOT_EQUAL */] = 'NOT_EQUAL';
|
|
8203
|
-
ops["array-contains" /* ARRAY_CONTAINS */] = 'ARRAY_CONTAINS';
|
|
8204
|
-
ops["in" /* IN */] = 'IN';
|
|
8205
|
-
ops["not-in" /* NOT_IN */] = 'NOT_IN';
|
|
8206
|
-
ops["array-contains-any" /* ARRAY_CONTAINS_ANY */] = 'ARRAY_CONTAINS_ANY';
|
|
8394
|
+
ops["<" /* Operator.LESS_THAN */] = 'LESS_THAN';
|
|
8395
|
+
ops["<=" /* Operator.LESS_THAN_OR_EQUAL */] = 'LESS_THAN_OR_EQUAL';
|
|
8396
|
+
ops[">" /* Operator.GREATER_THAN */] = 'GREATER_THAN';
|
|
8397
|
+
ops[">=" /* Operator.GREATER_THAN_OR_EQUAL */] = 'GREATER_THAN_OR_EQUAL';
|
|
8398
|
+
ops["==" /* Operator.EQUAL */] = 'EQUAL';
|
|
8399
|
+
ops["!=" /* Operator.NOT_EQUAL */] = 'NOT_EQUAL';
|
|
8400
|
+
ops["array-contains" /* Operator.ARRAY_CONTAINS */] = 'ARRAY_CONTAINS';
|
|
8401
|
+
ops["in" /* Operator.IN */] = 'IN';
|
|
8402
|
+
ops["not-in" /* Operator.NOT_IN */] = 'NOT_IN';
|
|
8403
|
+
ops["array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */] = 'ARRAY_CONTAINS_ANY';
|
|
8404
|
+
return ops;
|
|
8405
|
+
})();
|
|
8406
|
+
const COMPOSITE_OPERATORS = (() => {
|
|
8407
|
+
const ops = {};
|
|
8408
|
+
ops["and" /* CompositeOperator.AND */] = 'AND';
|
|
8409
|
+
ops["or" /* CompositeOperator.OR */] = 'OR';
|
|
8207
8410
|
return ops;
|
|
8208
8411
|
})();
|
|
8209
8412
|
function assertPresent(value, description) {
|
|
@@ -8501,19 +8704,19 @@ function fromWatchChange(serializer, change) {
|
|
|
8501
8704
|
}
|
|
8502
8705
|
function fromWatchTargetChangeState(state) {
|
|
8503
8706
|
if (state === 'NO_CHANGE') {
|
|
8504
|
-
return 0 /* NoChange */;
|
|
8707
|
+
return 0 /* WatchTargetChangeState.NoChange */;
|
|
8505
8708
|
}
|
|
8506
8709
|
else if (state === 'ADD') {
|
|
8507
|
-
return 1 /* Added */;
|
|
8710
|
+
return 1 /* WatchTargetChangeState.Added */;
|
|
8508
8711
|
}
|
|
8509
8712
|
else if (state === 'REMOVE') {
|
|
8510
|
-
return 2 /* Removed */;
|
|
8713
|
+
return 2 /* WatchTargetChangeState.Removed */;
|
|
8511
8714
|
}
|
|
8512
8715
|
else if (state === 'CURRENT') {
|
|
8513
|
-
return 3 /* Current */;
|
|
8716
|
+
return 3 /* WatchTargetChangeState.Current */;
|
|
8514
8717
|
}
|
|
8515
8718
|
else if (state === 'RESET') {
|
|
8516
|
-
return 4 /* Reset */;
|
|
8719
|
+
return 4 /* WatchTargetChangeState.Reset */;
|
|
8517
8720
|
}
|
|
8518
8721
|
else {
|
|
8519
8722
|
return fail();
|
|
@@ -8731,7 +8934,7 @@ function toQueryTarget(serializer, target) {
|
|
|
8731
8934
|
result.parent = toQueryPath(serializer, path.popLast());
|
|
8732
8935
|
result.structuredQuery.from = [{ collectionId: path.lastSegment() }];
|
|
8733
8936
|
}
|
|
8734
|
-
const where =
|
|
8937
|
+
const where = toFilters(target.filters);
|
|
8735
8938
|
if (where) {
|
|
8736
8939
|
result.structuredQuery.where = where;
|
|
8737
8940
|
}
|
|
@@ -8783,7 +8986,7 @@ function convertQueryTargetToQuery(target) {
|
|
|
8783
8986
|
}
|
|
8784
8987
|
let filterBy = [];
|
|
8785
8988
|
if (query.where) {
|
|
8786
|
-
filterBy =
|
|
8989
|
+
filterBy = fromFilters(query.where);
|
|
8787
8990
|
}
|
|
8788
8991
|
let orderBy = [];
|
|
8789
8992
|
if (query.orderBy) {
|
|
@@ -8801,7 +9004,7 @@ function convertQueryTargetToQuery(target) {
|
|
|
8801
9004
|
if (query.endAt) {
|
|
8802
9005
|
endAt = fromEndAtCursor(query.endAt);
|
|
8803
9006
|
}
|
|
8804
|
-
return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
|
|
9007
|
+
return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* LimitType.First */, startAt, endAt);
|
|
8805
9008
|
}
|
|
8806
9009
|
function fromQueryTarget(target) {
|
|
8807
9010
|
return queryToTarget(convertQueryTargetToQuery(target));
|
|
@@ -8819,11 +9022,11 @@ function toListenRequestLabels(serializer, targetData) {
|
|
|
8819
9022
|
}
|
|
8820
9023
|
function toLabel(serializer, purpose) {
|
|
8821
9024
|
switch (purpose) {
|
|
8822
|
-
case 0 /* Listen */:
|
|
9025
|
+
case 0 /* TargetPurpose.Listen */:
|
|
8823
9026
|
return null;
|
|
8824
|
-
case 1 /* ExistenceFilterMismatch */:
|
|
9027
|
+
case 1 /* TargetPurpose.ExistenceFilterMismatch */:
|
|
8825
9028
|
return 'existence-filter-mismatch';
|
|
8826
|
-
case 2 /* LimboResolution */:
|
|
9029
|
+
case 2 /* TargetPurpose.LimboResolution */:
|
|
8827
9030
|
return 'limbo-document';
|
|
8828
9031
|
default:
|
|
8829
9032
|
return fail();
|
|
@@ -8850,32 +9053,29 @@ function toTarget(serializer, targetData) {
|
|
|
8850
9053
|
}
|
|
8851
9054
|
return result;
|
|
8852
9055
|
}
|
|
8853
|
-
function
|
|
9056
|
+
function toFilters(filters) {
|
|
8854
9057
|
if (filters.length === 0) {
|
|
8855
9058
|
return;
|
|
8856
9059
|
}
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
9060
|
+
return toFilter(CompositeFilter.create(filters, "and" /* CompositeOperator.AND */));
|
|
9061
|
+
}
|
|
9062
|
+
function fromFilters(filter) {
|
|
9063
|
+
const result = fromFilter(filter);
|
|
9064
|
+
if (result instanceof CompositeFilter &&
|
|
9065
|
+
compositeFilterIsFlatConjunction(result)) {
|
|
9066
|
+
return result.getFilters();
|
|
8862
9067
|
}
|
|
8863
|
-
return
|
|
9068
|
+
return [result];
|
|
8864
9069
|
}
|
|
8865
9070
|
function fromFilter(filter) {
|
|
8866
|
-
if (
|
|
8867
|
-
return
|
|
8868
|
-
}
|
|
8869
|
-
else if (filter.unaryFilter !== undefined) {
|
|
8870
|
-
return [fromUnaryFilter(filter)];
|
|
9071
|
+
if (filter.unaryFilter !== undefined) {
|
|
9072
|
+
return fromUnaryFilter(filter);
|
|
8871
9073
|
}
|
|
8872
9074
|
else if (filter.fieldFilter !== undefined) {
|
|
8873
|
-
return
|
|
9075
|
+
return fromFieldFilter(filter);
|
|
8874
9076
|
}
|
|
8875
9077
|
else if (filter.compositeFilter !== undefined) {
|
|
8876
|
-
return filter
|
|
8877
|
-
.filters.map(f => fromFilter(f))
|
|
8878
|
-
.reduce((accum, current) => accum.concat(current));
|
|
9078
|
+
return fromCompositeFilter(filter);
|
|
8879
9079
|
}
|
|
8880
9080
|
else {
|
|
8881
9081
|
return fail();
|
|
@@ -8920,9 +9120,9 @@ function toDirection(dir) {
|
|
|
8920
9120
|
function fromDirection(dir) {
|
|
8921
9121
|
switch (dir) {
|
|
8922
9122
|
case 'ASCENDING':
|
|
8923
|
-
return "asc" /* ASCENDING */;
|
|
9123
|
+
return "asc" /* Direction.ASCENDING */;
|
|
8924
9124
|
case 'DESCENDING':
|
|
8925
|
-
return "desc" /* DESCENDING */;
|
|
9125
|
+
return "desc" /* Direction.DESCENDING */;
|
|
8926
9126
|
default:
|
|
8927
9127
|
return undefined;
|
|
8928
9128
|
}
|
|
@@ -8931,34 +9131,47 @@ function fromDirection(dir) {
|
|
|
8931
9131
|
function toOperatorName(op) {
|
|
8932
9132
|
return OPERATORS[op];
|
|
8933
9133
|
}
|
|
9134
|
+
function toCompositeOperatorName(op) {
|
|
9135
|
+
return COMPOSITE_OPERATORS[op];
|
|
9136
|
+
}
|
|
8934
9137
|
function fromOperatorName(op) {
|
|
8935
9138
|
switch (op) {
|
|
8936
9139
|
case 'EQUAL':
|
|
8937
|
-
return "==" /* EQUAL */;
|
|
9140
|
+
return "==" /* Operator.EQUAL */;
|
|
8938
9141
|
case 'NOT_EQUAL':
|
|
8939
|
-
return "!=" /* NOT_EQUAL */;
|
|
9142
|
+
return "!=" /* Operator.NOT_EQUAL */;
|
|
8940
9143
|
case 'GREATER_THAN':
|
|
8941
|
-
return ">" /* GREATER_THAN */;
|
|
9144
|
+
return ">" /* Operator.GREATER_THAN */;
|
|
8942
9145
|
case 'GREATER_THAN_OR_EQUAL':
|
|
8943
|
-
return ">=" /* GREATER_THAN_OR_EQUAL */;
|
|
9146
|
+
return ">=" /* Operator.GREATER_THAN_OR_EQUAL */;
|
|
8944
9147
|
case 'LESS_THAN':
|
|
8945
|
-
return "<" /* LESS_THAN */;
|
|
9148
|
+
return "<" /* Operator.LESS_THAN */;
|
|
8946
9149
|
case 'LESS_THAN_OR_EQUAL':
|
|
8947
|
-
return "<=" /* LESS_THAN_OR_EQUAL */;
|
|
9150
|
+
return "<=" /* Operator.LESS_THAN_OR_EQUAL */;
|
|
8948
9151
|
case 'ARRAY_CONTAINS':
|
|
8949
|
-
return "array-contains" /* ARRAY_CONTAINS */;
|
|
9152
|
+
return "array-contains" /* Operator.ARRAY_CONTAINS */;
|
|
8950
9153
|
case 'IN':
|
|
8951
|
-
return "in" /* IN */;
|
|
9154
|
+
return "in" /* Operator.IN */;
|
|
8952
9155
|
case 'NOT_IN':
|
|
8953
|
-
return "not-in" /* NOT_IN */;
|
|
9156
|
+
return "not-in" /* Operator.NOT_IN */;
|
|
8954
9157
|
case 'ARRAY_CONTAINS_ANY':
|
|
8955
|
-
return "array-contains-any" /* ARRAY_CONTAINS_ANY */;
|
|
9158
|
+
return "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */;
|
|
8956
9159
|
case 'OPERATOR_UNSPECIFIED':
|
|
8957
9160
|
return fail();
|
|
8958
9161
|
default:
|
|
8959
9162
|
return fail();
|
|
8960
9163
|
}
|
|
8961
9164
|
}
|
|
9165
|
+
function fromCompositeOperatorName(op) {
|
|
9166
|
+
switch (op) {
|
|
9167
|
+
case 'AND':
|
|
9168
|
+
return "and" /* CompositeOperator.AND */;
|
|
9169
|
+
case 'OR':
|
|
9170
|
+
return "or" /* CompositeOperator.OR */;
|
|
9171
|
+
default:
|
|
9172
|
+
return fail();
|
|
9173
|
+
}
|
|
9174
|
+
}
|
|
8962
9175
|
function toFieldPathReference(path) {
|
|
8963
9176
|
return { fieldPath: path.canonicalString() };
|
|
8964
9177
|
}
|
|
@@ -8975,12 +9188,32 @@ function toPropertyOrder(orderBy) {
|
|
|
8975
9188
|
function fromPropertyOrder(orderBy) {
|
|
8976
9189
|
return new OrderBy(fromFieldPathReference(orderBy.field), fromDirection(orderBy.direction));
|
|
8977
9190
|
}
|
|
8978
|
-
function fromFieldFilter(filter) {
|
|
8979
|
-
return FieldFilter.create(fromFieldPathReference(filter.fieldFilter.field), fromOperatorName(filter.fieldFilter.op), filter.fieldFilter.value);
|
|
8980
|
-
}
|
|
8981
9191
|
// visible for testing
|
|
9192
|
+
function toFilter(filter) {
|
|
9193
|
+
if (filter instanceof FieldFilter) {
|
|
9194
|
+
return toUnaryOrFieldFilter(filter);
|
|
9195
|
+
}
|
|
9196
|
+
else if (filter instanceof CompositeFilter) {
|
|
9197
|
+
return toCompositeFilter(filter);
|
|
9198
|
+
}
|
|
9199
|
+
else {
|
|
9200
|
+
return fail();
|
|
9201
|
+
}
|
|
9202
|
+
}
|
|
9203
|
+
function toCompositeFilter(filter) {
|
|
9204
|
+
const protos = filter.getFilters().map(filter => toFilter(filter));
|
|
9205
|
+
if (protos.length === 1) {
|
|
9206
|
+
return protos[0];
|
|
9207
|
+
}
|
|
9208
|
+
return {
|
|
9209
|
+
compositeFilter: {
|
|
9210
|
+
op: toCompositeOperatorName(filter.op),
|
|
9211
|
+
filters: protos
|
|
9212
|
+
}
|
|
9213
|
+
};
|
|
9214
|
+
}
|
|
8982
9215
|
function toUnaryOrFieldFilter(filter) {
|
|
8983
|
-
if (filter.op === "==" /* EQUAL */) {
|
|
9216
|
+
if (filter.op === "==" /* Operator.EQUAL */) {
|
|
8984
9217
|
if (isNanValue(filter.value)) {
|
|
8985
9218
|
return {
|
|
8986
9219
|
unaryFilter: {
|
|
@@ -8998,7 +9231,7 @@ function toUnaryOrFieldFilter(filter) {
|
|
|
8998
9231
|
};
|
|
8999
9232
|
}
|
|
9000
9233
|
}
|
|
9001
|
-
else if (filter.op === "!=" /* NOT_EQUAL */) {
|
|
9234
|
+
else if (filter.op === "!=" /* Operator.NOT_EQUAL */) {
|
|
9002
9235
|
if (isNanValue(filter.value)) {
|
|
9003
9236
|
return {
|
|
9004
9237
|
unaryFilter: {
|
|
@@ -9028,22 +9261,22 @@ function fromUnaryFilter(filter) {
|
|
|
9028
9261
|
switch (filter.unaryFilter.op) {
|
|
9029
9262
|
case 'IS_NAN':
|
|
9030
9263
|
const nanField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9031
|
-
return FieldFilter.create(nanField, "==" /* EQUAL */, {
|
|
9264
|
+
return FieldFilter.create(nanField, "==" /* Operator.EQUAL */, {
|
|
9032
9265
|
doubleValue: NaN
|
|
9033
9266
|
});
|
|
9034
9267
|
case 'IS_NULL':
|
|
9035
9268
|
const nullField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9036
|
-
return FieldFilter.create(nullField, "==" /* EQUAL */, {
|
|
9269
|
+
return FieldFilter.create(nullField, "==" /* Operator.EQUAL */, {
|
|
9037
9270
|
nullValue: 'NULL_VALUE'
|
|
9038
9271
|
});
|
|
9039
9272
|
case 'IS_NOT_NAN':
|
|
9040
9273
|
const notNanField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9041
|
-
return FieldFilter.create(notNanField, "!=" /* NOT_EQUAL */, {
|
|
9274
|
+
return FieldFilter.create(notNanField, "!=" /* Operator.NOT_EQUAL */, {
|
|
9042
9275
|
doubleValue: NaN
|
|
9043
9276
|
});
|
|
9044
9277
|
case 'IS_NOT_NULL':
|
|
9045
9278
|
const notNullField = fromFieldPathReference(filter.unaryFilter.field);
|
|
9046
|
-
return FieldFilter.create(notNullField, "!=" /* NOT_EQUAL */, {
|
|
9279
|
+
return FieldFilter.create(notNullField, "!=" /* Operator.NOT_EQUAL */, {
|
|
9047
9280
|
nullValue: 'NULL_VALUE'
|
|
9048
9281
|
});
|
|
9049
9282
|
case 'OPERATOR_UNSPECIFIED':
|
|
@@ -9052,6 +9285,12 @@ function fromUnaryFilter(filter) {
|
|
|
9052
9285
|
return fail();
|
|
9053
9286
|
}
|
|
9054
9287
|
}
|
|
9288
|
+
function fromFieldFilter(filter) {
|
|
9289
|
+
return FieldFilter.create(fromFieldPathReference(filter.fieldFilter.field), fromOperatorName(filter.fieldFilter.op), filter.fieldFilter.value);
|
|
9290
|
+
}
|
|
9291
|
+
function fromCompositeFilter(filter) {
|
|
9292
|
+
return CompositeFilter.create(filter.compositeFilter.filters.map(filter => fromFilter(filter)), fromCompositeOperatorName(filter.compositeFilter.op));
|
|
9293
|
+
}
|
|
9055
9294
|
function toDocumentMask(fieldMask) {
|
|
9056
9295
|
const canonicalFields = [];
|
|
9057
9296
|
fieldMask.fields.forEach(field => canonicalFields.push(field.canonicalString()));
|
|
@@ -9291,7 +9530,7 @@ function fromDbTarget(dbTarget) {
|
|
|
9291
9530
|
else {
|
|
9292
9531
|
target = fromQueryTarget(dbTarget.query);
|
|
9293
9532
|
}
|
|
9294
|
-
return new TargetData(target, dbTarget.targetId, 0 /* Listen */, dbTarget.lastListenSequenceNumber, version, lastLimboFreeSnapshotVersion, ByteString.fromBase64String(dbTarget.resumeToken));
|
|
9533
|
+
return new TargetData(target, dbTarget.targetId, 0 /* TargetPurpose.Listen */, dbTarget.lastListenSequenceNumber, version, lastLimboFreeSnapshotVersion, ByteString.fromBase64String(dbTarget.resumeToken));
|
|
9295
9534
|
}
|
|
9296
9535
|
/** Encodes TargetData into a DbTarget for storage locally. */
|
|
9297
9536
|
function toDbTarget(localSerializer, targetData) {
|
|
@@ -9368,7 +9607,7 @@ function fromBundledQuery(bundledQuery) {
|
|
|
9368
9607
|
structuredQuery: bundledQuery.structuredQuery
|
|
9369
9608
|
});
|
|
9370
9609
|
if (bundledQuery.limitType === 'LAST') {
|
|
9371
|
-
return queryWithLimit(query, query.limit, "L" /* Last */);
|
|
9610
|
+
return queryWithLimit(query, query.limit, "L" /* LimitType.Last */);
|
|
9372
9611
|
}
|
|
9373
9612
|
return query;
|
|
9374
9613
|
}
|
|
@@ -10143,7 +10382,7 @@ class IndexByteEncoder {
|
|
|
10143
10382
|
this.orderedCode.seed(encodedBytes);
|
|
10144
10383
|
}
|
|
10145
10384
|
forKind(kind) {
|
|
10146
|
-
return kind === 0 /* ASCENDING */ ? this.ascending : this.descending;
|
|
10385
|
+
return kind === 0 /* IndexKind.ASCENDING */ ? this.ascending : this.descending;
|
|
10147
10386
|
}
|
|
10148
10387
|
encodedBytes() {
|
|
10149
10388
|
return this.orderedCode.encodedBytes();
|
|
@@ -10298,6 +10537,7 @@ class TargetIndexMatcher {
|
|
|
10298
10537
|
* omitted.
|
|
10299
10538
|
*/
|
|
10300
10539
|
servedByIndex(index) {
|
|
10540
|
+
hardAssert(index.collectionGroup === this.collectionId);
|
|
10301
10541
|
// If there is an array element, find a matching filter.
|
|
10302
10542
|
const arraySegment = fieldIndexGetArraySegment(index);
|
|
10303
10543
|
if (arraySegment !== undefined &&
|
|
@@ -10361,19 +10601,268 @@ class TargetIndexMatcher {
|
|
|
10361
10601
|
if (filter === undefined || !filter.field.isEqual(segment.fieldPath)) {
|
|
10362
10602
|
return false;
|
|
10363
10603
|
}
|
|
10364
|
-
const isArrayOperator = filter.op === "array-contains" /* ARRAY_CONTAINS */ ||
|
|
10365
|
-
filter.op === "array-contains-any" /* ARRAY_CONTAINS_ANY */;
|
|
10366
|
-
return (segment.kind === 2 /* CONTAINS */) === isArrayOperator;
|
|
10604
|
+
const isArrayOperator = filter.op === "array-contains" /* Operator.ARRAY_CONTAINS */ ||
|
|
10605
|
+
filter.op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */;
|
|
10606
|
+
return (segment.kind === 2 /* IndexKind.CONTAINS */) === isArrayOperator;
|
|
10367
10607
|
}
|
|
10368
10608
|
matchesOrderBy(orderBy, segment) {
|
|
10369
10609
|
if (!orderBy.field.isEqual(segment.fieldPath)) {
|
|
10370
10610
|
return false;
|
|
10371
10611
|
}
|
|
10372
|
-
return ((segment.kind === 0 /* ASCENDING */ &&
|
|
10373
|
-
orderBy.dir === "asc" /* ASCENDING */) ||
|
|
10374
|
-
(segment.kind === 1 /* DESCENDING */ &&
|
|
10375
|
-
orderBy.dir === "desc" /* DESCENDING */));
|
|
10612
|
+
return ((segment.kind === 0 /* IndexKind.ASCENDING */ &&
|
|
10613
|
+
orderBy.dir === "asc" /* Direction.ASCENDING */) ||
|
|
10614
|
+
(segment.kind === 1 /* IndexKind.DESCENDING */ &&
|
|
10615
|
+
orderBy.dir === "desc" /* Direction.DESCENDING */));
|
|
10616
|
+
}
|
|
10617
|
+
}
|
|
10618
|
+
|
|
10619
|
+
/**
|
|
10620
|
+
* @license
|
|
10621
|
+
* Copyright 2022 Google LLC
|
|
10622
|
+
*
|
|
10623
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10624
|
+
* you may not use this file except in compliance with the License.
|
|
10625
|
+
* You may obtain a copy of the License at
|
|
10626
|
+
*
|
|
10627
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10628
|
+
*
|
|
10629
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10630
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
10631
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10632
|
+
* See the License for the specific language governing permissions and
|
|
10633
|
+
* limitations under the License.
|
|
10634
|
+
*/
|
|
10635
|
+
/**
|
|
10636
|
+
* Provides utility functions that help with boolean logic transformations needed for handling
|
|
10637
|
+
* complex filters used in queries.
|
|
10638
|
+
*/
|
|
10639
|
+
/**
|
|
10640
|
+
* The `in` filter is only a syntactic sugar over a disjunction of equalities. For instance: `a in
|
|
10641
|
+
* [1,2,3]` is in fact `a==1 || a==2 || a==3`. This method expands any `in` filter in the given
|
|
10642
|
+
* input into a disjunction of equality filters and returns the expanded filter.
|
|
10643
|
+
*/
|
|
10644
|
+
function computeInExpansion(filter) {
|
|
10645
|
+
var _a, _b;
|
|
10646
|
+
hardAssert(filter instanceof FieldFilter || filter instanceof CompositeFilter);
|
|
10647
|
+
if (filter instanceof FieldFilter) {
|
|
10648
|
+
if (filter instanceof InFilter) {
|
|
10649
|
+
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))) || [];
|
|
10650
|
+
return CompositeFilter.create(expandedFilters, "or" /* CompositeOperator.OR */);
|
|
10651
|
+
}
|
|
10652
|
+
else {
|
|
10653
|
+
// We have reached other kinds of field filters.
|
|
10654
|
+
return filter;
|
|
10655
|
+
}
|
|
10656
|
+
}
|
|
10657
|
+
// We have a composite filter.
|
|
10658
|
+
const expandedFilters = filter.filters.map(subfilter => computeInExpansion(subfilter));
|
|
10659
|
+
return CompositeFilter.create(expandedFilters, filter.op);
|
|
10660
|
+
}
|
|
10661
|
+
/**
|
|
10662
|
+
* Given a composite filter, returns the list of terms in its disjunctive normal form.
|
|
10663
|
+
*
|
|
10664
|
+
* <p>Each element in the return value is one term of the resulting DNF. For instance: For the
|
|
10665
|
+
* input: (A || B) && C, the DNF form is: (A && C) || (B && C), and the return value is a list
|
|
10666
|
+
* with two elements: a composite filter that performs (A && C), and a composite filter that
|
|
10667
|
+
* performs (B && C).
|
|
10668
|
+
*
|
|
10669
|
+
* @param filter the composite filter to calculate DNF transform for.
|
|
10670
|
+
* @return the terms in the DNF transform.
|
|
10671
|
+
*/
|
|
10672
|
+
function getDnfTerms(filter) {
|
|
10673
|
+
if (filter.getFilters().length === 0) {
|
|
10674
|
+
return [];
|
|
10675
|
+
}
|
|
10676
|
+
const result = computeDistributedNormalForm(computeInExpansion(filter));
|
|
10677
|
+
hardAssert(isDisjunctiveNormalForm(result));
|
|
10678
|
+
if (isSingleFieldFilter(result) || isFlatConjunction(result)) {
|
|
10679
|
+
return [result];
|
|
10680
|
+
}
|
|
10681
|
+
return result.getFilters();
|
|
10682
|
+
}
|
|
10683
|
+
/** Returns true if the given filter is a single field filter. e.g. (a == 10). */
|
|
10684
|
+
function isSingleFieldFilter(filter) {
|
|
10685
|
+
return filter instanceof FieldFilter;
|
|
10686
|
+
}
|
|
10687
|
+
/**
|
|
10688
|
+
* Returns true if the given filter is the conjunction of one or more field filters. e.g. (a == 10
|
|
10689
|
+
* && b == 20)
|
|
10690
|
+
*/
|
|
10691
|
+
function isFlatConjunction(filter) {
|
|
10692
|
+
return (filter instanceof CompositeFilter &&
|
|
10693
|
+
compositeFilterIsFlatConjunction(filter));
|
|
10694
|
+
}
|
|
10695
|
+
/**
|
|
10696
|
+
* Returns whether or not the given filter is in disjunctive normal form (DNF).
|
|
10697
|
+
*
|
|
10698
|
+
* <p>In boolean logic, a disjunctive normal form (DNF) is a canonical normal form of a logical
|
|
10699
|
+
* formula consisting of a disjunction of conjunctions; it can also be described as an OR of ANDs.
|
|
10700
|
+
*
|
|
10701
|
+
* <p>For more info, visit: https://en.wikipedia.org/wiki/Disjunctive_normal_form
|
|
10702
|
+
*/
|
|
10703
|
+
function isDisjunctiveNormalForm(filter) {
|
|
10704
|
+
return (isSingleFieldFilter(filter) ||
|
|
10705
|
+
isFlatConjunction(filter) ||
|
|
10706
|
+
isDisjunctionOfFieldFiltersAndFlatConjunctions(filter));
|
|
10707
|
+
}
|
|
10708
|
+
/**
|
|
10709
|
+
* Returns true if the given filter is the disjunction of one or more "flat conjunctions" and
|
|
10710
|
+
* field filters. e.g. (a == 10) || (b==20 && c==30)
|
|
10711
|
+
*/
|
|
10712
|
+
function isDisjunctionOfFieldFiltersAndFlatConjunctions(filter) {
|
|
10713
|
+
if (filter instanceof CompositeFilter) {
|
|
10714
|
+
if (compositeFilterIsDisjunction(filter)) {
|
|
10715
|
+
for (const subFilter of filter.getFilters()) {
|
|
10716
|
+
if (!isSingleFieldFilter(subFilter) && !isFlatConjunction(subFilter)) {
|
|
10717
|
+
return false;
|
|
10718
|
+
}
|
|
10719
|
+
}
|
|
10720
|
+
return true;
|
|
10721
|
+
}
|
|
10722
|
+
}
|
|
10723
|
+
return false;
|
|
10724
|
+
}
|
|
10725
|
+
function computeDistributedNormalForm(filter) {
|
|
10726
|
+
hardAssert(filter instanceof FieldFilter || filter instanceof CompositeFilter);
|
|
10727
|
+
if (filter instanceof FieldFilter) {
|
|
10728
|
+
return filter;
|
|
10729
|
+
}
|
|
10730
|
+
if (filter.filters.length === 1) {
|
|
10731
|
+
return computeDistributedNormalForm(filter.filters[0]);
|
|
10732
|
+
}
|
|
10733
|
+
// Compute DNF for each of the subfilters first
|
|
10734
|
+
const result = filter.filters.map(subfilter => computeDistributedNormalForm(subfilter));
|
|
10735
|
+
let newFilter = CompositeFilter.create(result, filter.op);
|
|
10736
|
+
newFilter = applyAssociation(newFilter);
|
|
10737
|
+
if (isDisjunctiveNormalForm(newFilter)) {
|
|
10738
|
+
return newFilter;
|
|
10739
|
+
}
|
|
10740
|
+
hardAssert(newFilter instanceof CompositeFilter);
|
|
10741
|
+
hardAssert(compositeFilterIsConjunction(newFilter));
|
|
10742
|
+
hardAssert(newFilter.filters.length > 1);
|
|
10743
|
+
return newFilter.filters.reduce((runningResult, filter) => applyDistribution(runningResult, filter));
|
|
10744
|
+
}
|
|
10745
|
+
function applyDistribution(lhs, rhs) {
|
|
10746
|
+
hardAssert(lhs instanceof FieldFilter || lhs instanceof CompositeFilter);
|
|
10747
|
+
hardAssert(rhs instanceof FieldFilter || rhs instanceof CompositeFilter);
|
|
10748
|
+
let result;
|
|
10749
|
+
if (lhs instanceof FieldFilter) {
|
|
10750
|
+
if (rhs instanceof FieldFilter) {
|
|
10751
|
+
// FieldFilter FieldFilter
|
|
10752
|
+
result = applyDistributionFieldFilters(lhs, rhs);
|
|
10753
|
+
}
|
|
10754
|
+
else {
|
|
10755
|
+
// FieldFilter CompositeFilter
|
|
10756
|
+
result = applyDistributionFieldAndCompositeFilters(lhs, rhs);
|
|
10757
|
+
}
|
|
10758
|
+
}
|
|
10759
|
+
else {
|
|
10760
|
+
if (rhs instanceof FieldFilter) {
|
|
10761
|
+
// CompositeFilter FieldFilter
|
|
10762
|
+
result = applyDistributionFieldAndCompositeFilters(rhs, lhs);
|
|
10763
|
+
}
|
|
10764
|
+
else {
|
|
10765
|
+
// CompositeFilter CompositeFilter
|
|
10766
|
+
result = applyDistributionCompositeFilters(lhs, rhs);
|
|
10767
|
+
}
|
|
10768
|
+
}
|
|
10769
|
+
return applyAssociation(result);
|
|
10770
|
+
}
|
|
10771
|
+
function applyDistributionFieldFilters(lhs, rhs) {
|
|
10772
|
+
// Conjunction distribution for two field filters is the conjunction of them.
|
|
10773
|
+
return CompositeFilter.create([lhs, rhs], "and" /* CompositeOperator.AND */);
|
|
10774
|
+
}
|
|
10775
|
+
function applyDistributionCompositeFilters(lhs, rhs) {
|
|
10776
|
+
hardAssert(lhs.filters.length > 0 && rhs.filters.length > 0);
|
|
10777
|
+
// There are four cases:
|
|
10778
|
+
// (A & B) & (C & D) --> (A & B & C & D)
|
|
10779
|
+
// (A & B) & (C | D) --> (A & B & C) | (A & B & D)
|
|
10780
|
+
// (A | B) & (C & D) --> (C & D & A) | (C & D & B)
|
|
10781
|
+
// (A | B) & (C | D) --> (A & C) | (A & D) | (B & C) | (B & D)
|
|
10782
|
+
// Case 1 is a merge.
|
|
10783
|
+
if (compositeFilterIsConjunction(lhs) && compositeFilterIsConjunction(rhs)) {
|
|
10784
|
+
return compositeFilterWithAddedFilters(lhs, rhs.getFilters());
|
|
10785
|
+
}
|
|
10786
|
+
// Case 2,3,4 all have at least one side (lhs or rhs) that is a disjunction. In all three cases
|
|
10787
|
+
// we should take each element of the disjunction and distribute it over the other side, and
|
|
10788
|
+
// return the disjunction of the distribution results.
|
|
10789
|
+
const disjunctionSide = compositeFilterIsDisjunction(lhs) ? lhs : rhs;
|
|
10790
|
+
const otherSide = compositeFilterIsDisjunction(lhs) ? rhs : lhs;
|
|
10791
|
+
const results = disjunctionSide.filters.map(subfilter => applyDistribution(subfilter, otherSide));
|
|
10792
|
+
return CompositeFilter.create(results, "or" /* CompositeOperator.OR */);
|
|
10793
|
+
}
|
|
10794
|
+
function applyDistributionFieldAndCompositeFilters(fieldFilter, compositeFilter) {
|
|
10795
|
+
// There are two cases:
|
|
10796
|
+
// A & (B & C) --> (A & B & C)
|
|
10797
|
+
// A & (B | C) --> (A & B) | (A & C)
|
|
10798
|
+
if (compositeFilterIsConjunction(compositeFilter)) {
|
|
10799
|
+
// Case 1
|
|
10800
|
+
return compositeFilterWithAddedFilters(compositeFilter, fieldFilter.getFilters());
|
|
10801
|
+
}
|
|
10802
|
+
else {
|
|
10803
|
+
// Case 2
|
|
10804
|
+
const newFilters = compositeFilter.filters.map(subfilter => applyDistribution(fieldFilter, subfilter));
|
|
10805
|
+
return CompositeFilter.create(newFilters, "or" /* CompositeOperator.OR */);
|
|
10806
|
+
}
|
|
10807
|
+
}
|
|
10808
|
+
/**
|
|
10809
|
+
* Applies the associativity property to the given filter and returns the resulting filter.
|
|
10810
|
+
*
|
|
10811
|
+
* <ul>
|
|
10812
|
+
* <li>A | (B | C) == (A | B) | C == (A | B | C)
|
|
10813
|
+
* <li>A & (B & C) == (A & B) & C == (A & B & C)
|
|
10814
|
+
* </ul>
|
|
10815
|
+
*
|
|
10816
|
+
* <p>For more info, visit: https://en.wikipedia.org/wiki/Associative_property#Propositional_logic
|
|
10817
|
+
*/
|
|
10818
|
+
function applyAssociation(filter) {
|
|
10819
|
+
hardAssert(filter instanceof FieldFilter || filter instanceof CompositeFilter);
|
|
10820
|
+
if (filter instanceof FieldFilter) {
|
|
10821
|
+
return filter;
|
|
10822
|
+
}
|
|
10823
|
+
const filters = filter.getFilters();
|
|
10824
|
+
// If the composite filter only contains 1 filter, apply associativity to it.
|
|
10825
|
+
if (filters.length === 1) {
|
|
10826
|
+
return applyAssociation(filters[0]);
|
|
10827
|
+
}
|
|
10828
|
+
// Associativity applied to a flat composite filter results is itself.
|
|
10829
|
+
if (compositeFilterIsFlat(filter)) {
|
|
10830
|
+
return filter;
|
|
10831
|
+
}
|
|
10832
|
+
// First apply associativity to all subfilters. This will in turn recursively apply
|
|
10833
|
+
// associativity to all nested composite filters and field filters.
|
|
10834
|
+
const updatedFilters = filters.map(subfilter => applyAssociation(subfilter));
|
|
10835
|
+
// For composite subfilters that perform the same kind of logical operation as `compositeFilter`
|
|
10836
|
+
// take out their filters and add them to `compositeFilter`. For example:
|
|
10837
|
+
// compositeFilter = (A | (B | C | D))
|
|
10838
|
+
// compositeSubfilter = (B | C | D)
|
|
10839
|
+
// Result: (A | B | C | D)
|
|
10840
|
+
// Note that the `compositeSubfilter` has been eliminated, and its filters (B, C, D) have been
|
|
10841
|
+
// added to the top-level "compositeFilter".
|
|
10842
|
+
const newSubfilters = [];
|
|
10843
|
+
updatedFilters.forEach(subfilter => {
|
|
10844
|
+
if (subfilter instanceof FieldFilter) {
|
|
10845
|
+
newSubfilters.push(subfilter);
|
|
10846
|
+
}
|
|
10847
|
+
else if (subfilter instanceof CompositeFilter) {
|
|
10848
|
+
if (subfilter.op === filter.op) {
|
|
10849
|
+
// compositeFilter: (A | (B | C))
|
|
10850
|
+
// compositeSubfilter: (B | C)
|
|
10851
|
+
// Result: (A | B | C)
|
|
10852
|
+
newSubfilters.push(...subfilter.filters);
|
|
10853
|
+
}
|
|
10854
|
+
else {
|
|
10855
|
+
// compositeFilter: (A | (B & C))
|
|
10856
|
+
// compositeSubfilter: (B & C)
|
|
10857
|
+
// Result: (A | (B & C))
|
|
10858
|
+
newSubfilters.push(subfilter);
|
|
10859
|
+
}
|
|
10860
|
+
}
|
|
10861
|
+
});
|
|
10862
|
+
if (newSubfilters.length === 1) {
|
|
10863
|
+
return newSubfilters[0];
|
|
10376
10864
|
}
|
|
10865
|
+
return CompositeFilter.create(newSubfilters, filter.op);
|
|
10377
10866
|
}
|
|
10378
10867
|
|
|
10379
10868
|
/**
|
|
@@ -10420,7 +10909,7 @@ class MemoryIndexManager {
|
|
|
10420
10909
|
}
|
|
10421
10910
|
getIndexType(transaction, target) {
|
|
10422
10911
|
// Field indices are not supported with memory persistence.
|
|
10423
|
-
return PersistencePromise.resolve(0 /* NONE */);
|
|
10912
|
+
return PersistencePromise.resolve(0 /* IndexType.NONE */);
|
|
10424
10913
|
}
|
|
10425
10914
|
getFieldIndexes(transaction, collectionGroup) {
|
|
10426
10915
|
// Field indices are not supported with memory persistence.
|
|
@@ -10643,8 +11132,14 @@ class IndexedDbIndexManager {
|
|
|
10643
11132
|
if (subTargets) {
|
|
10644
11133
|
return subTargets;
|
|
10645
11134
|
}
|
|
10646
|
-
|
|
10647
|
-
|
|
11135
|
+
if (target.filters.length === 0) {
|
|
11136
|
+
subTargets = [target];
|
|
11137
|
+
}
|
|
11138
|
+
else {
|
|
11139
|
+
// There is an implicit AND operation between all the filters stored in the target
|
|
11140
|
+
const dnf = getDnfTerms(CompositeFilter.create(target.filters, "and" /* CompositeOperator.AND */));
|
|
11141
|
+
subTargets = dnf.map(term => newTarget(target.path, target.collectionGroup, target.orderBy, term.getFilters(), target.limit, target.startAt, target.endAt));
|
|
11142
|
+
}
|
|
10648
11143
|
this.targetToDnfSubTargets.set(target, subTargets);
|
|
10649
11144
|
return subTargets;
|
|
10650
11145
|
}
|
|
@@ -10702,18 +11197,29 @@ class IndexedDbIndexManager {
|
|
|
10702
11197
|
});
|
|
10703
11198
|
}
|
|
10704
11199
|
getIndexType(transaction, target) {
|
|
10705
|
-
let indexType = 2 /* FULL */;
|
|
10706
|
-
|
|
11200
|
+
let indexType = 2 /* IndexType.FULL */;
|
|
11201
|
+
const subTargets = this.getSubTargets(target);
|
|
11202
|
+
return PersistencePromise.forEach(subTargets, (target) => {
|
|
10707
11203
|
return this.getFieldIndex(transaction, target).next(index => {
|
|
10708
11204
|
if (!index) {
|
|
10709
|
-
indexType = 0 /* NONE */;
|
|
11205
|
+
indexType = 0 /* IndexType.NONE */;
|
|
10710
11206
|
}
|
|
10711
|
-
else if (indexType !== 0 /* NONE */ &&
|
|
11207
|
+
else if (indexType !== 0 /* IndexType.NONE */ &&
|
|
10712
11208
|
index.fields.length < targetGetSegmentCount(target)) {
|
|
10713
|
-
indexType = 1 /* PARTIAL */;
|
|
11209
|
+
indexType = 1 /* IndexType.PARTIAL */;
|
|
10714
11210
|
}
|
|
10715
11211
|
});
|
|
10716
|
-
}).next(() =>
|
|
11212
|
+
}).next(() => {
|
|
11213
|
+
// OR queries have more than one sub-target (one sub-target per DNF term). We currently consider
|
|
11214
|
+
// OR queries that have a `limit` to have a partial index. For such queries we perform sorting
|
|
11215
|
+
// and apply the limit in memory as a post-processing step.
|
|
11216
|
+
if (targetHasLimit(target) &&
|
|
11217
|
+
subTargets.length > 1 &&
|
|
11218
|
+
indexType === 2 /* IndexType.FULL */) {
|
|
11219
|
+
return 1 /* IndexType.PARTIAL */;
|
|
11220
|
+
}
|
|
11221
|
+
return indexType;
|
|
11222
|
+
});
|
|
10717
11223
|
}
|
|
10718
11224
|
/**
|
|
10719
11225
|
* Returns the byte encoded form of the directional values in the field index.
|
|
@@ -10735,7 +11241,7 @@ class IndexedDbIndexManager {
|
|
|
10735
11241
|
/** Encodes a single value to the ascending index format. */
|
|
10736
11242
|
encodeSingleElement(value) {
|
|
10737
11243
|
const encoder = new IndexByteEncoder();
|
|
10738
|
-
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(value, encoder.forKind(0 /* ASCENDING */));
|
|
11244
|
+
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(value, encoder.forKind(0 /* IndexKind.ASCENDING */));
|
|
10739
11245
|
return encoder.encodedBytes();
|
|
10740
11246
|
}
|
|
10741
11247
|
/**
|
|
@@ -10751,15 +11257,15 @@ class IndexedDbIndexManager {
|
|
|
10751
11257
|
* Encodes the given field values according to the specification in `target`.
|
|
10752
11258
|
* For IN queries, a list of possible values is returned.
|
|
10753
11259
|
*/
|
|
10754
|
-
encodeValues(fieldIndex, target,
|
|
10755
|
-
if (
|
|
11260
|
+
encodeValues(fieldIndex, target, values) {
|
|
11261
|
+
if (values === null) {
|
|
10756
11262
|
return [];
|
|
10757
11263
|
}
|
|
10758
11264
|
let encoders = [];
|
|
10759
11265
|
encoders.push(new IndexByteEncoder());
|
|
10760
|
-
let
|
|
11266
|
+
let valueIdx = 0;
|
|
10761
11267
|
for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
|
|
10762
|
-
const value =
|
|
11268
|
+
const value = values[valueIdx++];
|
|
10763
11269
|
for (const encoder of encoders) {
|
|
10764
11270
|
if (this.isInFilter(target, segment.fieldPath) && isArray(value)) {
|
|
10765
11271
|
encoders = this.expandIndexValues(encoders, segment, value);
|
|
@@ -10810,7 +11316,7 @@ class IndexedDbIndexManager {
|
|
|
10810
11316
|
isInFilter(target, fieldPath) {
|
|
10811
11317
|
return !!target.filters.find(f => f instanceof FieldFilter &&
|
|
10812
11318
|
f.field.isEqual(fieldPath) &&
|
|
10813
|
-
(f.op === "in" /* IN */ || f.op === "not-in" /* NOT_IN */));
|
|
11319
|
+
(f.op === "in" /* Operator.IN */ || f.op === "not-in" /* Operator.NOT_IN */));
|
|
10814
11320
|
}
|
|
10815
11321
|
getFieldIndexes(transaction, collectionGroup) {
|
|
10816
11322
|
const indexes = indexConfigurationStore(transaction);
|
|
@@ -10999,24 +11505,36 @@ class IndexedDbIndexManager {
|
|
|
10999
11505
|
bounds.push(upper);
|
|
11000
11506
|
const ranges = [];
|
|
11001
11507
|
for (let i = 0; i < bounds.length; i += 2) {
|
|
11002
|
-
|
|
11508
|
+
// If we encounter two bounds that will create an unmatchable key range,
|
|
11509
|
+
// then we return an empty set of key ranges.
|
|
11510
|
+
if (this.isRangeMatchable(bounds[i], bounds[i + 1])) {
|
|
11511
|
+
return [];
|
|
11512
|
+
}
|
|
11513
|
+
const lowerBound = [
|
|
11003
11514
|
bounds[i].indexId,
|
|
11004
11515
|
this.uid,
|
|
11005
11516
|
bounds[i].arrayValue,
|
|
11006
11517
|
bounds[i].directionalValue,
|
|
11007
11518
|
EMPTY_VALUE,
|
|
11008
11519
|
[]
|
|
11009
|
-
]
|
|
11520
|
+
];
|
|
11521
|
+
const upperBound = [
|
|
11010
11522
|
bounds[i + 1].indexId,
|
|
11011
11523
|
this.uid,
|
|
11012
11524
|
bounds[i + 1].arrayValue,
|
|
11013
11525
|
bounds[i + 1].directionalValue,
|
|
11014
11526
|
EMPTY_VALUE,
|
|
11015
11527
|
[]
|
|
11016
|
-
]
|
|
11528
|
+
];
|
|
11529
|
+
ranges.push(IDBKeyRange.bound(lowerBound, upperBound));
|
|
11017
11530
|
}
|
|
11018
11531
|
return ranges;
|
|
11019
11532
|
}
|
|
11533
|
+
isRangeMatchable(lowerBound, upperBound) {
|
|
11534
|
+
// If lower bound is greater than the upper bound, then the key
|
|
11535
|
+
// range can never be matched.
|
|
11536
|
+
return indexEntryComparator(lowerBound, upperBound) > 0;
|
|
11537
|
+
}
|
|
11020
11538
|
getMinOffsetFromCollectionGroup(transaction, collectionGroup) {
|
|
11021
11539
|
return this.getFieldIndexes(transaction, collectionGroup).next(getMinOffsetFromFieldIndexes);
|
|
11022
11540
|
}
|
|
@@ -11993,7 +12511,7 @@ class LruScheduler {
|
|
|
11993
12511
|
}
|
|
11994
12512
|
scheduleGC(delay) {
|
|
11995
12513
|
logDebug(LOG_TAG$e, `Garbage collection scheduled in ${delay}ms`);
|
|
11996
|
-
this.gcTask = this.asyncQueue.enqueueAfterDelay("lru_garbage_collection" /* LruGarbageCollection */, delay, async () => {
|
|
12514
|
+
this.gcTask = this.asyncQueue.enqueueAfterDelay("lru_garbage_collection" /* TimerId.LruGarbageCollection */, delay, async () => {
|
|
11997
12515
|
this.gcTask = null;
|
|
11998
12516
|
try {
|
|
11999
12517
|
await this.localStore.collectGarbage(this.garbageCollector);
|
|
@@ -13190,7 +13708,7 @@ class LocalDocumentsView {
|
|
|
13190
13708
|
}
|
|
13191
13709
|
/** Returns a base document that can be used to apply `overlay`. */
|
|
13192
13710
|
getBaseDocument(transaction, key, overlay) {
|
|
13193
|
-
return overlay === null || overlay.mutation.type === 1 /* Patch */
|
|
13711
|
+
return overlay === null || overlay.mutation.type === 1 /* MutationType.Patch */
|
|
13194
13712
|
? this.remoteDocumentCache.getEntry(transaction, key)
|
|
13195
13713
|
: PersistencePromise.resolve(MutableDocument.newInvalidDocument(key));
|
|
13196
13714
|
}
|
|
@@ -14943,7 +15461,7 @@ class IndexedDbPersistence {
|
|
|
14943
15461
|
* extend or acquire the primary lease if the client is eligible.
|
|
14944
15462
|
*/
|
|
14945
15463
|
scheduleClientMetadataAndPrimaryLeaseRefreshes() {
|
|
14946
|
-
this.clientMetadataRefresher = this.queue.enqueueAfterDelay("client_metadata_refresh" /* ClientMetadataRefresh */, CLIENT_METADATA_REFRESH_INTERVAL_MS, () => {
|
|
15464
|
+
this.clientMetadataRefresher = this.queue.enqueueAfterDelay("client_metadata_refresh" /* TimerId.ClientMetadataRefresh */, CLIENT_METADATA_REFRESH_INTERVAL_MS, () => {
|
|
14947
15465
|
return this.updateClientMetadataAndTryBecomePrimary()
|
|
14948
15466
|
.then(() => this.maybeGarbageCollectMultiClientState())
|
|
14949
15467
|
.then(() => this.scheduleClientMetadataAndPrimaryLeaseRefreshes());
|
|
@@ -15953,7 +16471,7 @@ function localStoreAllocateTarget(localStore, target) {
|
|
|
15953
16471
|
return localStoreImpl.targetCache
|
|
15954
16472
|
.allocateTargetId(txn)
|
|
15955
16473
|
.next(targetId => {
|
|
15956
|
-
targetData = new TargetData(target, targetId, 0 /* Listen */, txn.currentSequenceNumber);
|
|
16474
|
+
targetData = new TargetData(target, targetId, 0 /* TargetPurpose.Listen */, txn.currentSequenceNumber);
|
|
15957
16475
|
return localStoreImpl.targetCache
|
|
15958
16476
|
.addTargetData(txn, targetData)
|
|
15959
16477
|
.next(() => targetData);
|
|
@@ -16375,11 +16893,11 @@ class QueryEngine {
|
|
|
16375
16893
|
return this.indexManager
|
|
16376
16894
|
.getIndexType(transaction, target)
|
|
16377
16895
|
.next(indexType => {
|
|
16378
|
-
if (indexType === 0 /* NONE */) {
|
|
16896
|
+
if (indexType === 0 /* IndexType.NONE */) {
|
|
16379
16897
|
// The target cannot be served from any index.
|
|
16380
16898
|
return null;
|
|
16381
16899
|
}
|
|
16382
|
-
if (query.limit !== null && indexType === 1 /* PARTIAL */) {
|
|
16900
|
+
if (query.limit !== null && indexType === 1 /* IndexType.PARTIAL */) {
|
|
16383
16901
|
// We cannot apply a limit for targets that are served using a partial
|
|
16384
16902
|
// index. If a partial index will be used to serve the target, the
|
|
16385
16903
|
// query may return a superset of documents that match the target
|
|
@@ -16387,7 +16905,7 @@ class QueryEngine {
|
|
|
16387
16905
|
// may return the correct set of documents in the wrong order (e.g. if
|
|
16388
16906
|
// the index doesn't include a segment for one of the orderBys).
|
|
16389
16907
|
// Therefore, a limit should not be applied in such cases.
|
|
16390
|
-
query = queryWithLimit(query, null, "F" /* First */);
|
|
16908
|
+
query = queryWithLimit(query, null, "F" /* LimitType.First */);
|
|
16391
16909
|
target = queryToTarget(query);
|
|
16392
16910
|
}
|
|
16393
16911
|
return this.indexManager
|
|
@@ -16408,7 +16926,7 @@ class QueryEngine {
|
|
|
16408
16926
|
// query's filters are included in the result set. The SDK
|
|
16409
16927
|
// can then apply the limit once all local edits are
|
|
16410
16928
|
// incorporated.
|
|
16411
|
-
return this.performQueryUsingIndex(transaction, queryWithLimit(query, null, "F" /* First */));
|
|
16929
|
+
return this.performQueryUsingIndex(transaction, queryWithLimit(query, null, "F" /* LimitType.First */));
|
|
16412
16930
|
}
|
|
16413
16931
|
return this.appendRemainingResults(transaction, previousResults, query, offset);
|
|
16414
16932
|
});
|
|
@@ -16487,7 +17005,7 @@ class QueryEngine {
|
|
|
16487
17005
|
// the boundary of the limit itself did not change and documents from cache
|
|
16488
17006
|
// will continue to be "rejected" by this boundary. Therefore, we can ignore
|
|
16489
17007
|
// any modifications that don't affect the last document.
|
|
16490
|
-
const docAtLimitEdge = query.limitType === "F" /* First */
|
|
17008
|
+
const docAtLimitEdge = query.limitType === "F" /* LimitType.First */
|
|
16491
17009
|
? sortedPreviousResults.last()
|
|
16492
17010
|
: sortedPreviousResults.first();
|
|
16493
17011
|
if (!docAtLimitEdge) {
|
|
@@ -17408,7 +17926,7 @@ function nodePromise(action) {
|
|
|
17408
17926
|
*/
|
|
17409
17927
|
// TODO: Fetch runtime version from grpc-js/package.json instead
|
|
17410
17928
|
// when there's a cleaner way to dynamic require JSON in both Node ESM and CJS
|
|
17411
|
-
const grpcVersion = '1.3
|
|
17929
|
+
const grpcVersion = '1.7.3';
|
|
17412
17930
|
const LOG_TAG$9 = 'Connection';
|
|
17413
17931
|
const X_GOOG_API_CLIENT_VALUE = `gl-node/${process.versions.node} fire/${SDK_VERSION} grpc/${grpcVersion}`;
|
|
17414
17932
|
function createMetadata(databasePath, authToken, appCheckToken, appId) {
|
|
@@ -19856,7 +20374,8 @@ const nested = {
|
|
|
19856
20374
|
Operator: {
|
|
19857
20375
|
values: {
|
|
19858
20376
|
OPERATOR_UNSPECIFIED: 0,
|
|
19859
|
-
AND: 1
|
|
20377
|
+
AND: 1,
|
|
20378
|
+
OR: 2
|
|
19860
20379
|
}
|
|
19861
20380
|
}
|
|
19862
20381
|
}
|
|
@@ -20732,7 +21251,7 @@ class PersistentStream {
|
|
|
20732
21251
|
this.authCredentialsProvider = authCredentialsProvider;
|
|
20733
21252
|
this.appCheckCredentialsProvider = appCheckCredentialsProvider;
|
|
20734
21253
|
this.listener = listener;
|
|
20735
|
-
this.state = 0 /* Initial */;
|
|
21254
|
+
this.state = 0 /* PersistentStreamState.Initial */;
|
|
20736
21255
|
/**
|
|
20737
21256
|
* A close count that's incremented every time the stream is closed; used by
|
|
20738
21257
|
* getCloseGuardedDispatcher() to invalidate callbacks that happen after
|
|
@@ -20752,8 +21271,8 @@ class PersistentStream {
|
|
|
20752
21271
|
* outbound requests.
|
|
20753
21272
|
*/
|
|
20754
21273
|
isStarted() {
|
|
20755
|
-
return (this.state === 1 /* Starting */ ||
|
|
20756
|
-
this.state === 5 /* Backoff */ ||
|
|
21274
|
+
return (this.state === 1 /* PersistentStreamState.Starting */ ||
|
|
21275
|
+
this.state === 5 /* PersistentStreamState.Backoff */ ||
|
|
20757
21276
|
this.isOpen());
|
|
20758
21277
|
}
|
|
20759
21278
|
/**
|
|
@@ -20761,8 +21280,8 @@ class PersistentStream {
|
|
|
20761
21280
|
* called) and the stream is ready for outbound requests.
|
|
20762
21281
|
*/
|
|
20763
21282
|
isOpen() {
|
|
20764
|
-
return (this.state === 2 /* Open */ ||
|
|
20765
|
-
this.state === 3 /* Healthy */);
|
|
21283
|
+
return (this.state === 2 /* PersistentStreamState.Open */ ||
|
|
21284
|
+
this.state === 3 /* PersistentStreamState.Healthy */);
|
|
20766
21285
|
}
|
|
20767
21286
|
/**
|
|
20768
21287
|
* Starts the RPC. Only allowed if isStarted() returns false. The stream is
|
|
@@ -20772,7 +21291,7 @@ class PersistentStream {
|
|
|
20772
21291
|
* When start returns, isStarted() will return true.
|
|
20773
21292
|
*/
|
|
20774
21293
|
start() {
|
|
20775
|
-
if (this.state === 4 /* Error */) {
|
|
21294
|
+
if (this.state === 4 /* PersistentStreamState.Error */) {
|
|
20776
21295
|
this.performBackoff();
|
|
20777
21296
|
return;
|
|
20778
21297
|
}
|
|
@@ -20786,7 +21305,7 @@ class PersistentStream {
|
|
|
20786
21305
|
*/
|
|
20787
21306
|
async stop() {
|
|
20788
21307
|
if (this.isStarted()) {
|
|
20789
|
-
await this.close(0 /* Initial */);
|
|
21308
|
+
await this.close(0 /* PersistentStreamState.Initial */);
|
|
20790
21309
|
}
|
|
20791
21310
|
}
|
|
20792
21311
|
/**
|
|
@@ -20798,7 +21317,7 @@ class PersistentStream {
|
|
|
20798
21317
|
* inhibit backoff if required.
|
|
20799
21318
|
*/
|
|
20800
21319
|
inhibitBackoff() {
|
|
20801
|
-
this.state = 0 /* Initial */;
|
|
21320
|
+
this.state = 0 /* PersistentStreamState.Initial */;
|
|
20802
21321
|
this.backoff.reset();
|
|
20803
21322
|
}
|
|
20804
21323
|
/**
|
|
@@ -20828,7 +21347,7 @@ class PersistentStream {
|
|
|
20828
21347
|
if (this.isOpen()) {
|
|
20829
21348
|
// When timing out an idle stream there's no reason to force the stream into backoff when
|
|
20830
21349
|
// it restarts so set the stream state to Initial instead of Error.
|
|
20831
|
-
return this.close(0 /* Initial */);
|
|
21350
|
+
return this.close(0 /* PersistentStreamState.Initial */);
|
|
20832
21351
|
}
|
|
20833
21352
|
}
|
|
20834
21353
|
/** Marks the stream as active again. */
|
|
@@ -20866,7 +21385,7 @@ class PersistentStream {
|
|
|
20866
21385
|
// Invalidates any stream-related callbacks (e.g. from auth or the
|
|
20867
21386
|
// underlying stream), guaranteeing they won't execute.
|
|
20868
21387
|
this.closeCount++;
|
|
20869
|
-
if (finalState !== 4 /* Error */) {
|
|
21388
|
+
if (finalState !== 4 /* PersistentStreamState.Error */) {
|
|
20870
21389
|
// If this is an intentional close ensure we don't delay our next connection attempt.
|
|
20871
21390
|
this.backoff.reset();
|
|
20872
21391
|
}
|
|
@@ -20878,7 +21397,7 @@ class PersistentStream {
|
|
|
20878
21397
|
}
|
|
20879
21398
|
else if (error &&
|
|
20880
21399
|
error.code === Code.UNAUTHENTICATED &&
|
|
20881
|
-
this.state !== 3 /* Healthy */) {
|
|
21400
|
+
this.state !== 3 /* PersistentStreamState.Healthy */) {
|
|
20882
21401
|
// "unauthenticated" error means the token was rejected. This should rarely
|
|
20883
21402
|
// happen since both Auth and AppCheck ensure a sufficient TTL when we
|
|
20884
21403
|
// request a token. If a user manually resets their system clock this can
|
|
@@ -20906,7 +21425,7 @@ class PersistentStream {
|
|
|
20906
21425
|
*/
|
|
20907
21426
|
tearDown() { }
|
|
20908
21427
|
auth() {
|
|
20909
|
-
this.state = 1 /* Starting */;
|
|
21428
|
+
this.state = 1 /* PersistentStreamState.Starting */;
|
|
20910
21429
|
const dispatchIfNotClosed = this.getCloseGuardedDispatcher(this.closeCount);
|
|
20911
21430
|
// TODO(mikelehen): Just use dispatchIfNotClosed, but see TODO below.
|
|
20912
21431
|
const closeCount = this.closeCount;
|
|
@@ -20936,10 +21455,10 @@ class PersistentStream {
|
|
|
20936
21455
|
this.stream = this.startRpc(authToken, appCheckToken);
|
|
20937
21456
|
this.stream.onOpen(() => {
|
|
20938
21457
|
dispatchIfNotClosed(() => {
|
|
20939
|
-
this.state = 2 /* Open */;
|
|
21458
|
+
this.state = 2 /* PersistentStreamState.Open */;
|
|
20940
21459
|
this.healthCheck = this.queue.enqueueAfterDelay(this.healthTimerId, HEALTHY_TIMEOUT_MS, () => {
|
|
20941
21460
|
if (this.isOpen()) {
|
|
20942
|
-
this.state = 3 /* Healthy */;
|
|
21461
|
+
this.state = 3 /* PersistentStreamState.Healthy */;
|
|
20943
21462
|
}
|
|
20944
21463
|
return Promise.resolve();
|
|
20945
21464
|
});
|
|
@@ -20958,9 +21477,9 @@ class PersistentStream {
|
|
|
20958
21477
|
});
|
|
20959
21478
|
}
|
|
20960
21479
|
performBackoff() {
|
|
20961
|
-
this.state = 5 /* Backoff */;
|
|
21480
|
+
this.state = 5 /* PersistentStreamState.Backoff */;
|
|
20962
21481
|
this.backoff.backoffAndRun(async () => {
|
|
20963
|
-
this.state = 0 /* Initial */;
|
|
21482
|
+
this.state = 0 /* PersistentStreamState.Initial */;
|
|
20964
21483
|
this.start();
|
|
20965
21484
|
});
|
|
20966
21485
|
}
|
|
@@ -20972,7 +21491,7 @@ class PersistentStream {
|
|
|
20972
21491
|
// we never expect this to happen because if we stop a stream ourselves,
|
|
20973
21492
|
// this callback will never be called. To prevent cases where we retry
|
|
20974
21493
|
// without a backoff accidentally, we set the stream to error in all cases.
|
|
20975
|
-
return this.close(4 /* Error */, error);
|
|
21494
|
+
return this.close(4 /* PersistentStreamState.Error */, error);
|
|
20976
21495
|
}
|
|
20977
21496
|
/**
|
|
20978
21497
|
* Returns a "dispatcher" function that dispatches operations onto the
|
|
@@ -21003,7 +21522,7 @@ class PersistentStream {
|
|
|
21003
21522
|
*/
|
|
21004
21523
|
class PersistentListenStream extends PersistentStream {
|
|
21005
21524
|
constructor(queue, connection, authCredentials, appCheckCredentials, serializer, listener) {
|
|
21006
|
-
super(queue, "listen_stream_connection_backoff" /* ListenStreamConnectionBackoff */, "listen_stream_idle" /* ListenStreamIdle */, "health_check_timeout" /* HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21525
|
+
super(queue, "listen_stream_connection_backoff" /* TimerId.ListenStreamConnectionBackoff */, "listen_stream_idle" /* TimerId.ListenStreamIdle */, "health_check_timeout" /* TimerId.HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21007
21526
|
this.serializer = serializer;
|
|
21008
21527
|
}
|
|
21009
21528
|
startRpc(authToken, appCheckToken) {
|
|
@@ -21062,7 +21581,7 @@ class PersistentListenStream extends PersistentStream {
|
|
|
21062
21581
|
*/
|
|
21063
21582
|
class PersistentWriteStream extends PersistentStream {
|
|
21064
21583
|
constructor(queue, connection, authCredentials, appCheckCredentials, serializer, listener) {
|
|
21065
|
-
super(queue, "write_stream_connection_backoff" /* WriteStreamConnectionBackoff */, "write_stream_idle" /* WriteStreamIdle */, "health_check_timeout" /* HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21584
|
+
super(queue, "write_stream_connection_backoff" /* TimerId.WriteStreamConnectionBackoff */, "write_stream_idle" /* TimerId.WriteStreamIdle */, "health_check_timeout" /* TimerId.HealthCheckTimeout */, connection, authCredentials, appCheckCredentials, listener);
|
|
21066
21585
|
this.serializer = serializer;
|
|
21067
21586
|
this.handshakeComplete_ = false;
|
|
21068
21587
|
}
|
|
@@ -21321,7 +21840,7 @@ class OnlineStateTracker {
|
|
|
21321
21840
|
this.asyncQueue = asyncQueue;
|
|
21322
21841
|
this.onlineStateHandler = onlineStateHandler;
|
|
21323
21842
|
/** The current OnlineState. */
|
|
21324
|
-
this.state = "Unknown" /* Unknown */;
|
|
21843
|
+
this.state = "Unknown" /* OnlineState.Unknown */;
|
|
21325
21844
|
/**
|
|
21326
21845
|
* A count of consecutive failures to open the stream. If it reaches the
|
|
21327
21846
|
* maximum defined by MAX_WATCH_STREAM_FAILURES, we'll set the OnlineState to
|
|
@@ -21350,12 +21869,12 @@ class OnlineStateTracker {
|
|
|
21350
21869
|
*/
|
|
21351
21870
|
handleWatchStreamStart() {
|
|
21352
21871
|
if (this.watchStreamFailures === 0) {
|
|
21353
|
-
this.setAndBroadcast("Unknown" /* Unknown */);
|
|
21354
|
-
this.onlineStateTimer = this.asyncQueue.enqueueAfterDelay("online_state_timeout" /* OnlineStateTimeout */, ONLINE_STATE_TIMEOUT_MS, () => {
|
|
21872
|
+
this.setAndBroadcast("Unknown" /* OnlineState.Unknown */);
|
|
21873
|
+
this.onlineStateTimer = this.asyncQueue.enqueueAfterDelay("online_state_timeout" /* TimerId.OnlineStateTimeout */, ONLINE_STATE_TIMEOUT_MS, () => {
|
|
21355
21874
|
this.onlineStateTimer = null;
|
|
21356
21875
|
this.logClientOfflineWarningIfNecessary(`Backend didn't respond within ${ONLINE_STATE_TIMEOUT_MS / 1000} ` +
|
|
21357
21876
|
`seconds.`);
|
|
21358
|
-
this.setAndBroadcast("Offline" /* Offline */);
|
|
21877
|
+
this.setAndBroadcast("Offline" /* OnlineState.Offline */);
|
|
21359
21878
|
// NOTE: handleWatchStreamFailure() will continue to increment
|
|
21360
21879
|
// watchStreamFailures even though we are already marked Offline,
|
|
21361
21880
|
// but this is non-harmful.
|
|
@@ -21370,8 +21889,8 @@ class OnlineStateTracker {
|
|
|
21370
21889
|
* actually transition to the 'Offline' state.
|
|
21371
21890
|
*/
|
|
21372
21891
|
handleWatchStreamFailure(error) {
|
|
21373
|
-
if (this.state === "Online" /* Online */) {
|
|
21374
|
-
this.setAndBroadcast("Unknown" /* Unknown */);
|
|
21892
|
+
if (this.state === "Online" /* OnlineState.Online */) {
|
|
21893
|
+
this.setAndBroadcast("Unknown" /* OnlineState.Unknown */);
|
|
21375
21894
|
}
|
|
21376
21895
|
else {
|
|
21377
21896
|
this.watchStreamFailures++;
|
|
@@ -21379,7 +21898,7 @@ class OnlineStateTracker {
|
|
|
21379
21898
|
this.clearOnlineStateTimer();
|
|
21380
21899
|
this.logClientOfflineWarningIfNecessary(`Connection failed ${MAX_WATCH_STREAM_FAILURES} ` +
|
|
21381
21900
|
`times. Most recent error: ${error.toString()}`);
|
|
21382
|
-
this.setAndBroadcast("Offline" /* Offline */);
|
|
21901
|
+
this.setAndBroadcast("Offline" /* OnlineState.Offline */);
|
|
21383
21902
|
}
|
|
21384
21903
|
}
|
|
21385
21904
|
}
|
|
@@ -21393,7 +21912,7 @@ class OnlineStateTracker {
|
|
|
21393
21912
|
set(newState) {
|
|
21394
21913
|
this.clearOnlineStateTimer();
|
|
21395
21914
|
this.watchStreamFailures = 0;
|
|
21396
|
-
if (newState === "Online" /* Online */) {
|
|
21915
|
+
if (newState === "Online" /* OnlineState.Online */) {
|
|
21397
21916
|
// We've connected to watch at least once. Don't warn the developer
|
|
21398
21917
|
// about being offline going forward.
|
|
21399
21918
|
this.shouldWarnClientIsOffline = false;
|
|
@@ -21520,7 +22039,7 @@ function newRemoteStore(localStore, datastore, asyncQueue, onlineStateHandler, c
|
|
|
21520
22039
|
/** Re-enables the network. Idempotent. */
|
|
21521
22040
|
function remoteStoreEnableNetwork(remoteStore) {
|
|
21522
22041
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21523
|
-
remoteStoreImpl.offlineCauses.delete(0 /* UserDisabled */);
|
|
22042
|
+
remoteStoreImpl.offlineCauses.delete(0 /* OfflineCause.UserDisabled */);
|
|
21524
22043
|
return enableNetworkInternal(remoteStoreImpl);
|
|
21525
22044
|
}
|
|
21526
22045
|
async function enableNetworkInternal(remoteStoreImpl) {
|
|
@@ -21536,10 +22055,10 @@ async function enableNetworkInternal(remoteStoreImpl) {
|
|
|
21536
22055
|
*/
|
|
21537
22056
|
async function remoteStoreDisableNetwork(remoteStore) {
|
|
21538
22057
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21539
|
-
remoteStoreImpl.offlineCauses.add(0 /* UserDisabled */);
|
|
22058
|
+
remoteStoreImpl.offlineCauses.add(0 /* OfflineCause.UserDisabled */);
|
|
21540
22059
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21541
22060
|
// Set the OnlineState to Offline so get()s return from cache, etc.
|
|
21542
|
-
remoteStoreImpl.onlineStateTracker.set("Offline" /* Offline */);
|
|
22061
|
+
remoteStoreImpl.onlineStateTracker.set("Offline" /* OnlineState.Offline */);
|
|
21543
22062
|
}
|
|
21544
22063
|
async function disableNetworkInternal(remoteStoreImpl) {
|
|
21545
22064
|
for (const networkStatusHandler of remoteStoreImpl.onNetworkStatusChange) {
|
|
@@ -21549,12 +22068,12 @@ async function disableNetworkInternal(remoteStoreImpl) {
|
|
|
21549
22068
|
async function remoteStoreShutdown(remoteStore) {
|
|
21550
22069
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21551
22070
|
logDebug(LOG_TAG$5, 'RemoteStore shutting down.');
|
|
21552
|
-
remoteStoreImpl.offlineCauses.add(5 /* Shutdown */);
|
|
22071
|
+
remoteStoreImpl.offlineCauses.add(5 /* OfflineCause.Shutdown */);
|
|
21553
22072
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21554
22073
|
remoteStoreImpl.connectivityMonitor.shutdown();
|
|
21555
22074
|
// Set the OnlineState to Unknown (rather than Offline) to avoid potentially
|
|
21556
22075
|
// triggering spurious listener events with cached data, etc.
|
|
21557
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22076
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21558
22077
|
}
|
|
21559
22078
|
/**
|
|
21560
22079
|
* Starts new listen for the given target. Uses resume token if provided. It
|
|
@@ -21594,7 +22113,7 @@ function remoteStoreUnlisten(remoteStore, targetId) {
|
|
|
21594
22113
|
// Revert to OnlineState.Unknown if the watch stream is not open and we
|
|
21595
22114
|
// have no listeners, since without any listens to send we cannot
|
|
21596
22115
|
// confirm if the stream is healthy and upgrade to OnlineState.Online.
|
|
21597
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22116
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21598
22117
|
}
|
|
21599
22118
|
}
|
|
21600
22119
|
}
|
|
@@ -21655,14 +22174,14 @@ async function onWatchStreamClose(remoteStoreImpl, error) {
|
|
|
21655
22174
|
// No need to restart watch stream because there are no active targets.
|
|
21656
22175
|
// The online state is set to unknown because there is no active attempt
|
|
21657
22176
|
// at establishing a connection
|
|
21658
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22177
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21659
22178
|
}
|
|
21660
22179
|
}
|
|
21661
22180
|
async function onWatchStreamChange(remoteStoreImpl, watchChange, snapshotVersion) {
|
|
21662
22181
|
// Mark the client as online since we got a message from the server
|
|
21663
|
-
remoteStoreImpl.onlineStateTracker.set("Online" /* Online */);
|
|
22182
|
+
remoteStoreImpl.onlineStateTracker.set("Online" /* OnlineState.Online */);
|
|
21664
22183
|
if (watchChange instanceof WatchTargetChange &&
|
|
21665
|
-
watchChange.state === 2 /* Removed */ &&
|
|
22184
|
+
watchChange.state === 2 /* WatchTargetChangeState.Removed */ &&
|
|
21666
22185
|
watchChange.cause) {
|
|
21667
22186
|
// There was an error on a target, don't wait for a consistent snapshot
|
|
21668
22187
|
// to raise events
|
|
@@ -21710,10 +22229,10 @@ async function onWatchStreamChange(remoteStoreImpl, watchChange, snapshotVersion
|
|
|
21710
22229
|
*/
|
|
21711
22230
|
async function disableNetworkUntilRecovery(remoteStoreImpl, e, op) {
|
|
21712
22231
|
if (isIndexedDbTransactionError(e)) {
|
|
21713
|
-
remoteStoreImpl.offlineCauses.add(1 /* IndexedDbFailed */);
|
|
22232
|
+
remoteStoreImpl.offlineCauses.add(1 /* OfflineCause.IndexedDbFailed */);
|
|
21714
22233
|
// Disable network and raise offline snapshots
|
|
21715
22234
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21716
|
-
remoteStoreImpl.onlineStateTracker.set("Offline" /* Offline */);
|
|
22235
|
+
remoteStoreImpl.onlineStateTracker.set("Offline" /* OnlineState.Offline */);
|
|
21717
22236
|
if (!op) {
|
|
21718
22237
|
// Use a simple read operation to determine if IndexedDB recovered.
|
|
21719
22238
|
// Ideally, we would expose a health check directly on SimpleDb, but
|
|
@@ -21724,7 +22243,7 @@ async function disableNetworkUntilRecovery(remoteStoreImpl, e, op) {
|
|
|
21724
22243
|
remoteStoreImpl.asyncQueue.enqueueRetryable(async () => {
|
|
21725
22244
|
logDebug(LOG_TAG$5, 'Retrying IndexedDB access');
|
|
21726
22245
|
await op();
|
|
21727
|
-
remoteStoreImpl.offlineCauses.delete(1 /* IndexedDbFailed */);
|
|
22246
|
+
remoteStoreImpl.offlineCauses.delete(1 /* OfflineCause.IndexedDbFailed */);
|
|
21728
22247
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21729
22248
|
});
|
|
21730
22249
|
}
|
|
@@ -21775,7 +22294,7 @@ function raiseWatchSnapshot(remoteStoreImpl, snapshotVersion) {
|
|
|
21775
22294
|
// mismatch, but don't actually retain that in listenTargets. This ensures
|
|
21776
22295
|
// that we flag the first re-listen this way without impacting future
|
|
21777
22296
|
// listens of this target (that might happen e.g. on reconnect).
|
|
21778
|
-
const requestTargetData = new TargetData(targetData.target, targetId, 1 /* ExistenceFilterMismatch */, targetData.sequenceNumber);
|
|
22297
|
+
const requestTargetData = new TargetData(targetData.target, targetId, 1 /* TargetPurpose.ExistenceFilterMismatch */, targetData.sequenceNumber);
|
|
21779
22298
|
sendWatchRequest(remoteStoreImpl, requestTargetData);
|
|
21780
22299
|
});
|
|
21781
22300
|
return remoteStoreImpl.remoteSyncer.applyRemoteEvent(remoteEvent);
|
|
@@ -21906,10 +22425,10 @@ async function handleWriteError(remoteStoreImpl, error) {
|
|
|
21906
22425
|
}
|
|
21907
22426
|
async function restartNetwork(remoteStore) {
|
|
21908
22427
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21909
|
-
remoteStoreImpl.offlineCauses.add(4 /* ConnectivityChange */);
|
|
22428
|
+
remoteStoreImpl.offlineCauses.add(4 /* OfflineCause.ConnectivityChange */);
|
|
21910
22429
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21911
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
21912
|
-
remoteStoreImpl.offlineCauses.delete(4 /* ConnectivityChange */);
|
|
22430
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
22431
|
+
remoteStoreImpl.offlineCauses.delete(4 /* OfflineCause.ConnectivityChange */);
|
|
21913
22432
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21914
22433
|
}
|
|
21915
22434
|
async function remoteStoreHandleCredentialChange(remoteStore, user) {
|
|
@@ -21920,14 +22439,14 @@ async function remoteStoreHandleCredentialChange(remoteStore, user) {
|
|
|
21920
22439
|
// Tear down and re-create our network streams. This will ensure we get a
|
|
21921
22440
|
// fresh auth token for the new user and re-fill the write pipeline with
|
|
21922
22441
|
// new mutations from the LocalStore (since mutations are per-user).
|
|
21923
|
-
remoteStoreImpl.offlineCauses.add(3 /* CredentialChange */);
|
|
22442
|
+
remoteStoreImpl.offlineCauses.add(3 /* OfflineCause.CredentialChange */);
|
|
21924
22443
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21925
22444
|
if (usesNetwork) {
|
|
21926
22445
|
// Don't set the network status to Unknown if we are offline.
|
|
21927
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22446
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21928
22447
|
}
|
|
21929
22448
|
await remoteStoreImpl.remoteSyncer.handleCredentialChange(user);
|
|
21930
|
-
remoteStoreImpl.offlineCauses.delete(3 /* CredentialChange */);
|
|
22449
|
+
remoteStoreImpl.offlineCauses.delete(3 /* OfflineCause.CredentialChange */);
|
|
21931
22450
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21932
22451
|
}
|
|
21933
22452
|
/**
|
|
@@ -21936,13 +22455,13 @@ async function remoteStoreHandleCredentialChange(remoteStore, user) {
|
|
|
21936
22455
|
async function remoteStoreApplyPrimaryState(remoteStore, isPrimary) {
|
|
21937
22456
|
const remoteStoreImpl = debugCast(remoteStore);
|
|
21938
22457
|
if (isPrimary) {
|
|
21939
|
-
remoteStoreImpl.offlineCauses.delete(2 /* IsSecondary */);
|
|
22458
|
+
remoteStoreImpl.offlineCauses.delete(2 /* OfflineCause.IsSecondary */);
|
|
21940
22459
|
await enableNetworkInternal(remoteStoreImpl);
|
|
21941
22460
|
}
|
|
21942
22461
|
else if (!isPrimary) {
|
|
21943
|
-
remoteStoreImpl.offlineCauses.add(2 /* IsSecondary */);
|
|
22462
|
+
remoteStoreImpl.offlineCauses.add(2 /* OfflineCause.IsSecondary */);
|
|
21944
22463
|
await disableNetworkInternal(remoteStoreImpl);
|
|
21945
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22464
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21946
22465
|
}
|
|
21947
22466
|
}
|
|
21948
22467
|
/**
|
|
@@ -21968,7 +22487,7 @@ function ensureWatchStream(remoteStoreImpl) {
|
|
|
21968
22487
|
startWatchStream(remoteStoreImpl);
|
|
21969
22488
|
}
|
|
21970
22489
|
else {
|
|
21971
|
-
remoteStoreImpl.onlineStateTracker.set("Unknown" /* Unknown */);
|
|
22490
|
+
remoteStoreImpl.onlineStateTracker.set("Unknown" /* OnlineState.Unknown */);
|
|
21972
22491
|
}
|
|
21973
22492
|
}
|
|
21974
22493
|
else {
|
|
@@ -22299,46 +22818,46 @@ class DocumentChangeSet {
|
|
|
22299
22818
|
return;
|
|
22300
22819
|
}
|
|
22301
22820
|
// Merge the new change with the existing change.
|
|
22302
|
-
if (change.type !== 0 /* Added */ &&
|
|
22303
|
-
oldChange.type === 3 /* Metadata */) {
|
|
22821
|
+
if (change.type !== 0 /* ChangeType.Added */ &&
|
|
22822
|
+
oldChange.type === 3 /* ChangeType.Metadata */) {
|
|
22304
22823
|
this.changeMap = this.changeMap.insert(key, change);
|
|
22305
22824
|
}
|
|
22306
|
-
else if (change.type === 3 /* Metadata */ &&
|
|
22307
|
-
oldChange.type !== 1 /* Removed */) {
|
|
22825
|
+
else if (change.type === 3 /* ChangeType.Metadata */ &&
|
|
22826
|
+
oldChange.type !== 1 /* ChangeType.Removed */) {
|
|
22308
22827
|
this.changeMap = this.changeMap.insert(key, {
|
|
22309
22828
|
type: oldChange.type,
|
|
22310
22829
|
doc: change.doc
|
|
22311
22830
|
});
|
|
22312
22831
|
}
|
|
22313
|
-
else if (change.type === 2 /* Modified */ &&
|
|
22314
|
-
oldChange.type === 2 /* Modified */) {
|
|
22832
|
+
else if (change.type === 2 /* ChangeType.Modified */ &&
|
|
22833
|
+
oldChange.type === 2 /* ChangeType.Modified */) {
|
|
22315
22834
|
this.changeMap = this.changeMap.insert(key, {
|
|
22316
|
-
type: 2 /* Modified */,
|
|
22835
|
+
type: 2 /* ChangeType.Modified */,
|
|
22317
22836
|
doc: change.doc
|
|
22318
22837
|
});
|
|
22319
22838
|
}
|
|
22320
|
-
else if (change.type === 2 /* Modified */ &&
|
|
22321
|
-
oldChange.type === 0 /* Added */) {
|
|
22839
|
+
else if (change.type === 2 /* ChangeType.Modified */ &&
|
|
22840
|
+
oldChange.type === 0 /* ChangeType.Added */) {
|
|
22322
22841
|
this.changeMap = this.changeMap.insert(key, {
|
|
22323
|
-
type: 0 /* Added */,
|
|
22842
|
+
type: 0 /* ChangeType.Added */,
|
|
22324
22843
|
doc: change.doc
|
|
22325
22844
|
});
|
|
22326
22845
|
}
|
|
22327
|
-
else if (change.type === 1 /* Removed */ &&
|
|
22328
|
-
oldChange.type === 0 /* Added */) {
|
|
22846
|
+
else if (change.type === 1 /* ChangeType.Removed */ &&
|
|
22847
|
+
oldChange.type === 0 /* ChangeType.Added */) {
|
|
22329
22848
|
this.changeMap = this.changeMap.remove(key);
|
|
22330
22849
|
}
|
|
22331
|
-
else if (change.type === 1 /* Removed */ &&
|
|
22332
|
-
oldChange.type === 2 /* Modified */) {
|
|
22850
|
+
else if (change.type === 1 /* ChangeType.Removed */ &&
|
|
22851
|
+
oldChange.type === 2 /* ChangeType.Modified */) {
|
|
22333
22852
|
this.changeMap = this.changeMap.insert(key, {
|
|
22334
|
-
type: 1 /* Removed */,
|
|
22853
|
+
type: 1 /* ChangeType.Removed */,
|
|
22335
22854
|
doc: oldChange.doc
|
|
22336
22855
|
});
|
|
22337
22856
|
}
|
|
22338
|
-
else if (change.type === 0 /* Added */ &&
|
|
22339
|
-
oldChange.type === 1 /* Removed */) {
|
|
22857
|
+
else if (change.type === 0 /* ChangeType.Added */ &&
|
|
22858
|
+
oldChange.type === 1 /* ChangeType.Removed */) {
|
|
22340
22859
|
this.changeMap = this.changeMap.insert(key, {
|
|
22341
|
-
type: 2 /* Modified */,
|
|
22860
|
+
type: 2 /* ChangeType.Modified */,
|
|
22342
22861
|
doc: change.doc
|
|
22343
22862
|
});
|
|
22344
22863
|
}
|
|
@@ -22377,7 +22896,7 @@ class ViewSnapshot {
|
|
|
22377
22896
|
static fromInitialDocuments(query, documents, mutatedKeys, fromCache, hasCachedResults) {
|
|
22378
22897
|
const changes = [];
|
|
22379
22898
|
documents.forEach(doc => {
|
|
22380
|
-
changes.push({ type: 0 /* Added */, doc });
|
|
22899
|
+
changes.push({ type: 0 /* ChangeType.Added */, doc });
|
|
22381
22900
|
});
|
|
22382
22901
|
return new ViewSnapshot(query, documents, DocumentSet.emptySet(documents), changes, mutatedKeys, fromCache,
|
|
22383
22902
|
/* syncStateChanged= */ true,
|
|
@@ -22443,7 +22962,7 @@ function newEventManager() {
|
|
|
22443
22962
|
class EventManagerImpl {
|
|
22444
22963
|
constructor() {
|
|
22445
22964
|
this.queries = new ObjectMap(q => canonifyQuery(q), queryEquals);
|
|
22446
|
-
this.onlineState = "Unknown" /* Unknown */;
|
|
22965
|
+
this.onlineState = "Unknown" /* OnlineState.Unknown */;
|
|
22447
22966
|
this.snapshotsInSyncListeners = new Set();
|
|
22448
22967
|
}
|
|
22449
22968
|
}
|
|
@@ -22574,7 +23093,7 @@ class QueryListener {
|
|
|
22574
23093
|
*/
|
|
22575
23094
|
this.raisedInitialEvent = false;
|
|
22576
23095
|
this.snap = null;
|
|
22577
|
-
this.onlineState = "Unknown" /* Unknown */;
|
|
23096
|
+
this.onlineState = "Unknown" /* OnlineState.Unknown */;
|
|
22578
23097
|
this.options = options || {};
|
|
22579
23098
|
}
|
|
22580
23099
|
/**
|
|
@@ -22588,7 +23107,7 @@ class QueryListener {
|
|
|
22588
23107
|
// Remove the metadata only changes.
|
|
22589
23108
|
const docChanges = [];
|
|
22590
23109
|
for (const docChange of snap.docChanges) {
|
|
22591
|
-
if (docChange.type !== 3 /* Metadata */) {
|
|
23110
|
+
if (docChange.type !== 3 /* ChangeType.Metadata */) {
|
|
22592
23111
|
docChanges.push(docChange);
|
|
22593
23112
|
}
|
|
22594
23113
|
}
|
|
@@ -22631,7 +23150,7 @@ class QueryListener {
|
|
|
22631
23150
|
}
|
|
22632
23151
|
// NOTE: We consider OnlineState.Unknown as online (it should become Offline
|
|
22633
23152
|
// or Online if we wait long enough).
|
|
22634
|
-
const maybeOnline = onlineState !== "Offline" /* Offline */;
|
|
23153
|
+
const maybeOnline = onlineState !== "Offline" /* OnlineState.Offline */;
|
|
22635
23154
|
// Don't raise the event if we're online, aren't synced yet (checked
|
|
22636
23155
|
// above) and are waiting for a sync.
|
|
22637
23156
|
if (this.options.waitForSyncWhenOnline && maybeOnline) {
|
|
@@ -22641,7 +23160,7 @@ class QueryListener {
|
|
|
22641
23160
|
// or we are offline.
|
|
22642
23161
|
return (!snap.docs.isEmpty() ||
|
|
22643
23162
|
snap.hasCachedResults ||
|
|
22644
|
-
onlineState === "Offline" /* Offline */);
|
|
23163
|
+
onlineState === "Offline" /* OnlineState.Offline */);
|
|
22645
23164
|
}
|
|
22646
23165
|
shouldRaiseEvent(snap) {
|
|
22647
23166
|
// We don't need to handle includeDocumentMetadataChanges here because
|
|
@@ -22700,10 +23219,10 @@ class LocalViewChanges {
|
|
|
22700
23219
|
let removedKeys = documentKeySet();
|
|
22701
23220
|
for (const docChange of viewSnapshot.docChanges) {
|
|
22702
23221
|
switch (docChange.type) {
|
|
22703
|
-
case 0 /* Added */:
|
|
23222
|
+
case 0 /* ChangeType.Added */:
|
|
22704
23223
|
addedKeys = addedKeys.add(docChange.doc.key);
|
|
22705
23224
|
break;
|
|
22706
|
-
case 1 /* Removed */:
|
|
23225
|
+
case 1 /* ChangeType.Removed */:
|
|
22707
23226
|
removedKeys = removedKeys.add(docChange.doc.key);
|
|
22708
23227
|
break;
|
|
22709
23228
|
// do nothing
|
|
@@ -22951,11 +23470,11 @@ class View {
|
|
|
22951
23470
|
//
|
|
22952
23471
|
// Note that this should never get used in a refill (when previousChanges is
|
|
22953
23472
|
// set), because there will only be adds -- no deletes or updates.
|
|
22954
|
-
const lastDocInLimit = this.query.limitType === "F" /* First */ &&
|
|
23473
|
+
const lastDocInLimit = this.query.limitType === "F" /* LimitType.First */ &&
|
|
22955
23474
|
oldDocumentSet.size === this.query.limit
|
|
22956
23475
|
? oldDocumentSet.last()
|
|
22957
23476
|
: null;
|
|
22958
|
-
const firstDocInLimit = this.query.limitType === "L" /* Last */ &&
|
|
23477
|
+
const firstDocInLimit = this.query.limitType === "L" /* LimitType.Last */ &&
|
|
22959
23478
|
oldDocumentSet.size === this.query.limit
|
|
22960
23479
|
? oldDocumentSet.first()
|
|
22961
23480
|
: null;
|
|
@@ -22978,7 +23497,7 @@ class View {
|
|
|
22978
23497
|
if (!docsEqual) {
|
|
22979
23498
|
if (!this.shouldWaitForSyncedDocument(oldDoc, newDoc)) {
|
|
22980
23499
|
changeSet.track({
|
|
22981
|
-
type: 2 /* Modified */,
|
|
23500
|
+
type: 2 /* ChangeType.Modified */,
|
|
22982
23501
|
doc: newDoc
|
|
22983
23502
|
});
|
|
22984
23503
|
changeApplied = true;
|
|
@@ -22994,16 +23513,16 @@ class View {
|
|
|
22994
23513
|
}
|
|
22995
23514
|
}
|
|
22996
23515
|
else if (oldDocHadPendingMutations !== newDocHasPendingMutations) {
|
|
22997
|
-
changeSet.track({ type: 3 /* Metadata */, doc: newDoc });
|
|
23516
|
+
changeSet.track({ type: 3 /* ChangeType.Metadata */, doc: newDoc });
|
|
22998
23517
|
changeApplied = true;
|
|
22999
23518
|
}
|
|
23000
23519
|
}
|
|
23001
23520
|
else if (!oldDoc && newDoc) {
|
|
23002
|
-
changeSet.track({ type: 0 /* Added */, doc: newDoc });
|
|
23521
|
+
changeSet.track({ type: 0 /* ChangeType.Added */, doc: newDoc });
|
|
23003
23522
|
changeApplied = true;
|
|
23004
23523
|
}
|
|
23005
23524
|
else if (oldDoc && !newDoc) {
|
|
23006
|
-
changeSet.track({ type: 1 /* Removed */, doc: oldDoc });
|
|
23525
|
+
changeSet.track({ type: 1 /* ChangeType.Removed */, doc: oldDoc });
|
|
23007
23526
|
changeApplied = true;
|
|
23008
23527
|
if (lastDocInLimit || firstDocInLimit) {
|
|
23009
23528
|
// A doc was removed from a full limit query. We'll need to
|
|
@@ -23031,12 +23550,12 @@ class View {
|
|
|
23031
23550
|
// Drop documents out to meet limit/limitToLast requirement.
|
|
23032
23551
|
if (this.query.limit !== null) {
|
|
23033
23552
|
while (newDocumentSet.size > this.query.limit) {
|
|
23034
|
-
const oldDoc = this.query.limitType === "F" /* First */
|
|
23553
|
+
const oldDoc = this.query.limitType === "F" /* LimitType.First */
|
|
23035
23554
|
? newDocumentSet.last()
|
|
23036
23555
|
: newDocumentSet.first();
|
|
23037
23556
|
newDocumentSet = newDocumentSet.delete(oldDoc.key);
|
|
23038
23557
|
newMutatedKeys = newMutatedKeys.delete(oldDoc.key);
|
|
23039
|
-
changeSet.track({ type: 1 /* Removed */, doc: oldDoc });
|
|
23558
|
+
changeSet.track({ type: 1 /* ChangeType.Removed */, doc: oldDoc });
|
|
23040
23559
|
}
|
|
23041
23560
|
}
|
|
23042
23561
|
return {
|
|
@@ -23084,7 +23603,7 @@ class View {
|
|
|
23084
23603
|
? this.updateLimboDocuments()
|
|
23085
23604
|
: [];
|
|
23086
23605
|
const synced = this.limboDocuments.size === 0 && this.current;
|
|
23087
|
-
const newSyncState = synced ? 1 /* Synced */ : 0 /* Local */;
|
|
23606
|
+
const newSyncState = synced ? 1 /* SyncState.Synced */ : 0 /* SyncState.Local */;
|
|
23088
23607
|
const syncStateChanged = newSyncState !== this.syncState;
|
|
23089
23608
|
this.syncState = newSyncState;
|
|
23090
23609
|
if (changes.length === 0 && !syncStateChanged) {
|
|
@@ -23092,7 +23611,7 @@ class View {
|
|
|
23092
23611
|
return { limboChanges };
|
|
23093
23612
|
}
|
|
23094
23613
|
else {
|
|
23095
|
-
const snap = new ViewSnapshot(this.query, docChanges.documentSet, oldDocs, changes, docChanges.mutatedKeys, newSyncState === 0 /* Local */, syncStateChanged,
|
|
23614
|
+
const snap = new ViewSnapshot(this.query, docChanges.documentSet, oldDocs, changes, docChanges.mutatedKeys, newSyncState === 0 /* SyncState.Local */, syncStateChanged,
|
|
23096
23615
|
/* excludesMetadataChanges= */ false, targetChange
|
|
23097
23616
|
? targetChange.resumeToken.approximateByteSize() > 0
|
|
23098
23617
|
: false);
|
|
@@ -23107,7 +23626,7 @@ class View {
|
|
|
23107
23626
|
* ViewChange if the view's syncState changes as a result.
|
|
23108
23627
|
*/
|
|
23109
23628
|
applyOnlineStateChange(onlineState) {
|
|
23110
|
-
if (this.current && onlineState === "Offline" /* Offline */) {
|
|
23629
|
+
if (this.current && onlineState === "Offline" /* OnlineState.Offline */) {
|
|
23111
23630
|
// If we're offline, set `current` to false and then call applyChanges()
|
|
23112
23631
|
// to refresh our syncState and generate a ViewChange as appropriate. We
|
|
23113
23632
|
// are guaranteed to get a new TargetChange that sets `current` back to
|
|
@@ -23222,22 +23741,22 @@ class View {
|
|
|
23222
23741
|
*/
|
|
23223
23742
|
// PORTING NOTE: Multi-tab only.
|
|
23224
23743
|
computeInitialSnapshot() {
|
|
23225
|
-
return ViewSnapshot.fromInitialDocuments(this.query, this.documentSet, this.mutatedKeys, this.syncState === 0 /* Local */, this.hasCachedResults);
|
|
23744
|
+
return ViewSnapshot.fromInitialDocuments(this.query, this.documentSet, this.mutatedKeys, this.syncState === 0 /* SyncState.Local */, this.hasCachedResults);
|
|
23226
23745
|
}
|
|
23227
23746
|
}
|
|
23228
23747
|
function compareChangeType(c1, c2) {
|
|
23229
23748
|
const order = (change) => {
|
|
23230
23749
|
switch (change) {
|
|
23231
|
-
case 0 /* Added */:
|
|
23750
|
+
case 0 /* ChangeType.Added */:
|
|
23232
23751
|
return 1;
|
|
23233
|
-
case 2 /* Modified */:
|
|
23752
|
+
case 2 /* ChangeType.Modified */:
|
|
23234
23753
|
return 2;
|
|
23235
|
-
case 3 /* Metadata */:
|
|
23754
|
+
case 3 /* ChangeType.Metadata */:
|
|
23236
23755
|
// A metadata change is converted to a modified change at the public
|
|
23237
23756
|
// api layer. Since we sort by document key and then change type,
|
|
23238
23757
|
// metadata and modified changes must be sorted equivalently.
|
|
23239
23758
|
return 2;
|
|
23240
|
-
case 1 /* Removed */:
|
|
23759
|
+
case 1 /* ChangeType.Removed */:
|
|
23241
23760
|
return 0;
|
|
23242
23761
|
default:
|
|
23243
23762
|
return fail();
|
|
@@ -23355,7 +23874,7 @@ class SyncEngineImpl {
|
|
|
23355
23874
|
/** Stores user callbacks waiting for all pending writes to be acknowledged. */
|
|
23356
23875
|
this.pendingWritesCallbacks = new Map();
|
|
23357
23876
|
this.limboTargetIdGenerator = TargetIdGenerator.forSyncEngine();
|
|
23358
|
-
this.onlineState = "Unknown" /* Unknown */;
|
|
23877
|
+
this.onlineState = "Unknown" /* OnlineState.Unknown */;
|
|
23359
23878
|
// The primary state is set to `true` or `false` immediately after Firestore
|
|
23360
23879
|
// startup. In the interim, a client should only be considered primary if
|
|
23361
23880
|
// `isPrimary` is true.
|
|
@@ -23419,7 +23938,7 @@ async function initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId,
|
|
|
23419
23938
|
/* usePreviousResults= */ true);
|
|
23420
23939
|
const view = new View(query, queryResult.remoteKeys);
|
|
23421
23940
|
const viewDocChanges = view.computeDocChanges(queryResult.documents);
|
|
23422
|
-
const synthesizedTargetChange = TargetChange.createSynthesizedTargetChangeForCurrentChange(targetId, current && syncEngineImpl.onlineState !== "Offline" /* Offline */, resumeToken);
|
|
23941
|
+
const synthesizedTargetChange = TargetChange.createSynthesizedTargetChangeForCurrentChange(targetId, current && syncEngineImpl.onlineState !== "Offline" /* OnlineState.Offline */, resumeToken);
|
|
23423
23942
|
const viewChange = view.applyChanges(viewDocChanges,
|
|
23424
23943
|
/* updateLimboDocuments= */ syncEngineImpl.isPrimaryClient, synthesizedTargetChange);
|
|
23425
23944
|
updateTrackedLimbos(syncEngineImpl, targetId, viewChange.limboChanges);
|
|
@@ -23545,9 +24064,9 @@ function syncEngineApplyOnlineStateChange(syncEngine, onlineState, source) {
|
|
|
23545
24064
|
// tab remains online) and only apply the primary tab's online state from
|
|
23546
24065
|
// SharedClientState.
|
|
23547
24066
|
if ((syncEngineImpl.isPrimaryClient &&
|
|
23548
|
-
source === 0 /* RemoteStore */) ||
|
|
24067
|
+
source === 0 /* OnlineStateSource.RemoteStore */) ||
|
|
23549
24068
|
(!syncEngineImpl.isPrimaryClient &&
|
|
23550
|
-
source === 1 /* SharedClientState */)) {
|
|
24069
|
+
source === 1 /* OnlineStateSource.SharedClientState */)) {
|
|
23551
24070
|
const newViewSnapshots = [];
|
|
23552
24071
|
syncEngineImpl.queryViewsByQuery.forEach((query, queryView) => {
|
|
23553
24072
|
const viewChange = queryView.view.applyOnlineStateChange(onlineState);
|
|
@@ -23815,7 +24334,7 @@ function pumpEnqueuedLimboResolutions(syncEngineImpl) {
|
|
|
23815
24334
|
syncEngineImpl.activeLimboResolutionsByTarget.set(limboTargetId, new LimboResolution(key));
|
|
23816
24335
|
syncEngineImpl.activeLimboTargetsByKey =
|
|
23817
24336
|
syncEngineImpl.activeLimboTargetsByKey.insert(key, limboTargetId);
|
|
23818
|
-
remoteStoreListen(syncEngineImpl.remoteStore, new TargetData(queryToTarget(newQueryForPath(key.path)), limboTargetId, 2 /* LimboResolution */, ListenSequence.INVALID));
|
|
24337
|
+
remoteStoreListen(syncEngineImpl.remoteStore, new TargetData(queryToTarget(newQueryForPath(key.path)), limboTargetId, 2 /* TargetPurpose.LimboResolution */, ListenSequence.INVALID));
|
|
23819
24338
|
}
|
|
23820
24339
|
}
|
|
23821
24340
|
async function syncEngineEmitNewSnapsAndNotifyLocalStore(syncEngine, changes, remoteEvent) {
|
|
@@ -24068,7 +24587,7 @@ async function synchronizeQueryViewsAndRaiseSnapshots(syncEngine, targets, trans
|
|
|
24068
24587
|
*/
|
|
24069
24588
|
// PORTING NOTE: Multi-Tab only.
|
|
24070
24589
|
function synthesizeTargetToQuery(target) {
|
|
24071
|
-
return newQuery(target.path, target.collectionGroup, target.orderBy, target.filters, target.limit, "F" /* First */, target.startAt, target.endAt);
|
|
24590
|
+
return newQuery(target.path, target.collectionGroup, target.orderBy, target.filters, target.limit, "F" /* LimitType.First */, target.startAt, target.endAt);
|
|
24072
24591
|
}
|
|
24073
24592
|
/** Returns the IDs of the clients that are currently active. */
|
|
24074
24593
|
// PORTING NOTE: Multi-Tab only.
|
|
@@ -24399,7 +24918,7 @@ class OnlineComponentProvider {
|
|
|
24399
24918
|
this.eventManager = this.createEventManager(cfg);
|
|
24400
24919
|
this.syncEngine = this.createSyncEngine(cfg,
|
|
24401
24920
|
/* startAsPrimary=*/ !offlineComponentProvider.synchronizeTabs);
|
|
24402
|
-
this.sharedClientState.onlineStateHandler = onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 1 /* SharedClientState */);
|
|
24921
|
+
this.sharedClientState.onlineStateHandler = onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 1 /* OnlineStateSource.SharedClientState */);
|
|
24403
24922
|
this.remoteStore.remoteSyncer.handleCredentialChange =
|
|
24404
24923
|
syncEngineHandleCredentialChange.bind(null, this.syncEngine);
|
|
24405
24924
|
await remoteStoreApplyPrimaryState(this.remoteStore, this.syncEngine.isPrimaryClient);
|
|
@@ -24413,7 +24932,7 @@ class OnlineComponentProvider {
|
|
|
24413
24932
|
return newDatastore(cfg.authCredentials, cfg.appCheckCredentials, connection, serializer);
|
|
24414
24933
|
}
|
|
24415
24934
|
createRemoteStore(cfg) {
|
|
24416
|
-
return newRemoteStore(this.localStore, this.datastore, cfg.asyncQueue, onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 0 /* RemoteStore */), newConnectivityMonitor());
|
|
24935
|
+
return newRemoteStore(this.localStore, this.datastore, cfg.asyncQueue, onlineState => syncEngineApplyOnlineStateChange(this.syncEngine, onlineState, 0 /* OnlineStateSource.RemoteStore */), newConnectivityMonitor());
|
|
24417
24936
|
}
|
|
24418
24937
|
createSyncEngine(cfg, startAsPrimary) {
|
|
24419
24938
|
return newSyncEngine(this.localStore, this.remoteStore, this.eventManager, this.sharedClientState, cfg.initialUser, cfg.maxConcurrentLimboResolutions, startAsPrimary);
|
|
@@ -25170,7 +25689,7 @@ class TransactionRunner {
|
|
|
25170
25689
|
this.updateFunction = updateFunction;
|
|
25171
25690
|
this.deferred = deferred;
|
|
25172
25691
|
this.attemptsRemaining = options.maxAttempts;
|
|
25173
|
-
this.backoff = new ExponentialBackoff(this.asyncQueue, "transaction_retry" /* TransactionRetry */);
|
|
25692
|
+
this.backoff = new ExponentialBackoff(this.asyncQueue, "transaction_retry" /* TimerId.TransactionRetry */);
|
|
25174
25693
|
}
|
|
25175
25694
|
/** Runs the transaction and sets the result on deferred. */
|
|
25176
25695
|
run() {
|
|
@@ -26203,7 +26722,7 @@ class AsyncQueueImpl {
|
|
|
26203
26722
|
// List of TimerIds to fast-forward delays for.
|
|
26204
26723
|
this.timerIdsToSkip = [];
|
|
26205
26724
|
// Backoff timer used to schedule retries for retryable operations
|
|
26206
|
-
this.backoff = new ExponentialBackoff(this, "async_queue_retry" /* AsyncQueueRetry */);
|
|
26725
|
+
this.backoff = new ExponentialBackoff(this, "async_queue_retry" /* TimerId.AsyncQueueRetry */);
|
|
26207
26726
|
// Visibility handler that triggers an immediate retry of all retryable
|
|
26208
26727
|
// operations. Meant to speed up recovery when we regain file system access
|
|
26209
26728
|
// after page comes into foreground.
|
|
@@ -26373,7 +26892,7 @@ class AsyncQueueImpl {
|
|
|
26373
26892
|
this.delayedOperations.sort((a, b) => a.targetTimeMs - b.targetTimeMs);
|
|
26374
26893
|
for (const op of this.delayedOperations) {
|
|
26375
26894
|
op.skipDelay();
|
|
26376
|
-
if (lastTimerId !== "all" /* All */ && op.timerId === lastTimerId) {
|
|
26895
|
+
if (lastTimerId !== "all" /* TimerId.All */ && op.timerId === lastTimerId) {
|
|
26377
26896
|
break;
|
|
26378
26897
|
}
|
|
26379
26898
|
}
|
|
@@ -27286,12 +27805,12 @@ class ParsedUpdateData {
|
|
|
27286
27805
|
}
|
|
27287
27806
|
function isWrite(dataSource) {
|
|
27288
27807
|
switch (dataSource) {
|
|
27289
|
-
case 0 /* Set */: // fall through
|
|
27290
|
-
case 2 /* MergeSet */: // fall through
|
|
27291
|
-
case 1 /* Update */:
|
|
27808
|
+
case 0 /* UserDataSource.Set */: // fall through
|
|
27809
|
+
case 2 /* UserDataSource.MergeSet */: // fall through
|
|
27810
|
+
case 1 /* UserDataSource.Update */:
|
|
27292
27811
|
return true;
|
|
27293
|
-
case 3 /* Argument */:
|
|
27294
|
-
case 4 /* ArrayArgument */:
|
|
27812
|
+
case 3 /* UserDataSource.Argument */:
|
|
27813
|
+
case 4 /* UserDataSource.ArrayArgument */:
|
|
27295
27814
|
return false;
|
|
27296
27815
|
default:
|
|
27297
27816
|
throw fail();
|
|
@@ -27416,8 +27935,8 @@ function newUserDataReader(firestore) {
|
|
|
27416
27935
|
/** Parse document data from a set() call. */
|
|
27417
27936
|
function parseSetData(userDataReader, methodName, targetDoc, input, hasConverter, options = {}) {
|
|
27418
27937
|
const context = userDataReader.createContext(options.merge || options.mergeFields
|
|
27419
|
-
? 2 /* MergeSet */
|
|
27420
|
-
: 0 /* Set */, methodName, targetDoc, hasConverter);
|
|
27938
|
+
? 2 /* UserDataSource.MergeSet */
|
|
27939
|
+
: 0 /* UserDataSource.Set */, methodName, targetDoc, hasConverter);
|
|
27421
27940
|
validatePlainObject('Data must be an object, but it was:', context, input);
|
|
27422
27941
|
const updateData = parseObject(input, context);
|
|
27423
27942
|
let fieldMask;
|
|
@@ -27448,12 +27967,12 @@ function parseSetData(userDataReader, methodName, targetDoc, input, hasConverter
|
|
|
27448
27967
|
}
|
|
27449
27968
|
class DeleteFieldValueImpl extends FieldValue {
|
|
27450
27969
|
_toFieldTransform(context) {
|
|
27451
|
-
if (context.dataSource === 2 /* MergeSet */) {
|
|
27970
|
+
if (context.dataSource === 2 /* UserDataSource.MergeSet */) {
|
|
27452
27971
|
// No transform to add for a delete, but we need to add it to our
|
|
27453
27972
|
// fieldMask so it gets deleted.
|
|
27454
27973
|
context.fieldMask.push(context.path);
|
|
27455
27974
|
}
|
|
27456
|
-
else if (context.dataSource === 1 /* Update */) {
|
|
27975
|
+
else if (context.dataSource === 1 /* UserDataSource.Update */) {
|
|
27457
27976
|
throw context.createError(`${this._methodName}() can only appear at the top level ` +
|
|
27458
27977
|
'of your update data');
|
|
27459
27978
|
}
|
|
@@ -27486,7 +28005,7 @@ class DeleteFieldValueImpl extends FieldValue {
|
|
|
27486
28005
|
*/
|
|
27487
28006
|
function createSentinelChildContext(fieldValue, context, arrayElement) {
|
|
27488
28007
|
return new ParseContextImpl({
|
|
27489
|
-
dataSource: 3 /* Argument */,
|
|
28008
|
+
dataSource: 3 /* UserDataSource.Argument */,
|
|
27490
28009
|
targetDoc: context.settings.targetDoc,
|
|
27491
28010
|
methodName: fieldValue._methodName,
|
|
27492
28011
|
arrayElement
|
|
@@ -27550,7 +28069,7 @@ class NumericIncrementFieldValueImpl extends FieldValue {
|
|
|
27550
28069
|
}
|
|
27551
28070
|
/** Parse update data from an update() call. */
|
|
27552
28071
|
function parseUpdateData(userDataReader, methodName, targetDoc, input) {
|
|
27553
|
-
const context = userDataReader.createContext(1 /* Update */, methodName, targetDoc);
|
|
28072
|
+
const context = userDataReader.createContext(1 /* UserDataSource.Update */, methodName, targetDoc);
|
|
27554
28073
|
validatePlainObject('Data must be an object, but it was:', context, input);
|
|
27555
28074
|
const fieldMaskPaths = [];
|
|
27556
28075
|
const updateData = ObjectValue.empty();
|
|
@@ -27577,7 +28096,7 @@ function parseUpdateData(userDataReader, methodName, targetDoc, input) {
|
|
|
27577
28096
|
}
|
|
27578
28097
|
/** Parse update data from a list of field/value arguments. */
|
|
27579
28098
|
function parseUpdateVarargs(userDataReader, methodName, targetDoc, field, value, moreFieldsAndValues) {
|
|
27580
|
-
const context = userDataReader.createContext(1 /* Update */, methodName, targetDoc);
|
|
28099
|
+
const context = userDataReader.createContext(1 /* UserDataSource.Update */, methodName, targetDoc);
|
|
27581
28100
|
const keys = [fieldPathFromArgument$1(methodName, field, targetDoc)];
|
|
27582
28101
|
const values = [value];
|
|
27583
28102
|
if (moreFieldsAndValues.length % 2 !== 0) {
|
|
@@ -27624,7 +28143,7 @@ function parseUpdateVarargs(userDataReader, methodName, targetDoc, field, value,
|
|
|
27624
28143
|
* contain additional arrays (e.g. the operand of an `in` query).
|
|
27625
28144
|
*/
|
|
27626
28145
|
function parseQueryValue(userDataReader, methodName, input, allowArrays = false) {
|
|
27627
|
-
const context = userDataReader.createContext(allowArrays ? 4 /* ArrayArgument */ : 3 /* Argument */, methodName);
|
|
28146
|
+
const context = userDataReader.createContext(allowArrays ? 4 /* UserDataSource.ArrayArgument */ : 3 /* UserDataSource.Argument */, methodName);
|
|
27628
28147
|
const parsed = parseData(input, context);
|
|
27629
28148
|
return parsed;
|
|
27630
28149
|
}
|
|
@@ -27674,7 +28193,7 @@ function parseData(input, context) {
|
|
|
27674
28193
|
// contain additional arrays (each representing an individual field
|
|
27675
28194
|
// value), so we disable this validation.
|
|
27676
28195
|
if (context.settings.arrayElement &&
|
|
27677
|
-
context.dataSource !== 4 /* ArrayArgument */) {
|
|
28196
|
+
context.dataSource !== 4 /* UserDataSource.ArrayArgument */) {
|
|
27678
28197
|
throw context.createError('Nested arrays are not supported');
|
|
27679
28198
|
}
|
|
27680
28199
|
return parseArray(input, context);
|
|
@@ -28056,164 +28575,334 @@ function fieldPathFromArgument(methodName, arg) {
|
|
|
28056
28575
|
* limitations under the License.
|
|
28057
28576
|
*/
|
|
28058
28577
|
function validateHasExplicitOrderByForLimitToLast(query) {
|
|
28059
|
-
if (query.limitType === "L" /* Last */ &&
|
|
28578
|
+
if (query.limitType === "L" /* LimitType.Last */ &&
|
|
28060
28579
|
query.explicitOrderBy.length === 0) {
|
|
28061
28580
|
throw new FirestoreError(Code.UNIMPLEMENTED, 'limitToLast() queries require specifying at least one orderBy() clause');
|
|
28062
28581
|
}
|
|
28063
28582
|
}
|
|
28583
|
+
/**
|
|
28584
|
+
* An `AppliableConstraint` is an abstraction of a constraint that can be applied
|
|
28585
|
+
* to a Firestore query.
|
|
28586
|
+
*/
|
|
28587
|
+
class AppliableConstraint {
|
|
28588
|
+
}
|
|
28064
28589
|
/**
|
|
28065
28590
|
* A `QueryConstraint` is used to narrow the set of documents returned by a
|
|
28066
28591
|
* Firestore query. `QueryConstraint`s are created by invoking {@link where},
|
|
28067
|
-
* {@link orderBy}, {@link
|
|
28068
|
-
* endBefore
|
|
28592
|
+
* {@link orderBy}, {@link startAt}, {@link startAfter}, {@link
|
|
28593
|
+
* endBefore}, {@link endAt}, {@link limit}, {@link limitToLast} and
|
|
28069
28594
|
* can then be passed to {@link query} to create a new query instance that
|
|
28070
28595
|
* also contains this `QueryConstraint`.
|
|
28071
28596
|
*/
|
|
28072
|
-
class QueryConstraint {
|
|
28597
|
+
class QueryConstraint extends AppliableConstraint {
|
|
28073
28598
|
}
|
|
28074
|
-
|
|
28075
|
-
|
|
28076
|
-
|
|
28077
|
-
|
|
28078
|
-
|
|
28079
|
-
|
|
28080
|
-
|
|
28081
|
-
* existing or new constraints.
|
|
28082
|
-
*/
|
|
28083
|
-
function query(query, ...queryConstraints) {
|
|
28599
|
+
function query(query, queryConstraint, ...additionalQueryConstraints) {
|
|
28600
|
+
let queryConstraints = [];
|
|
28601
|
+
if (queryConstraint instanceof AppliableConstraint) {
|
|
28602
|
+
queryConstraints.push(queryConstraint);
|
|
28603
|
+
}
|
|
28604
|
+
queryConstraints = queryConstraints.concat(additionalQueryConstraints);
|
|
28605
|
+
validateQueryConstraintArray(queryConstraints);
|
|
28084
28606
|
for (const constraint of queryConstraints) {
|
|
28085
28607
|
query = constraint._apply(query);
|
|
28086
28608
|
}
|
|
28087
28609
|
return query;
|
|
28088
28610
|
}
|
|
28089
|
-
|
|
28611
|
+
/**
|
|
28612
|
+
* A `QueryFieldFilterConstraint` is used to narrow the set of documents returned by
|
|
28613
|
+
* a Firestore query by filtering on one or more document fields.
|
|
28614
|
+
* `QueryFieldFilterConstraint`s are created by invoking {@link where} and can then
|
|
28615
|
+
* be passed to {@link query} to create a new query instance that also contains
|
|
28616
|
+
* this `QueryFieldFilterConstraint`.
|
|
28617
|
+
*/
|
|
28618
|
+
class QueryFieldFilterConstraint extends QueryConstraint {
|
|
28619
|
+
/**
|
|
28620
|
+
* @internal
|
|
28621
|
+
*/
|
|
28090
28622
|
constructor(_field, _op, _value) {
|
|
28091
28623
|
super();
|
|
28092
28624
|
this._field = _field;
|
|
28093
28625
|
this._op = _op;
|
|
28094
28626
|
this._value = _value;
|
|
28627
|
+
/** The type of this query constraint */
|
|
28095
28628
|
this.type = 'where';
|
|
28096
28629
|
}
|
|
28630
|
+
static _create(_field, _op, _value) {
|
|
28631
|
+
return new QueryFieldFilterConstraint(_field, _op, _value);
|
|
28632
|
+
}
|
|
28097
28633
|
_apply(query) {
|
|
28634
|
+
const filter = this._parse(query);
|
|
28635
|
+
validateNewFieldFilter(query._query, filter);
|
|
28636
|
+
return new Query(query.firestore, query.converter, queryWithAddedFilter(query._query, filter));
|
|
28637
|
+
}
|
|
28638
|
+
_parse(query) {
|
|
28098
28639
|
const reader = newUserDataReader(query.firestore);
|
|
28099
28640
|
const filter = newQueryFilter(query._query, 'where', reader, query.firestore._databaseId, this._field, this._op, this._value);
|
|
28100
|
-
return
|
|
28641
|
+
return filter;
|
|
28101
28642
|
}
|
|
28102
28643
|
}
|
|
28103
28644
|
/**
|
|
28104
|
-
* Creates a {@link
|
|
28105
|
-
* specified field and that the value should satisfy the
|
|
28106
|
-
* provided.
|
|
28645
|
+
* Creates a {@link QueryFieldFilterConstraint} that enforces that documents
|
|
28646
|
+
* must contain the specified field and that the value should satisfy the
|
|
28647
|
+
* relation constraint provided.
|
|
28107
28648
|
*
|
|
28108
28649
|
* @param fieldPath - The path to compare
|
|
28109
28650
|
* @param opStr - The operation string (e.g "<", "<=", "==", "<",
|
|
28110
28651
|
* "<=", "!=").
|
|
28111
28652
|
* @param value - The value for comparison
|
|
28112
|
-
* @returns The created {@link
|
|
28653
|
+
* @returns The created {@link QueryFieldFilterConstraint}.
|
|
28113
28654
|
*/
|
|
28114
28655
|
function where(fieldPath, opStr, value) {
|
|
28115
28656
|
const op = opStr;
|
|
28116
28657
|
const field = fieldPathFromArgument('where', fieldPath);
|
|
28117
|
-
return
|
|
28658
|
+
return QueryFieldFilterConstraint._create(field, op, value);
|
|
28659
|
+
}
|
|
28660
|
+
/**
|
|
28661
|
+
* A `QueryCompositeFilterConstraint` is used to narrow the set of documents
|
|
28662
|
+
* returned by a Firestore query by performing the logical OR or AND of multiple
|
|
28663
|
+
* {@link QueryFieldFilterConstraint}s or {@link QueryCompositeFilterConstraint}s.
|
|
28664
|
+
* `QueryCompositeFilterConstraint`s are created by invoking {@link or} or
|
|
28665
|
+
* {@link and} and can then be passed to {@link query} to create a new query
|
|
28666
|
+
* instance that also contains the `QueryCompositeFilterConstraint`.
|
|
28667
|
+
* @internal TODO remove this internal tag with OR Query support in the server
|
|
28668
|
+
*/
|
|
28669
|
+
class QueryCompositeFilterConstraint extends AppliableConstraint {
|
|
28670
|
+
/**
|
|
28671
|
+
* @internal
|
|
28672
|
+
*/
|
|
28673
|
+
constructor(
|
|
28674
|
+
/** The type of this query constraint */
|
|
28675
|
+
type, _queryConstraints) {
|
|
28676
|
+
super();
|
|
28677
|
+
this.type = type;
|
|
28678
|
+
this._queryConstraints = _queryConstraints;
|
|
28679
|
+
}
|
|
28680
|
+
static _create(type, _queryConstraints) {
|
|
28681
|
+
return new QueryCompositeFilterConstraint(type, _queryConstraints);
|
|
28682
|
+
}
|
|
28683
|
+
_parse(query) {
|
|
28684
|
+
const parsedFilters = this._queryConstraints
|
|
28685
|
+
.map(queryConstraint => {
|
|
28686
|
+
return queryConstraint._parse(query);
|
|
28687
|
+
})
|
|
28688
|
+
.filter(parsedFilter => parsedFilter.getFilters().length > 0);
|
|
28689
|
+
if (parsedFilters.length === 1) {
|
|
28690
|
+
return parsedFilters[0];
|
|
28691
|
+
}
|
|
28692
|
+
return CompositeFilter.create(parsedFilters, this._getOperator());
|
|
28693
|
+
}
|
|
28694
|
+
_apply(query) {
|
|
28695
|
+
const parsedFilter = this._parse(query);
|
|
28696
|
+
if (parsedFilter.getFilters().length === 0) {
|
|
28697
|
+
// Return the existing query if not adding any more filters (e.g. an empty
|
|
28698
|
+
// composite filter).
|
|
28699
|
+
return query;
|
|
28700
|
+
}
|
|
28701
|
+
validateNewFilter(query._query, parsedFilter);
|
|
28702
|
+
return new Query(query.firestore, query.converter, queryWithAddedFilter(query._query, parsedFilter));
|
|
28703
|
+
}
|
|
28704
|
+
_getQueryConstraints() {
|
|
28705
|
+
return this._queryConstraints;
|
|
28706
|
+
}
|
|
28707
|
+
_getOperator() {
|
|
28708
|
+
return this.type === 'and' ? "and" /* CompositeOperator.AND */ : "or" /* CompositeOperator.OR */;
|
|
28709
|
+
}
|
|
28710
|
+
}
|
|
28711
|
+
/**
|
|
28712
|
+
* Creates a {@link QueryCompositeFilterConstraint} that performs a logical OR
|
|
28713
|
+
* of all the provided {@link QueryFilterConstraint}s.
|
|
28714
|
+
*
|
|
28715
|
+
* @param queryConstraints - Optional. The {@link QueryFilterConstraint}s
|
|
28716
|
+
* for OR operation. These must be created with calls to {@link where},
|
|
28717
|
+
* {@link or}, or {@link and}.
|
|
28718
|
+
* @returns The created {@link QueryCompositeFilterConstraint}.
|
|
28719
|
+
* @internal TODO remove this internal tag with OR Query support in the server
|
|
28720
|
+
*/
|
|
28721
|
+
function or(...queryConstraints) {
|
|
28722
|
+
// Only support QueryFilterConstraints
|
|
28723
|
+
queryConstraints.forEach(queryConstraint => validateQueryFilterConstraint('or', queryConstraint));
|
|
28724
|
+
return QueryCompositeFilterConstraint._create("or" /* CompositeOperator.OR */, queryConstraints);
|
|
28725
|
+
}
|
|
28726
|
+
/**
|
|
28727
|
+
* Creates a {@link QueryCompositeFilterConstraint} that performs a logical AND
|
|
28728
|
+
* of all the provided {@link QueryFilterConstraint}s.
|
|
28729
|
+
*
|
|
28730
|
+
* @param queryConstraints - Optional. The {@link QueryFilterConstraint}s
|
|
28731
|
+
* for AND operation. These must be created with calls to {@link where},
|
|
28732
|
+
* {@link or}, or {@link and}.
|
|
28733
|
+
* @returns The created {@link QueryCompositeFilterConstraint}.
|
|
28734
|
+
* @internal TODO remove this internal tag with OR Query support in the server
|
|
28735
|
+
*/
|
|
28736
|
+
function and(...queryConstraints) {
|
|
28737
|
+
// Only support QueryFilterConstraints
|
|
28738
|
+
queryConstraints.forEach(queryConstraint => validateQueryFilterConstraint('and', queryConstraint));
|
|
28739
|
+
return QueryCompositeFilterConstraint._create("and" /* CompositeOperator.AND */, queryConstraints);
|
|
28118
28740
|
}
|
|
28741
|
+
/**
|
|
28742
|
+
* A `QueryOrderByConstraint` is used to sort the set of documents returned by a
|
|
28743
|
+
* Firestore query. `QueryOrderByConstraint`s are created by invoking
|
|
28744
|
+
* {@link orderBy} and can then be passed to {@link query} to create a new query
|
|
28745
|
+
* instance that also contains this `QueryOrderByConstraint`.
|
|
28746
|
+
*
|
|
28747
|
+
* Note: Documents that do not contain the orderBy field will not be present in
|
|
28748
|
+
* the query result.
|
|
28749
|
+
*/
|
|
28119
28750
|
class QueryOrderByConstraint extends QueryConstraint {
|
|
28751
|
+
/**
|
|
28752
|
+
* @internal
|
|
28753
|
+
*/
|
|
28120
28754
|
constructor(_field, _direction) {
|
|
28121
28755
|
super();
|
|
28122
28756
|
this._field = _field;
|
|
28123
28757
|
this._direction = _direction;
|
|
28758
|
+
/** The type of this query constraint */
|
|
28124
28759
|
this.type = 'orderBy';
|
|
28125
28760
|
}
|
|
28761
|
+
static _create(_field, _direction) {
|
|
28762
|
+
return new QueryOrderByConstraint(_field, _direction);
|
|
28763
|
+
}
|
|
28126
28764
|
_apply(query) {
|
|
28127
28765
|
const orderBy = newQueryOrderBy(query._query, this._field, this._direction);
|
|
28128
28766
|
return new Query(query.firestore, query.converter, queryWithAddedOrderBy(query._query, orderBy));
|
|
28129
28767
|
}
|
|
28130
28768
|
}
|
|
28131
28769
|
/**
|
|
28132
|
-
* Creates a {@link
|
|
28770
|
+
* Creates a {@link QueryOrderByConstraint} that sorts the query result by the
|
|
28133
28771
|
* specified field, optionally in descending order instead of ascending.
|
|
28134
28772
|
*
|
|
28773
|
+
* Note: Documents that do not contain the specified field will not be present
|
|
28774
|
+
* in the query result.
|
|
28775
|
+
*
|
|
28135
28776
|
* @param fieldPath - The field to sort by.
|
|
28136
28777
|
* @param directionStr - Optional direction to sort by ('asc' or 'desc'). If
|
|
28137
28778
|
* not specified, order will be ascending.
|
|
28138
|
-
* @returns The created {@link
|
|
28779
|
+
* @returns The created {@link QueryOrderByConstraint}.
|
|
28139
28780
|
*/
|
|
28140
28781
|
function orderBy(fieldPath, directionStr = 'asc') {
|
|
28141
28782
|
const direction = directionStr;
|
|
28142
28783
|
const path = fieldPathFromArgument('orderBy', fieldPath);
|
|
28143
|
-
return
|
|
28784
|
+
return QueryOrderByConstraint._create(path, direction);
|
|
28144
28785
|
}
|
|
28786
|
+
/**
|
|
28787
|
+
* A `QueryLimitConstraint` is used to limit the number of documents returned by
|
|
28788
|
+
* a Firestore query.
|
|
28789
|
+
* `QueryLimitConstraint`s are created by invoking {@link limit} or
|
|
28790
|
+
* {@link limitToLast} and can then be passed to {@link query} to create a new
|
|
28791
|
+
* query instance that also contains this `QueryLimitConstraint`.
|
|
28792
|
+
*/
|
|
28145
28793
|
class QueryLimitConstraint extends QueryConstraint {
|
|
28146
|
-
|
|
28794
|
+
/**
|
|
28795
|
+
* @internal
|
|
28796
|
+
*/
|
|
28797
|
+
constructor(
|
|
28798
|
+
/** The type of this query constraint */
|
|
28799
|
+
type, _limit, _limitType) {
|
|
28147
28800
|
super();
|
|
28148
28801
|
this.type = type;
|
|
28149
28802
|
this._limit = _limit;
|
|
28150
28803
|
this._limitType = _limitType;
|
|
28151
28804
|
}
|
|
28805
|
+
static _create(type, _limit, _limitType) {
|
|
28806
|
+
return new QueryLimitConstraint(type, _limit, _limitType);
|
|
28807
|
+
}
|
|
28152
28808
|
_apply(query) {
|
|
28153
28809
|
return new Query(query.firestore, query.converter, queryWithLimit(query._query, this._limit, this._limitType));
|
|
28154
28810
|
}
|
|
28155
28811
|
}
|
|
28156
28812
|
/**
|
|
28157
|
-
* Creates a {@link
|
|
28813
|
+
* Creates a {@link QueryLimitConstraint} that only returns the first matching
|
|
28814
|
+
* documents.
|
|
28158
28815
|
*
|
|
28159
28816
|
* @param limit - The maximum number of items to return.
|
|
28160
|
-
* @returns The created {@link
|
|
28817
|
+
* @returns The created {@link QueryLimitConstraint}.
|
|
28161
28818
|
*/
|
|
28162
28819
|
function limit(limit) {
|
|
28163
28820
|
validatePositiveNumber('limit', limit);
|
|
28164
|
-
return
|
|
28821
|
+
return QueryLimitConstraint._create('limit', limit, "F" /* LimitType.First */);
|
|
28165
28822
|
}
|
|
28166
28823
|
/**
|
|
28167
|
-
* Creates a {@link
|
|
28824
|
+
* Creates a {@link QueryLimitConstraint} that only returns the last matching
|
|
28825
|
+
* documents.
|
|
28168
28826
|
*
|
|
28169
28827
|
* You must specify at least one `orderBy` clause for `limitToLast` queries,
|
|
28170
28828
|
* otherwise an exception will be thrown during execution.
|
|
28171
28829
|
*
|
|
28172
28830
|
* @param limit - The maximum number of items to return.
|
|
28173
|
-
* @returns The created {@link
|
|
28831
|
+
* @returns The created {@link QueryLimitConstraint}.
|
|
28174
28832
|
*/
|
|
28175
28833
|
function limitToLast(limit) {
|
|
28176
28834
|
validatePositiveNumber('limitToLast', limit);
|
|
28177
|
-
return
|
|
28835
|
+
return QueryLimitConstraint._create('limitToLast', limit, "L" /* LimitType.Last */);
|
|
28178
28836
|
}
|
|
28837
|
+
/**
|
|
28838
|
+
* A `QueryStartAtConstraint` is used to exclude documents from the start of a
|
|
28839
|
+
* result set returned by a Firestore query.
|
|
28840
|
+
* `QueryStartAtConstraint`s are created by invoking {@link (startAt:1)} or
|
|
28841
|
+
* {@link (startAfter:1)} and can then be passed to {@link query} to create a
|
|
28842
|
+
* new query instance that also contains this `QueryStartAtConstraint`.
|
|
28843
|
+
*/
|
|
28179
28844
|
class QueryStartAtConstraint extends QueryConstraint {
|
|
28180
|
-
|
|
28845
|
+
/**
|
|
28846
|
+
* @internal
|
|
28847
|
+
*/
|
|
28848
|
+
constructor(
|
|
28849
|
+
/** The type of this query constraint */
|
|
28850
|
+
type, _docOrFields, _inclusive) {
|
|
28181
28851
|
super();
|
|
28182
28852
|
this.type = type;
|
|
28183
28853
|
this._docOrFields = _docOrFields;
|
|
28184
28854
|
this._inclusive = _inclusive;
|
|
28185
28855
|
}
|
|
28856
|
+
static _create(type, _docOrFields, _inclusive) {
|
|
28857
|
+
return new QueryStartAtConstraint(type, _docOrFields, _inclusive);
|
|
28858
|
+
}
|
|
28186
28859
|
_apply(query) {
|
|
28187
28860
|
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
|
|
28188
28861
|
return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
|
|
28189
28862
|
}
|
|
28190
28863
|
}
|
|
28191
28864
|
function startAt(...docOrFields) {
|
|
28192
|
-
return
|
|
28865
|
+
return QueryStartAtConstraint._create('startAt', docOrFields,
|
|
28193
28866
|
/*inclusive=*/ true);
|
|
28194
28867
|
}
|
|
28195
28868
|
function startAfter(...docOrFields) {
|
|
28196
|
-
return
|
|
28869
|
+
return QueryStartAtConstraint._create('startAfter', docOrFields,
|
|
28197
28870
|
/*inclusive=*/ false);
|
|
28198
28871
|
}
|
|
28872
|
+
/**
|
|
28873
|
+
* A `QueryEndAtConstraint` is used to exclude documents from the end of a
|
|
28874
|
+
* result set returned by a Firestore query.
|
|
28875
|
+
* `QueryEndAtConstraint`s are created by invoking {@link (endAt:1)} or
|
|
28876
|
+
* {@link (endBefore:1)} and can then be passed to {@link query} to create a new
|
|
28877
|
+
* query instance that also contains this `QueryEndAtConstraint`.
|
|
28878
|
+
*/
|
|
28199
28879
|
class QueryEndAtConstraint extends QueryConstraint {
|
|
28200
|
-
|
|
28880
|
+
/**
|
|
28881
|
+
* @internal
|
|
28882
|
+
*/
|
|
28883
|
+
constructor(
|
|
28884
|
+
/** The type of this query constraint */
|
|
28885
|
+
type, _docOrFields, _inclusive) {
|
|
28201
28886
|
super();
|
|
28202
28887
|
this.type = type;
|
|
28203
28888
|
this._docOrFields = _docOrFields;
|
|
28204
28889
|
this._inclusive = _inclusive;
|
|
28205
28890
|
}
|
|
28891
|
+
static _create(type, _docOrFields, _inclusive) {
|
|
28892
|
+
return new QueryEndAtConstraint(type, _docOrFields, _inclusive);
|
|
28893
|
+
}
|
|
28206
28894
|
_apply(query) {
|
|
28207
28895
|
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
|
|
28208
28896
|
return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
|
|
28209
28897
|
}
|
|
28210
28898
|
}
|
|
28211
28899
|
function endBefore(...docOrFields) {
|
|
28212
|
-
return
|
|
28900
|
+
return QueryEndAtConstraint._create('endBefore', docOrFields,
|
|
28213
28901
|
/*inclusive=*/ false);
|
|
28214
28902
|
}
|
|
28215
28903
|
function endAt(...docOrFields) {
|
|
28216
|
-
return
|
|
28904
|
+
return QueryEndAtConstraint._create('endAt', docOrFields,
|
|
28905
|
+
/*inclusive=*/ true);
|
|
28217
28906
|
}
|
|
28218
28907
|
/** Helper function to create a bound from a document or fields */
|
|
28219
28908
|
function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
|
|
@@ -28229,10 +28918,10 @@ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive)
|
|
|
28229
28918
|
function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
|
|
28230
28919
|
let fieldValue;
|
|
28231
28920
|
if (fieldPath.isKeyField()) {
|
|
28232
|
-
if (op === "array-contains" /* ARRAY_CONTAINS */ || op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
28921
|
+
if (op === "array-contains" /* Operator.ARRAY_CONTAINS */ || op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
28233
28922
|
throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid Query. You can't perform '${op}' queries on documentId().`);
|
|
28234
28923
|
}
|
|
28235
|
-
else if (op === "in" /* IN */ || op === "not-in" /* NOT_IN */) {
|
|
28924
|
+
else if (op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */) {
|
|
28236
28925
|
validateDisjunctiveFilterElements(value, op);
|
|
28237
28926
|
const referenceList = [];
|
|
28238
28927
|
for (const arrayValue of value) {
|
|
@@ -28245,16 +28934,15 @@ function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op
|
|
|
28245
28934
|
}
|
|
28246
28935
|
}
|
|
28247
28936
|
else {
|
|
28248
|
-
if (op === "in" /* IN */ ||
|
|
28249
|
-
op === "not-in" /* NOT_IN */ ||
|
|
28250
|
-
op === "array-contains-any" /* ARRAY_CONTAINS_ANY */) {
|
|
28937
|
+
if (op === "in" /* Operator.IN */ ||
|
|
28938
|
+
op === "not-in" /* Operator.NOT_IN */ ||
|
|
28939
|
+
op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) {
|
|
28251
28940
|
validateDisjunctiveFilterElements(value, op);
|
|
28252
28941
|
}
|
|
28253
28942
|
fieldValue = parseQueryValue(dataReader, methodName, value,
|
|
28254
|
-
/* allowArrays= */ op === "in" /* IN */ || op === "not-in" /* NOT_IN */);
|
|
28943
|
+
/* allowArrays= */ op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */);
|
|
28255
28944
|
}
|
|
28256
28945
|
const filter = FieldFilter.create(fieldPath, op, fieldValue);
|
|
28257
|
-
validateNewFilter(query, filter);
|
|
28258
28946
|
return filter;
|
|
28259
28947
|
}
|
|
28260
28948
|
function newQueryOrderBy(query, fieldPath, direction) {
|
|
@@ -28424,62 +29112,84 @@ function validateDisjunctiveFilterElements(value, operator) {
|
|
|
28424
29112
|
*/
|
|
28425
29113
|
function conflictingOps(op) {
|
|
28426
29114
|
switch (op) {
|
|
28427
|
-
case "!=" /* NOT_EQUAL */:
|
|
28428
|
-
return ["!=" /* NOT_EQUAL */, "not-in" /* NOT_IN */];
|
|
28429
|
-
case "array-contains" /* ARRAY_CONTAINS */:
|
|
29115
|
+
case "!=" /* Operator.NOT_EQUAL */:
|
|
29116
|
+
return ["!=" /* Operator.NOT_EQUAL */, "not-in" /* Operator.NOT_IN */];
|
|
29117
|
+
case "array-contains" /* Operator.ARRAY_CONTAINS */:
|
|
28430
29118
|
return [
|
|
28431
|
-
"array-contains" /* ARRAY_CONTAINS */,
|
|
28432
|
-
"array-contains-any" /* ARRAY_CONTAINS_ANY */,
|
|
28433
|
-
"not-in" /* NOT_IN */
|
|
29119
|
+
"array-contains" /* Operator.ARRAY_CONTAINS */,
|
|
29120
|
+
"array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */,
|
|
29121
|
+
"not-in" /* Operator.NOT_IN */
|
|
28434
29122
|
];
|
|
28435
|
-
case "in" /* IN */:
|
|
28436
|
-
return ["array-contains-any" /* ARRAY_CONTAINS_ANY */, "in" /* IN */, "not-in" /* NOT_IN */];
|
|
28437
|
-
case "array-contains-any" /* ARRAY_CONTAINS_ANY */:
|
|
29123
|
+
case "in" /* Operator.IN */:
|
|
29124
|
+
return ["array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */, "in" /* Operator.IN */, "not-in" /* Operator.NOT_IN */];
|
|
29125
|
+
case "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */:
|
|
28438
29126
|
return [
|
|
28439
|
-
"array-contains" /* ARRAY_CONTAINS */,
|
|
28440
|
-
"array-contains-any" /* ARRAY_CONTAINS_ANY */,
|
|
28441
|
-
"in" /* IN */,
|
|
28442
|
-
"not-in" /* NOT_IN */
|
|
29127
|
+
"array-contains" /* Operator.ARRAY_CONTAINS */,
|
|
29128
|
+
"array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */,
|
|
29129
|
+
"in" /* Operator.IN */,
|
|
29130
|
+
"not-in" /* Operator.NOT_IN */
|
|
28443
29131
|
];
|
|
28444
|
-
case "not-in" /* NOT_IN */:
|
|
29132
|
+
case "not-in" /* Operator.NOT_IN */:
|
|
28445
29133
|
return [
|
|
28446
|
-
"array-contains" /* ARRAY_CONTAINS */,
|
|
28447
|
-
"array-contains-any" /* ARRAY_CONTAINS_ANY */,
|
|
28448
|
-
"in" /* IN */,
|
|
28449
|
-
"not-in" /* NOT_IN */,
|
|
28450
|
-
"!=" /* NOT_EQUAL */
|
|
29134
|
+
"array-contains" /* Operator.ARRAY_CONTAINS */,
|
|
29135
|
+
"array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */,
|
|
29136
|
+
"in" /* Operator.IN */,
|
|
29137
|
+
"not-in" /* Operator.NOT_IN */,
|
|
29138
|
+
"!=" /* Operator.NOT_EQUAL */
|
|
28451
29139
|
];
|
|
28452
29140
|
default:
|
|
28453
29141
|
return [];
|
|
28454
29142
|
}
|
|
28455
29143
|
}
|
|
28456
|
-
function
|
|
28457
|
-
if (
|
|
28458
|
-
const
|
|
28459
|
-
|
|
29144
|
+
function validateNewFieldFilter(query, fieldFilter) {
|
|
29145
|
+
if (fieldFilter.isInequality()) {
|
|
29146
|
+
const existingInequality = getInequalityFilterField(query);
|
|
29147
|
+
const newInequality = fieldFilter.field;
|
|
29148
|
+
if (existingInequality !== null &&
|
|
29149
|
+
!existingInequality.isEqual(newInequality)) {
|
|
28460
29150
|
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Invalid query. All where filters with an inequality' +
|
|
28461
29151
|
' (<, <=, !=, not-in, >, or >=) must be on the same field. But you have' +
|
|
28462
|
-
` inequality filters on '${
|
|
28463
|
-
` and '${
|
|
29152
|
+
` inequality filters on '${existingInequality.toString()}'` +
|
|
29153
|
+
` and '${newInequality.toString()}'`);
|
|
28464
29154
|
}
|
|
28465
29155
|
const firstOrderByField = getFirstOrderByField(query);
|
|
28466
29156
|
if (firstOrderByField !== null) {
|
|
28467
|
-
validateOrderByAndInequalityMatch(query,
|
|
29157
|
+
validateOrderByAndInequalityMatch(query, newInequality, firstOrderByField);
|
|
28468
29158
|
}
|
|
28469
29159
|
}
|
|
28470
|
-
const conflictingOp =
|
|
29160
|
+
const conflictingOp = findOpInsideFilters(query.filters, conflictingOps(fieldFilter.op));
|
|
28471
29161
|
if (conflictingOp !== null) {
|
|
28472
29162
|
// Special case when it's a duplicate op to give a slightly clearer error message.
|
|
28473
|
-
if (conflictingOp ===
|
|
29163
|
+
if (conflictingOp === fieldFilter.op) {
|
|
28474
29164
|
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Invalid query. You cannot use more than one ' +
|
|
28475
|
-
`'${
|
|
29165
|
+
`'${fieldFilter.op.toString()}' filter.`);
|
|
28476
29166
|
}
|
|
28477
29167
|
else {
|
|
28478
|
-
throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid query. You cannot use '${
|
|
29168
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid query. You cannot use '${fieldFilter.op.toString()}' filters ` +
|
|
28479
29169
|
`with '${conflictingOp.toString()}' filters.`);
|
|
28480
29170
|
}
|
|
28481
29171
|
}
|
|
28482
29172
|
}
|
|
29173
|
+
function validateNewFilter(query, filter) {
|
|
29174
|
+
let testQuery = query;
|
|
29175
|
+
const subFilters = filter.getFlattenedFilters();
|
|
29176
|
+
for (const subFilter of subFilters) {
|
|
29177
|
+
validateNewFieldFilter(testQuery, subFilter);
|
|
29178
|
+
testQuery = queryWithAddedFilter(testQuery, subFilter);
|
|
29179
|
+
}
|
|
29180
|
+
}
|
|
29181
|
+
// Checks if any of the provided filter operators are included in the given list of filters and
|
|
29182
|
+
// returns the first one that is, or null if none are.
|
|
29183
|
+
function findOpInsideFilters(filters, operators) {
|
|
29184
|
+
for (const filter of filters) {
|
|
29185
|
+
for (const fieldFilter of filter.getFlattenedFilters()) {
|
|
29186
|
+
if (operators.indexOf(fieldFilter.op) >= 0) {
|
|
29187
|
+
return fieldFilter.op;
|
|
29188
|
+
}
|
|
29189
|
+
}
|
|
29190
|
+
}
|
|
29191
|
+
return null;
|
|
29192
|
+
}
|
|
28483
29193
|
function validateNewOrderBy(query, orderBy) {
|
|
28484
29194
|
if (getFirstOrderByField(query) === null) {
|
|
28485
29195
|
// This is the first order by. It must match any inequality.
|
|
@@ -28497,6 +29207,24 @@ function validateOrderByAndInequalityMatch(baseQuery, inequality, orderBy) {
|
|
|
28497
29207
|
`as your first argument to orderBy(), but your first orderBy() ` +
|
|
28498
29208
|
`is on field '${orderBy.toString()}' instead.`);
|
|
28499
29209
|
}
|
|
29210
|
+
}
|
|
29211
|
+
function validateQueryFilterConstraint(functionName, queryConstraint) {
|
|
29212
|
+
if (!(queryConstraint instanceof QueryFieldFilterConstraint) &&
|
|
29213
|
+
!(queryConstraint instanceof QueryCompositeFilterConstraint)) {
|
|
29214
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, `Function ${functionName}() requires AppliableConstraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`);
|
|
29215
|
+
}
|
|
29216
|
+
}
|
|
29217
|
+
function validateQueryConstraintArray(queryConstraint) {
|
|
29218
|
+
const compositeFilterCount = queryConstraint.filter(filter => filter instanceof QueryCompositeFilterConstraint).length;
|
|
29219
|
+
const fieldFilterCount = queryConstraint.filter(filter => filter instanceof QueryFieldFilterConstraint).length;
|
|
29220
|
+
if (compositeFilterCount > 1 ||
|
|
29221
|
+
(compositeFilterCount > 0 && fieldFilterCount > 0)) {
|
|
29222
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, 'InvalidQuery. When using composite filters, you cannot use ' +
|
|
29223
|
+
'more than one filter at the top level. Consider nesting the multiple ' +
|
|
29224
|
+
'filters within an `and(...)` statement. For example: ' +
|
|
29225
|
+
'change `query(query, where(...), or(...))` to ' +
|
|
29226
|
+
'`query(query, and(where(...), or(...)))`.');
|
|
29227
|
+
}
|
|
28500
29228
|
}
|
|
28501
29229
|
|
|
28502
29230
|
/**
|
|
@@ -28524,27 +29252,27 @@ function validateOrderByAndInequalityMatch(baseQuery, inequality, orderBy) {
|
|
|
28524
29252
|
class AbstractUserDataWriter {
|
|
28525
29253
|
convertValue(value, serverTimestampBehavior = 'none') {
|
|
28526
29254
|
switch (typeOrder(value)) {
|
|
28527
|
-
case 0 /* NullValue */:
|
|
29255
|
+
case 0 /* TypeOrder.NullValue */:
|
|
28528
29256
|
return null;
|
|
28529
|
-
case 1 /* BooleanValue */:
|
|
29257
|
+
case 1 /* TypeOrder.BooleanValue */:
|
|
28530
29258
|
return value.booleanValue;
|
|
28531
|
-
case 2 /* NumberValue */:
|
|
29259
|
+
case 2 /* TypeOrder.NumberValue */:
|
|
28532
29260
|
return normalizeNumber(value.integerValue || value.doubleValue);
|
|
28533
|
-
case 3 /* TimestampValue */:
|
|
29261
|
+
case 3 /* TypeOrder.TimestampValue */:
|
|
28534
29262
|
return this.convertTimestamp(value.timestampValue);
|
|
28535
|
-
case 4 /* ServerTimestampValue */:
|
|
29263
|
+
case 4 /* TypeOrder.ServerTimestampValue */:
|
|
28536
29264
|
return this.convertServerTimestamp(value, serverTimestampBehavior);
|
|
28537
|
-
case 5 /* StringValue */:
|
|
29265
|
+
case 5 /* TypeOrder.StringValue */:
|
|
28538
29266
|
return value.stringValue;
|
|
28539
|
-
case 6 /* BlobValue */:
|
|
29267
|
+
case 6 /* TypeOrder.BlobValue */:
|
|
28540
29268
|
return this.convertBytes(normalizeByteString(value.bytesValue));
|
|
28541
|
-
case 7 /* RefValue */:
|
|
29269
|
+
case 7 /* TypeOrder.RefValue */:
|
|
28542
29270
|
return this.convertReference(value.referenceValue);
|
|
28543
|
-
case 8 /* GeoPointValue */:
|
|
29271
|
+
case 8 /* TypeOrder.GeoPointValue */:
|
|
28544
29272
|
return this.convertGeoPoint(value.geoPointValue);
|
|
28545
|
-
case 9 /* ArrayValue */:
|
|
29273
|
+
case 9 /* TypeOrder.ArrayValue */:
|
|
28546
29274
|
return this.convertArray(value.arrayValue, serverTimestampBehavior);
|
|
28547
|
-
case 10 /* ObjectValue */:
|
|
29275
|
+
case 10 /* TypeOrder.ObjectValue */:
|
|
28548
29276
|
return this.convertObject(value.mapValue, serverTimestampBehavior);
|
|
28549
29277
|
default:
|
|
28550
29278
|
throw fail();
|
|
@@ -28886,16 +29614,16 @@ function changesFromSnapshot(querySnapshot, includeMetadataChanges) {
|
|
|
28886
29614
|
// to lookup the index of a document.
|
|
28887
29615
|
let indexTracker = querySnapshot._snapshot.oldDocs;
|
|
28888
29616
|
return querySnapshot._snapshot.docChanges
|
|
28889
|
-
.filter(change => includeMetadataChanges || change.type !== 3 /* Metadata */)
|
|
29617
|
+
.filter(change => includeMetadataChanges || change.type !== 3 /* ChangeType.Metadata */)
|
|
28890
29618
|
.map(change => {
|
|
28891
29619
|
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);
|
|
28892
29620
|
let oldIndex = -1;
|
|
28893
29621
|
let newIndex = -1;
|
|
28894
|
-
if (change.type !== 0 /* Added */) {
|
|
29622
|
+
if (change.type !== 0 /* ChangeType.Added */) {
|
|
28895
29623
|
oldIndex = indexTracker.indexOf(change.doc.key);
|
|
28896
29624
|
indexTracker = indexTracker.delete(change.doc.key);
|
|
28897
29625
|
}
|
|
28898
|
-
if (change.type !== 1 /* Removed */) {
|
|
29626
|
+
if (change.type !== 1 /* ChangeType.Removed */) {
|
|
28899
29627
|
indexTracker = indexTracker.add(change.doc);
|
|
28900
29628
|
newIndex = indexTracker.indexOf(change.doc.key);
|
|
28901
29629
|
}
|
|
@@ -28910,12 +29638,12 @@ function changesFromSnapshot(querySnapshot, includeMetadataChanges) {
|
|
|
28910
29638
|
}
|
|
28911
29639
|
function resultChangeType(type) {
|
|
28912
29640
|
switch (type) {
|
|
28913
|
-
case 0 /* Added */:
|
|
29641
|
+
case 0 /* ChangeType.Added */:
|
|
28914
29642
|
return 'added';
|
|
28915
|
-
case 2 /* Modified */:
|
|
28916
|
-
case 3 /* Metadata */:
|
|
29643
|
+
case 2 /* ChangeType.Modified */:
|
|
29644
|
+
case 3 /* ChangeType.Metadata */:
|
|
28917
29645
|
return 'modified';
|
|
28918
|
-
case 1 /* Removed */:
|
|
29646
|
+
case 1 /* ChangeType.Removed */:
|
|
28919
29647
|
return 'removed';
|
|
28920
29648
|
default:
|
|
28921
29649
|
return fail();
|
|
@@ -29749,13 +30477,13 @@ function parseIndexes(jsonOrConfiguration) {
|
|
|
29749
30477
|
const fieldPathString = tryGetString(field, 'fieldPath');
|
|
29750
30478
|
const fieldPath = fieldPathFromDotSeparatedString('setIndexConfiguration', fieldPathString);
|
|
29751
30479
|
if (field.arrayConfig === 'CONTAINS') {
|
|
29752
|
-
segments.push(new IndexSegment(fieldPath, 2 /* CONTAINS */));
|
|
30480
|
+
segments.push(new IndexSegment(fieldPath, 2 /* IndexKind.CONTAINS */));
|
|
29753
30481
|
}
|
|
29754
30482
|
else if (field.order === 'ASCENDING') {
|
|
29755
|
-
segments.push(new IndexSegment(fieldPath, 0 /* ASCENDING */));
|
|
30483
|
+
segments.push(new IndexSegment(fieldPath, 0 /* IndexKind.ASCENDING */));
|
|
29756
30484
|
}
|
|
29757
30485
|
else if (field.order === 'DESCENDING') {
|
|
29758
|
-
segments.push(new IndexSegment(fieldPath, 1 /* DESCENDING */));
|
|
30486
|
+
segments.push(new IndexSegment(fieldPath, 1 /* IndexKind.DESCENDING */));
|
|
29759
30487
|
}
|
|
29760
30488
|
}
|
|
29761
30489
|
}
|
|
@@ -29765,12 +30493,11 @@ function parseIndexes(jsonOrConfiguration) {
|
|
|
29765
30493
|
return parsedIndexes;
|
|
29766
30494
|
}
|
|
29767
30495
|
function tryParseJson(json) {
|
|
29768
|
-
var _a;
|
|
29769
30496
|
try {
|
|
29770
30497
|
return JSON.parse(json);
|
|
29771
30498
|
}
|
|
29772
30499
|
catch (e) {
|
|
29773
|
-
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Failed to parse JSON: ' + (
|
|
30500
|
+
throw new FirestoreError(Code.INVALID_ARGUMENT, 'Failed to parse JSON: ' + (e === null || e === void 0 ? void 0 : e.message));
|
|
29774
30501
|
}
|
|
29775
30502
|
}
|
|
29776
30503
|
function tryGetString(data, property) {
|
|
@@ -29813,9 +30540,15 @@ exports.FirestoreError = FirestoreError;
|
|
|
29813
30540
|
exports.GeoPoint = GeoPoint;
|
|
29814
30541
|
exports.LoadBundleTask = LoadBundleTask;
|
|
29815
30542
|
exports.Query = Query;
|
|
30543
|
+
exports.QueryCompositeFilterConstraint = QueryCompositeFilterConstraint;
|
|
29816
30544
|
exports.QueryConstraint = QueryConstraint;
|
|
29817
30545
|
exports.QueryDocumentSnapshot = QueryDocumentSnapshot;
|
|
30546
|
+
exports.QueryEndAtConstraint = QueryEndAtConstraint;
|
|
30547
|
+
exports.QueryFieldFilterConstraint = QueryFieldFilterConstraint;
|
|
30548
|
+
exports.QueryLimitConstraint = QueryLimitConstraint;
|
|
30549
|
+
exports.QueryOrderByConstraint = QueryOrderByConstraint;
|
|
29818
30550
|
exports.QuerySnapshot = QuerySnapshot;
|
|
30551
|
+
exports.QueryStartAtConstraint = QueryStartAtConstraint;
|
|
29819
30552
|
exports.SnapshotMetadata = SnapshotMetadata;
|
|
29820
30553
|
exports.Timestamp = Timestamp;
|
|
29821
30554
|
exports.Transaction = Transaction;
|
|
@@ -29832,6 +30565,7 @@ exports._logWarn = logWarn;
|
|
|
29832
30565
|
exports._validateIsNotUsedTogether = validateIsNotUsedTogether;
|
|
29833
30566
|
exports.addDoc = addDoc;
|
|
29834
30567
|
exports.aggregateQuerySnapshotEqual = aggregateQuerySnapshotEqual;
|
|
30568
|
+
exports.and = and;
|
|
29835
30569
|
exports.arrayRemove = arrayRemove;
|
|
29836
30570
|
exports.arrayUnion = arrayUnion;
|
|
29837
30571
|
exports.clearIndexedDbPersistence = clearIndexedDbPersistence;
|
|
@@ -29866,6 +30600,7 @@ exports.loadBundle = loadBundle;
|
|
|
29866
30600
|
exports.namedQuery = namedQuery;
|
|
29867
30601
|
exports.onSnapshot = onSnapshot;
|
|
29868
30602
|
exports.onSnapshotsInSync = onSnapshotsInSync;
|
|
30603
|
+
exports.or = or;
|
|
29869
30604
|
exports.orderBy = orderBy;
|
|
29870
30605
|
exports.query = query;
|
|
29871
30606
|
exports.queryEqual = queryEqual;
|