Skip to content

Commit

Permalink
fix(NODE-3770): Filter type uses WithId on the schema (#3053)
Browse files Browse the repository at this point in the history
Co-authored-by: Daria Pardue <daria.pardue@mongodb.com>
  • Loading branch information
avaly and dariakp committed Nov 29, 2021
1 parent b6a63df commit 307d623
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 26 deletions.
6 changes: 3 additions & 3 deletions src/collection.ts
Expand Up @@ -730,9 +730,9 @@ export class Collection<TSchema extends Document = Document> {
* @param filter - The filter predicate. If unspecified, then all documents in the collection will match the predicate
*/
find(): FindCursor<WithId<TSchema>>;
find(filter: Filter<WithId<TSchema>>, options?: FindOptions): FindCursor<WithId<TSchema>>;
find<T>(filter: Filter<WithId<TSchema>>, options?: FindOptions): FindCursor<T>;
find(filter?: Filter<WithId<TSchema>>, options?: FindOptions): FindCursor<WithId<TSchema>> {
find(filter: Filter<TSchema>, options?: FindOptions): FindCursor<WithId<TSchema>>;
find<T>(filter: Filter<TSchema>, options?: FindOptions): FindCursor<T>;
find(filter?: Filter<TSchema>, options?: FindOptions): FindCursor<WithId<TSchema>> {
if (arguments.length > 2) {
throw new MongoInvalidArgumentError(
'Method "collection.find()" accepts at most two arguments'
Expand Down
4 changes: 2 additions & 2 deletions src/mongo_types.ts
Expand Up @@ -56,8 +56,8 @@ export type WithoutId<TSchema> = Omit<TSchema, '_id'>;

/** A MongoDB filter can be some portion of the schema or a set of operators @public */
export type Filter<TSchema> = {
[P in keyof TSchema]?: Condition<TSchema[P]>;
} & RootFilterOperators<TSchema>;
[P in keyof WithId<TSchema>]?: Condition<WithId<TSchema>[P]>;
} & RootFilterOperators<WithId<TSchema>>;

/** @public */
export type Condition<T> = AlternativeType<T> | FilterOperators<AlternativeType<T>>;
Expand Down
9 changes: 9 additions & 0 deletions test/types/community/collection/findX.test-d.ts
Expand Up @@ -270,6 +270,9 @@ interface SchemaWithTypicalId {
const schemaWithTypicalIdCol = db.collection<SchemaWithTypicalId>('a');
expectType<WithId<SchemaWithTypicalId> | null>(await schemaWithTypicalIdCol.findOne());
expectAssignable<SchemaWithTypicalId | null>(await schemaWithTypicalIdCol.findOne());
// should allow _id as an ObjectId
await schemaWithTypicalIdCol.findOne({ _id: new ObjectId() });
schemaWithTypicalIdCol.find({ _id: new ObjectId() });

interface SchemaWithOptionalTypicalId {
_id?: ObjectId;
Expand All @@ -278,6 +281,9 @@ interface SchemaWithOptionalTypicalId {
const schemaWithOptionalTypicalId = db.collection<SchemaWithOptionalTypicalId>('a');
expectType<WithId<SchemaWithOptionalTypicalId> | null>(await schemaWithOptionalTypicalId.findOne());
expectAssignable<SchemaWithOptionalTypicalId | null>(await schemaWithOptionalTypicalId.findOne());
// should allow _id as an ObjectId
await schemaWithTypicalIdCol.findOne({ _id: new ObjectId() });
await schemaWithTypicalIdCol.find({ _id: new ObjectId() });

interface SchemaWithUserDefinedId {
_id: number;
Expand All @@ -290,3 +296,6 @@ if (result !== null) {
expectType<number>(result._id);
}
expectAssignable<SchemaWithUserDefinedId | null>(await schemaWithUserDefinedId.findOne());
// should allow _id as a number
await schemaWithUserDefinedId.findOne({ _id: 5 });
await schemaWithUserDefinedId.find({ _id: 5 });
2 changes: 2 additions & 0 deletions test/types/schema_helpers.test-d.ts
Expand Up @@ -19,6 +19,8 @@ expectAssignable<InferIdType<{ _id: number } | { b: string }>>(1 + 1);
// WithId
expectAssignable<WithId<Document>>({ _id: new ObjectId() });
expectAssignable<WithId<{ a: number }>>({ _id: new ObjectId(), a: 3 });
expectAssignable<WithId<{ _id: ObjectId }>>({ _id: new ObjectId() });
expectAssignable<WithId<{ _id: number }>>({ _id: 5 });
expectNotType<WithId<Document>>({ _id: 3 });

// Changing _id to a type other than ObjectId makes it required:
Expand Down
22 changes: 1 addition & 21 deletions test/types/union_schema.test-d.ts
Expand Up @@ -2,7 +2,7 @@ import { expectType, expectError, expectNotType, expectNotAssignable, expectAssi

import type { Collection } from '../../src/collection';
import { ObjectId } from '../../src/bson';
import type { Filter, WithId } from '../../src/mongo_types';
import type { WithId } from '../../src/mongo_types';

type InsertOneFirstParam<Schema> = Parameters<Collection<Schema>['insertOne']>[0];

Expand Down Expand Up @@ -44,23 +44,3 @@ interface B {
type Data = A | B;
expectAssignable<InsertOneFirstParam<Data>>({ _id: 2 });
expectAssignable<InsertOneFirstParam<Data>>({ _id: 'hi' });

// Ensure Exclusive Union Type doesn't break inside our collection methods
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
// eslint-disable-next-line @typescript-eslint/ban-types
type XOR<T, U> = T | U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;

interface Dog {
bark: string;
}
interface Cat {
meow: string;
}
type Pet = XOR<Dog, Cat>;
expectNotAssignable<InsertOneFirstParam<Pet>>({ meow: '', bark: '' });
expectAssignable<InsertOneFirstParam<Pet>>({ meow: '' });
expectAssignable<InsertOneFirstParam<Pet>>({ bark: '' });
expectAssignable<InsertOneFirstParam<Pet>>({ bark: '', _id: new ObjectId() });
expectNotAssignable<Filter<Pet>>({ meow: '', bark: '' }); // find
expectAssignable<Filter<Pet>>({ bark: '' });
expectAssignable<Filter<Pet>>({ meow: '' });

0 comments on commit 307d623

Please sign in to comment.