Skip to content

Commit

Permalink
Merge pull request #14764 from alex-statsig/patch-1
Browse files Browse the repository at this point in the history
Refine query selector to highlight unexpected query keys
  • Loading branch information
vkarpov15 authored Aug 12, 2024
2 parents 80cd6a8 + e5c9b7b commit 9b7324f
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 63 deletions.
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

0 comments on commit 9b7324f

Please sign in to comment.