Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine query selector to highlight unexpected query keys #14764

Merged
merged 7 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions test/types/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ function find() {
Project.find({});
Project.find({ name: 'Hello' });

// just callback
Project.find((error: CallbackError, result: IProject[]) => console.log(error, result));
// just callback; this is no longer supported on .find()
expectError(Project.find((error: CallbackError, result: IProject[]) => console.log(error, result)));

// filter + projection
Project.find({}, undefined);
Expand Down Expand Up @@ -977,3 +977,29 @@ function testWithLevel1NestedPaths() {
'foo.one': string | null | undefined
}>({} as Test2);
}

function gh14764TestFilterQueryRestrictions() {
const TestModel = model<{ validKey: number }>('Test', new Schema({}));
// A key not in the schema should be invalid
expectError(TestModel.find({ invalidKey: 0 }));
// A key not in the schema should be invalid for simple root operators
expectError(TestModel.find({ $and: [{ invalidKey: 0 }] }));

// Any "nested" keys should be valid
TestModel.find({ 'validKey.subkey': 0 });

// And deeply "nested" keys should be valid
TestModel.find({ 'validKey.deep.nested.key': 0 });
TestModel.find({ validKey: { deep: { nested: { key: 0 } } } });

// Any Query should be accepted as the root argument (due to merge support)
TestModel.find(TestModel.find());
// A Query should not be a valid type for a FilterQuery within an op like $and
expectError(TestModel.find({ $and: [TestModel.find()] }));

const id = new Types.ObjectId();
// Any ObjectId should be accepted as the root argument
TestModel.find(id);
// A ObjectId should not be a valid type for a FilterQuery within an op like $and
expectError(TestModel.find({ $and: [id] }));
}
2 changes: 1 addition & 1 deletion test/types/queryhelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Project {
type ProjectModelType = Model<Project, ProjectQueryHelpers>;
// Query helpers should return `Query<any, Document<DocType>> & ProjectQueryHelpers`
// to enable chaining.
type ProjectModelQuery = Query<any, HydratedDocument<Project>, ProjectQueryHelpers> & ProjectQueryHelpers;
type ProjectModelQuery = Query<any, HydratedDocument<Project>, ProjectQueryHelpers, any> & ProjectQueryHelpers;
interface ProjectQueryHelpers {
byName(this: ProjectModelQuery, name: string): ProjectModelQuery;
}
Expand Down
72 changes: 36 additions & 36 deletions types/models.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ declare module 'mongoose' {

export interface ReplaceOneModel<TSchema = AnyObject> {
/** The filter to limit the replaced document. */
filter: FilterQuery<TSchema>;
filter: RootFilterQuery<TSchema>;
/** The document with which to replace the matched document. */
replacement: mongodb.WithoutId<TSchema>;
/** Specifies a collation. */
Expand All @@ -203,7 +203,7 @@ declare module 'mongoose' {

export interface UpdateOneModel<TSchema = AnyObject> {
/** The filter to limit the updated documents. */
filter: FilterQuery<TSchema>;
filter: RootFilterQuery<TSchema>;
/** A document or pipeline containing update operators. */
update: UpdateQuery<TSchema>;
/** A set of filters specifying to which array elements an update should apply. */
Expand All @@ -220,7 +220,7 @@ declare module 'mongoose' {

export interface UpdateManyModel<TSchema = AnyObject> {
/** The filter to limit the updated documents. */
filter: FilterQuery<TSchema>;
filter: RootFilterQuery<TSchema>;
/** A document or pipeline containing update operators. */
update: UpdateQuery<TSchema>;
/** A set of filters specifying to which array elements an update should apply. */
Expand All @@ -237,7 +237,7 @@ declare module 'mongoose' {

export interface DeleteOneModel<TSchema = AnyObject> {
/** The filter to limit the deleted documents. */
filter: FilterQuery<TSchema>;
filter: RootFilterQuery<TSchema>;
/** Specifies a collation. */
collation?: mongodb.CollationOptions;
/** The index to use. If specified, then the query system will only consider plans using the hinted index. */
Expand All @@ -246,7 +246,7 @@ declare module 'mongoose' {

export interface DeleteManyModel<TSchema = AnyObject> {
/** The filter to limit the deleted documents. */
filter: FilterQuery<TSchema>;
filter: RootFilterQuery<TSchema>;
/** Specifies a collation. */
collation?: mongodb.CollationOptions;
/** The index to use. If specified, then the query system will only consider plans using the hinted index. */
Expand Down Expand Up @@ -318,7 +318,7 @@ declare module 'mongoose' {

/** Creates a `countDocuments` query: counts the number of documents that match `filter`. */
countDocuments(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
options?: (mongodb.CountOptions & MongooseBaseQueryOptions<TRawDocType>) | null
): QueryWithHelpers<
number,
Expand Down Expand Up @@ -357,7 +357,7 @@ declare module 'mongoose' {
* regardless of the `single` option.
*/
deleteMany(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
options?: (mongodb.DeleteOptions & MongooseBaseQueryOptions<TRawDocType>) | null
): QueryWithHelpers<
mongodb.DeleteResult,
Expand All @@ -368,7 +368,7 @@ declare module 'mongoose' {
TInstanceMethods
>;
deleteMany(
filter: FilterQuery<TRawDocType>
filter: RootFilterQuery<TRawDocType>
): QueryWithHelpers<
mongodb.DeleteResult,
THydratedDocumentType,
Expand All @@ -384,7 +384,7 @@ declare module 'mongoose' {
* `single` option.
*/
deleteOne(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
options?: (mongodb.DeleteOptions & MongooseBaseQueryOptions<TRawDocType>) | null
): QueryWithHelpers<
mongodb.DeleteResult,
Expand All @@ -395,7 +395,7 @@ declare module 'mongoose' {
TInstanceMethods
>;
deleteOne(
filter: FilterQuery<TRawDocType>
filter: RootFilterQuery<TRawDocType>
): QueryWithHelpers<
mongodb.DeleteResult,
THydratedDocumentType,
Expand Down Expand Up @@ -446,7 +446,7 @@ declare module 'mongoose' {

/** Finds one document. */
findOne<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
projection: ProjectionType<TRawDocType> | null | undefined,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
Expand All @@ -458,16 +458,16 @@ declare module 'mongoose' {
TInstanceMethods
>;
findOne<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
projection?: ProjectionType<TRawDocType> | null,
options?: QueryOptions<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOne', TInstanceMethods>;
findOne<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
projection?: ProjectionType<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOne', TInstanceMethods>;
findOne<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>
filter?: RootFilterQuery<TRawDocType>
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOne', TInstanceMethods>;

/**
Expand Down Expand Up @@ -621,7 +621,7 @@ declare module 'mongoose' {
/** Creates a `distinct` query: returns the distinct values of the given `field` that match `filter`. */
distinct<DocKey extends string, ResultType = unknown>(
field: DocKey,
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
options?: QueryOptions<TRawDocType>
): QueryWithHelpers<
Array<
Expand Down Expand Up @@ -651,7 +651,7 @@ declare module 'mongoose' {
* the given `filter`, and `null` otherwise.
*/
exists(
filter: FilterQuery<TRawDocType>
filter: RootFilterQuery<TRawDocType>
): QueryWithHelpers<
{ _id: InferId<TRawDocType> } | null,
THydratedDocumentType,
Expand All @@ -663,7 +663,7 @@ declare module 'mongoose' {

/** Creates a `find` query: gets a list of documents that match `filter`. */
find<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
projection: ProjectionType<TRawDocType> | null | undefined,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
Expand All @@ -675,16 +675,16 @@ declare module 'mongoose' {
TInstanceMethods
>;
find<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
projection?: ProjectionType<TRawDocType> | null | undefined,
options?: QueryOptions<TRawDocType> | null | undefined
): QueryWithHelpers<Array<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'find', TInstanceMethods>;
find<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
projection?: ProjectionType<TRawDocType> | null | undefined
): QueryWithHelpers<Array<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'find', TInstanceMethods>;
find<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>
filter: RootFilterQuery<TRawDocType>
): QueryWithHelpers<Array<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'find', TInstanceMethods>;
find<ResultDoc = THydratedDocumentType>(
): QueryWithHelpers<Array<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'find', TInstanceMethods>;
Expand Down Expand Up @@ -712,7 +712,7 @@ declare module 'mongoose' {

/** Creates a `findOneAndUpdate` query, filtering by the given `_id`. */
findByIdAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { includeResultMetadata: true, lean: true }
): QueryWithHelpers<
Expand Down Expand Up @@ -757,7 +757,7 @@ declare module 'mongoose' {

/** Creates a `findOneAndDelete` query: atomically finds the given document, deletes it, and returns the document as it was before deletion. */
findOneAndDelete<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndDelete'> | null,
Expand All @@ -768,17 +768,17 @@ declare module 'mongoose' {
TInstanceMethods
>;
findOneAndDelete<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { includeResultMetadata: true }
): QueryWithHelpers<ModifyResult<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndDelete', TInstanceMethods>;
findOneAndDelete<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType> | null,
filter?: RootFilterQuery<TRawDocType> | null,
options?: QueryOptions<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndDelete', TInstanceMethods>;

/** Creates a `findOneAndReplace` query: atomically finds the given document and replaces it with `replacement`. */
findOneAndReplace<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
replacement: TRawDocType | AnyObject,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
Expand All @@ -790,24 +790,24 @@ declare module 'mongoose' {
TInstanceMethods
>;
findOneAndReplace<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
replacement: TRawDocType | AnyObject,
options: QueryOptions<TRawDocType> & { includeResultMetadata: true }
): QueryWithHelpers<ModifyResult<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndReplace', TInstanceMethods>;
findOneAndReplace<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
replacement: TRawDocType | AnyObject,
options: QueryOptions<TRawDocType> & { upsert: true } & ReturnsNewDoc
): QueryWithHelpers<ResultDoc, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndReplace', TInstanceMethods>;
findOneAndReplace<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
replacement?: TRawDocType | AnyObject,
options?: QueryOptions<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndReplace', TInstanceMethods>;

/** Creates a `findOneAndUpdate` query: atomically find the first document that matches `filter` and apply `update`. */
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { includeResultMetadata: true, lean: true }
): QueryWithHelpers<
Expand All @@ -819,7 +819,7 @@ declare module 'mongoose' {
TInstanceMethods
>;
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
Expand All @@ -831,24 +831,24 @@ declare module 'mongoose' {
TInstanceMethods
>;
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { includeResultMetadata: true }
): QueryWithHelpers<ModifyResult<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndUpdate', TInstanceMethods>;
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
filter: RootFilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { upsert: true } & ReturnsNewDoc
): QueryWithHelpers<ResultDoc, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndUpdate', TInstanceMethods>;
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
update?: UpdateQuery<TRawDocType>,
options?: QueryOptions<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndUpdate', TInstanceMethods>;

/** Creates a `replaceOne` query: finds the first document that matches `filter` and replaces it with `replacement`. */
replaceOne<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
replacement?: TRawDocType | AnyObject,
options?: (mongodb.ReplaceOptions & MongooseQueryOptions<TRawDocType>) | null
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'replaceOne', TInstanceMethods>;
Expand All @@ -861,14 +861,14 @@ declare module 'mongoose' {

/** Creates a `updateMany` query: updates all documents that match `filter` with `update`. */
updateMany<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
update?: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions<TRawDocType>) | null
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateMany', TInstanceMethods>;

/** Creates a `updateOne` query: updates the first document that matches `filter` with `update`. */
updateOne<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
filter?: RootFilterQuery<TRawDocType>,
update?: UpdateQuery<TRawDocType> | UpdateWithAggregationPipeline,
options?: (mongodb.UpdateOptions & MongooseUpdateQueryOptions<TRawDocType>) | null
): QueryWithHelpers<UpdateWriteOpResult, ResultDoc, TQueryHelpers, TRawDocType, 'updateOne', TInstanceMethods>;
Expand Down
Loading