Skip to content

Commit 8f038fd

Browse files
author
Brian Chen
committed
Fix NotInFilter matches
1 parent 0119d66 commit 8f038fd

File tree

6 files changed

+177
-193
lines changed

6 files changed

+177
-193
lines changed

packages/firestore/exp/src/api/transaction.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ import { Transaction as InternalTransaction } from '../../../src/core/transactio
2929
import { validateReference } from '../../../lite/src/api/write_batch';
3030
import { getDatastore } from '../../../lite/src/api/components';
3131

32-
export class Transaction extends LiteTransaction
32+
export class Transaction
33+
extends LiteTransaction
3334
implements firestore.Transaction {
3435
// This class implements the same logic as the Transaction API in the Lite SDK
3536
// but is subclassed in order to return its own DocumentSnapshot types.

packages/firestore/lite/src/api/field_value.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import { ParseContext } from '../../../src/api/user_data_reader';
3030
import { FieldTransform } from '../../../src/model/mutation';
3131

3232
/** The public FieldValue class of the lite API. */
33-
export abstract class FieldValue extends SerializableFieldValue
33+
export abstract class FieldValue
34+
extends SerializableFieldValue
3435
implements firestore.FieldValue {}
3536

3637
/**

packages/firestore/src/core/query.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,11 @@ export class NotInFilter extends FieldFilter {
855855
}
856856

857857
matches(doc: Document): boolean {
858+
if (
859+
arrayValueContains(this.value.arrayValue!, { nullValue: 'NULL_VALUE' })
860+
) {
861+
return false;
862+
}
858863
const other = doc.field(this.field);
859864
return other !== null && !arrayValueContains(this.value.arrayValue!, other);
860865
}

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

Lines changed: 144 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import { EventsAccumulator } from '../util/events_accumulator';
2424
import * as firebaseExport from '../util/firebase_export';
2525
import {
2626
apiDescribe,
27-
isRunningAgainstEmulator,
2827
notEqualOp,
2928
notInOp,
3029
toChangesArray,
@@ -687,101 +686,82 @@ apiDescribe('Queries', (persistence: boolean) => {
687686
});
688687
});
689688

690-
// eslint-disable-next-line no-restricted-properties
691-
(isRunningAgainstEmulator() ? it : it.skip)(
692-
'can use != filters',
693-
async () => {
694-
const testDocs = {
695-
a: { zip: 98101 },
696-
b: { zip: 91102 },
697-
c: { zip: '98101' },
698-
d: { zip: [98101] },
699-
e: { zip: ['98101', { zip: 98101 }] },
700-
f: { zip: { code: 500 } },
701-
g: { zip: [98101, 98102] },
702-
h: { code: 500 },
703-
i: { zip: null },
704-
j: { zip: Number.NaN }
705-
};
689+
it('can use != filters', async () => {
690+
const testDocs = {
691+
a: { zip: 98101 },
692+
b: { zip: 91102 },
693+
c: { zip: '98101' },
694+
d: { zip: [98101] },
695+
e: { zip: ['98101', { zip: 98101 }] },
696+
f: { zip: { code: 500 } },
697+
g: { zip: [98101, 98102] },
698+
h: { code: 500 },
699+
i: { zip: null },
700+
j: { zip: Number.NaN }
701+
};
706702

707-
await withTestCollection(persistence, testDocs, async coll => {
708-
let expected = { ...testDocs };
709-
// @ts-expect-error
710-
delete expected.a;
711-
// @ts-expect-error
712-
delete expected.h;
713-
// @ts-expect-error
714-
delete expected.i;
715-
const snapshot = await coll.where('zip', notEqualOp, 98101).get();
716-
expect(toDataArray(snapshot)).to.have.deep.members(
717-
Object.values(expected)
718-
);
703+
await withTestCollection(persistence, testDocs, async coll => {
704+
let expected = { ...testDocs };
705+
delete expected.a;
706+
delete expected.h;
707+
delete expected.i;
708+
const snapshot = await coll.where('zip', notEqualOp, 98101).get();
709+
expect(toDataArray(snapshot)).to.have.deep.members(
710+
Object.values(expected)
711+
);
719712

720-
// With objects.
721-
const snapshot2 = await coll
722-
.where('zip', notEqualOp, { code: 500 })
723-
.get();
724-
expected = { ...testDocs };
725-
// @ts-expect-error
726-
delete expected.f;
727-
// @ts-expect-error
728-
delete expected.h;
729-
// @ts-expect-error
730-
delete expected.i;
731-
expect(toDataArray(snapshot2)).to.have.deep.members(
732-
Object.values(expected)
733-
);
713+
// With objects.
714+
const snapshot2 = await coll
715+
.where('zip', notEqualOp, { code: 500 })
716+
.get();
717+
expected = { ...testDocs };
718+
delete expected.f;
719+
delete expected.h;
720+
delete expected.i;
721+
expect(toDataArray(snapshot2)).to.have.deep.members(
722+
Object.values(expected)
723+
);
734724

735-
// With null.
736-
const snapshot3 = await coll.where('zip', notEqualOp, null).get();
737-
expected = { ...testDocs };
738-
// @ts-expect-error
739-
delete expected.h;
740-
// @ts-expect-error
741-
delete expected.i;
742-
expect(toDataArray(snapshot3)).to.have.deep.members(
743-
Object.values(expected)
744-
);
725+
// With null.
726+
const snapshot3 = await coll.where('zip', notEqualOp, null).get();
727+
expected = { ...testDocs };
728+
delete expected.h;
729+
delete expected.i;
730+
expect(toDataArray(snapshot3)).to.have.deep.members(
731+
Object.values(expected)
732+
);
745733

746-
// With NaN.
747-
const snapshot4 = await coll.where('zip', notEqualOp, Number.NaN).get();
748-
expected = { ...testDocs };
749-
// @ts-expect-error
750-
delete expected.h;
751-
// @ts-expect-error
752-
delete expected.i;
753-
// @ts-expect-error
754-
delete expected.j;
755-
expect(toDataArray(snapshot4)).to.have.deep.members(
756-
Object.values(expected)
757-
);
758-
});
759-
}
760-
);
761-
762-
// eslint-disable-next-line no-restricted-properties
763-
(isRunningAgainstEmulator() ? it : it.skip)(
764-
'can use != filters by document ID',
765-
async () => {
766-
const testDocs = {
767-
aa: { key: 'aa' },
768-
ab: { key: 'ab' },
769-
ba: { key: 'ba' },
770-
bb: { key: 'bb' }
771-
};
772-
await withTestCollection(persistence, testDocs, async coll => {
773-
const snapshot = await coll
774-
.where(FieldPath.documentId(), notEqualOp, 'aa')
775-
.get();
776-
777-
expect(toDataArray(snapshot)).to.deep.equal([
778-
{ key: 'ab' },
779-
{ key: 'ba' },
780-
{ key: 'bb' }
781-
]);
782-
});
783-
}
784-
);
734+
// With NaN.
735+
const snapshot4 = await coll.where('zip', notEqualOp, Number.NaN).get();
736+
expected = { ...testDocs };
737+
delete expected.h;
738+
delete expected.i;
739+
delete expected.j;
740+
expect(toDataArray(snapshot4)).to.have.deep.members(
741+
Object.values(expected)
742+
);
743+
});
744+
});
745+
746+
it('can use != filters by document ID', async () => {
747+
const testDocs = {
748+
aa: { key: 'aa' },
749+
ab: { key: 'ab' },
750+
ba: { key: 'ba' },
751+
bb: { key: 'bb' }
752+
};
753+
await withTestCollection(persistence, testDocs, async coll => {
754+
const snapshot = await coll
755+
.where(FieldPath.documentId(), notEqualOp, 'aa')
756+
.get();
757+
758+
expect(toDataArray(snapshot)).to.deep.equal([
759+
{ key: 'ab' },
760+
{ key: 'ba' },
761+
{ key: 'bb' }
762+
]);
763+
});
764+
});
785765

786766
it('can use array-contains filters', async () => {
787767
const testDocs = {
@@ -851,100 +831,79 @@ apiDescribe('Queries', (persistence: boolean) => {
851831
});
852832
});
853833

854-
// eslint-disable-next-line no-restricted-properties
855-
(isRunningAgainstEmulator() ? it : it.skip)(
856-
'can use NOT_IN filters',
857-
async () => {
858-
const testDocs = {
859-
a: { zip: 98101 },
860-
b: { zip: 91102 },
861-
c: { zip: 98103 },
862-
d: { zip: [98101] },
863-
e: { zip: ['98101', { zip: 98101 }] },
864-
f: { zip: { code: 500 } },
865-
g: { zip: [98101, 98102] },
866-
h: { code: 500 },
867-
i: { zip: null },
868-
j: { zip: Number.NaN }
869-
};
834+
it('can use NOT_IN filters', async () => {
835+
const testDocs = {
836+
a: { zip: 98101 },
837+
b: { zip: 91102 },
838+
c: { zip: 98103 },
839+
d: { zip: [98101] },
840+
e: { zip: ['98101', { zip: 98101 }] },
841+
f: { zip: { code: 500 } },
842+
g: { zip: [98101, 98102] },
843+
h: { code: 500 },
844+
i: { zip: null },
845+
j: { zip: Number.NaN }
846+
};
870847

871-
await withTestCollection(persistence, testDocs, async coll => {
872-
let expected = { ...testDocs };
873-
// @ts-expect-error
874-
delete expected.a;
875-
// @ts-expect-error
876-
delete expected.c;
877-
// @ts-expect-error
878-
delete expected.g;
879-
// @ts-expect-error
880-
delete expected.h;
881-
const snapshot = await coll
882-
.where('zip', notInOp, [98101, 98103, [98101, 98102]])
883-
.get();
884-
expect(toDataArray(snapshot)).to.deep.equal(Object.values(expected));
885-
886-
// With objects.
887-
const snapshot2 = await coll
888-
.where('zip', notInOp, [{ code: 500 }])
889-
.get();
890-
expected = { ...testDocs };
891-
// @ts-expect-error
892-
delete expected.f;
893-
// @ts-expect-error
894-
delete expected.h;
895-
expect(toDataArray(snapshot2)).to.deep.equal(Object.values(expected));
896-
897-
// With null.
898-
const snapshot3 = await coll.where('zip', notInOp, [null]).get();
899-
expect(toDataArray(snapshot3)).to.deep.equal([]);
900-
901-
// With NaN.
902-
const snapshot4 = await coll.where('zip', notInOp, [Number.NaN]).get();
903-
expected = { ...testDocs };
904-
// @ts-expect-error
905-
delete expected.h;
906-
// @ts-expect-error
907-
delete expected.j;
908-
expect(toDataArray(snapshot4)).to.deep.equal(Object.values(expected));
909-
910-
// With NaN and a number.
911-
const snapshot5 = await coll
912-
.where('zip', notInOp, [Number.NaN, 98101])
913-
.get();
914-
expected = { ...testDocs };
915-
// @ts-expect-error
916-
delete expected.a;
917-
// @ts-expect-error
918-
delete expected.h;
919-
// @ts-expect-error
920-
delete expected.j;
921-
expect(toDataArray(snapshot5)).to.deep.equal(Object.values(expected));
922-
});
923-
}
924-
);
925-
926-
// eslint-disable-next-line no-restricted-properties
927-
(isRunningAgainstEmulator() ? it : it.skip)(
928-
'can use NOT_IN filters by document ID',
929-
async () => {
930-
const testDocs = {
931-
aa: { key: 'aa' },
932-
ab: { key: 'ab' },
933-
ba: { key: 'ba' },
934-
bb: { key: 'bb' }
935-
};
936-
await withTestCollection(persistence, testDocs, async coll => {
937-
const snapshot = await coll
938-
.where(FieldPath.documentId(), notInOp, ['aa', 'ab'])
939-
.get();
940-
941-
expect(toDataArray(snapshot)).to.deep.equal([
942-
{ key: 'ba' },
943-
{ key: 'bb' }
944-
]);
945-
});
946-
}
947-
);
848+
await withTestCollection(persistence, testDocs, async coll => {
849+
let expected = { ...testDocs };
850+
delete expected.a;
851+
delete expected.c;
852+
delete expected.g;
853+
delete expected.h;
854+
const snapshot = await coll
855+
.where('zip', notInOp, [98101, 98103, [98101, 98102]])
856+
.get();
857+
expect(toDataArray(snapshot)).to.deep.equal(Object.values(expected));
858+
859+
// With objects.
860+
const snapshot2 = await coll.where('zip', notInOp, [{ code: 500 }]).get();
861+
expected = { ...testDocs };
862+
delete expected.f;
863+
delete expected.h;
864+
expect(toDataArray(snapshot2)).to.deep.equal(Object.values(expected));
865+
866+
// With null.
867+
const snapshot3 = await coll.where('zip', notInOp, [null]).get();
868+
expect(toDataArray(snapshot3)).to.deep.equal([]);
869+
870+
// With NaN.
871+
const snapshot4 = await coll.where('zip', notInOp, [Number.NaN]).get();
872+
expected = { ...testDocs };
873+
delete expected.h;
874+
delete expected.j;
875+
expect(toDataArray(snapshot4)).to.deep.equal(Object.values(expected));
876+
877+
// With NaN and a number.
878+
const snapshot5 = await coll
879+
.where('zip', notInOp, [Number.NaN, 98101])
880+
.get();
881+
expected = { ...testDocs };
882+
delete expected.a;
883+
delete expected.h;
884+
delete expected.j;
885+
expect(toDataArray(snapshot5)).to.deep.equal(Object.values(expected));
886+
});
887+
});
888+
889+
it('can use NOT_IN filters by document ID', async () => {
890+
const testDocs = {
891+
aa: { key: 'aa' },
892+
ab: { key: 'ab' },
893+
ba: { key: 'ba' },
894+
bb: { key: 'bb' }
895+
};
896+
await withTestCollection(persistence, testDocs, async coll => {
897+
const snapshot = await coll
898+
.where(FieldPath.documentId(), notInOp, ['aa', 'ab'])
899+
.get();
900+
901+
expect(toDataArray(snapshot)).to.deep.equal([
902+
{ key: 'ba' },
903+
{ key: 'bb' }
904+
]);
905+
});
906+
});
948907

949908
it('can use array-contains-any filters', async () => {
950909
const testDocs = {

0 commit comments

Comments
 (0)