Skip to content

Commit 5cde6cf

Browse files
committed
Merge branch 'main' into crashlytics
2 parents f94f49b + d818df4 commit 5cde6cf

File tree

2 files changed

+82
-18
lines changed

2 files changed

+82
-18
lines changed

packages/firestore/src/core/pipeline-util.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpression {
8181
fieldValue.equal(Constant._fromProto(value))
8282
);
8383
case Operator.NOT_EQUAL:
84-
return and(
85-
fieldValue.exists(),
86-
fieldValue.notEqual(Constant._fromProto(value))
87-
);
84+
return fieldValue.notEqual(Constant._fromProto(value));
8885
case Operator.ARRAY_CONTAINS:
8986
return and(
9087
fieldValue.exists(),
@@ -113,11 +110,11 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpression {
113110
Constant._fromProto(val)
114111
);
115112
if (!values) {
116-
return and(fieldValue.exists(), fieldValue.notEqualAny([]));
113+
return fieldValue.notEqualAny([]);
117114
} else if (values.length === 1) {
118-
return and(fieldValue.exists(), fieldValue.notEqual(values[0]));
115+
return fieldValue.notEqual(values[0]);
119116
} else {
120-
return and(fieldValue.exists(), fieldValue.notEqualAny(values));
117+
return fieldValue.notEqualAny(values);
121118
}
122119
}
123120
default:
@@ -169,19 +166,19 @@ export function toPipeline(query: Query, db: Firestore): Pipeline {
169166

170167
// orders
171168
const orders = queryNormalizedOrderBy(query);
172-
const existsConditions = orders.map(order =>
169+
const existsConditions = query.explicitOrderBy.map(order =>
173170
field(order.field.canonicalString()).exists()
174171
);
175-
if (existsConditions.length > 1) {
176-
pipeline = pipeline.where(
177-
and(
178-
existsConditions[0],
179-
existsConditions[1],
180-
...existsConditions.slice(2)
181-
)
182-
);
183-
} else {
184-
pipeline = pipeline.where(existsConditions[0]);
172+
if (existsConditions.length > 0) {
173+
const condition =
174+
existsConditions.length === 1
175+
? existsConditions[0]
176+
: and(
177+
existsConditions[0],
178+
existsConditions[1],
179+
...existsConditions.slice(2)
180+
);
181+
pipeline = pipeline.where(condition);
185182
}
186183

187184
const orderings = orders.map(order =>

packages/firestore/test/integration/api/query_to_pipeline.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,4 +814,71 @@ apiDescribe.skipClassic('Query to Pipeline', persistence => {
814814
}
815815
);
816816
});
817+
818+
it('not-in removes existence filter', () => {
819+
return withTestCollection(
820+
PERSISTENCE_MODE_UNSPECIFIED,
821+
{
822+
doc1: { field: 2 },
823+
doc2: { field: 1 },
824+
doc3: {}
825+
},
826+
async (collRef, db) => {
827+
const query1 = query(collRef, where('field', 'not-in', [1]));
828+
const snapshot = await execute(db.pipeline().createFrom(query1));
829+
// doc3 (missing 'field') should be included because 'not-in' (and implicit order by)
830+
// should NOT generate an existence filter.
831+
verifyResults(snapshot, { field: 2 }, {});
832+
}
833+
);
834+
});
835+
836+
it('not-equal removes existence filter', () => {
837+
return withTestCollection(
838+
PERSISTENCE_MODE_UNSPECIFIED,
839+
{
840+
doc1: { field: 2 },
841+
doc2: { field: 1 },
842+
doc3: {}
843+
},
844+
async (collRef, db) => {
845+
const query1 = query(collRef, where('field', '!=', 1));
846+
const snapshot = await execute(db.pipeline().createFrom(query1));
847+
// doc3 (missing 'field') should be included.
848+
verifyResults(snapshot, { field: 2 }, {});
849+
}
850+
);
851+
});
852+
853+
it('inequality maintains existence filter', () => {
854+
return withTestCollection(
855+
PERSISTENCE_MODE_UNSPECIFIED,
856+
{
857+
doc1: { field: 0 },
858+
doc2: {}
859+
},
860+
async (collRef, db) => {
861+
const query1 = query(collRef, where('field', '<', 1));
862+
const snapshot = await execute(db.pipeline().createFrom(query1));
863+
// doc2 (missing 'field') should be EXCLUDED by the inequality filter itself.
864+
verifyResults(snapshot, { field: 0 });
865+
}
866+
);
867+
});
868+
869+
it('explicit order maintains existence filter', () => {
870+
return withTestCollection(
871+
PERSISTENCE_MODE_UNSPECIFIED,
872+
{
873+
doc1: { field: 1 },
874+
doc2: {}
875+
},
876+
async (collRef, db) => {
877+
const query1 = query(collRef, orderBy('field'));
878+
const snapshot = await execute(db.pipeline().createFrom(query1));
879+
// doc2 (missing 'field') should be EXCLUDED by the explicit orderBy existence filter.
880+
verifyResults(snapshot, { field: 1 });
881+
}
882+
);
883+
});
817884
});

0 commit comments

Comments
 (0)