From bf31e32d7e554a7e9876bde171ceb5e4f1fb1cd6 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 8 Jan 2024 15:52:16 +0100 Subject: [PATCH] fix(NODE-5791): type error with $addToSet in bulkWrite --- src/bulk/common.ts | 16 +- src/collection.ts | 18 +- src/mongo_types.ts | 6 +- .../community/collection/bulkWrite.test-d.ts | 196 +++++++++++++++++- .../community/collection/updateX.test-d.ts | 63 ++++++ 5 files changed, 288 insertions(+), 11 deletions(-) diff --git a/src/bulk/common.ts b/src/bulk/common.ts index 328c6e27697..a4f0da8c48a 100644 --- a/src/bulk/common.ts +++ b/src/bulk/common.ts @@ -85,8 +85,12 @@ export interface ReplaceOneModel { export interface UpdateOneModel { /** The filter to limit the updated documents. */ filter: Filter; - /** A document or pipeline containing update operators. */ - update: UpdateFilter | UpdateFilter[]; + /** + * The modifications to apply. The value can be either: + * UpdateFilter - A document that contains update operator expressions, + * Document[] - an aggregation pipeline. + */ + update: UpdateFilter | Document[]; /** A set of filters specifying to which array elements an update should apply. */ arrayFilters?: Document[]; /** Specifies a collation. */ @@ -101,8 +105,12 @@ export interface UpdateOneModel { export interface UpdateManyModel { /** The filter to limit the updated documents. */ filter: Filter; - /** A document or pipeline containing update operators. */ - update: UpdateFilter | UpdateFilter[]; + /** + * The modifications to apply. The value can be either: + * UpdateFilter - A document that contains update operator expressions, + * Document[] - an aggregation pipeline. + */ + update: UpdateFilter | Document[]; /** A set of filters specifying to which array elements an update should apply. */ arrayFilters?: Document[]; /** Specifies a collation. */ diff --git a/src/collection.ts b/src/collection.ts index 8ace41e9eef..bb2a8ab73f7 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -344,13 +344,17 @@ export class Collection { /** * Update a single document in a collection * + * The value of `update` can be either: + * - UpdateFilter - A document that contains update operator expressions, + * - Document[] - an aggregation pipeline. + * * @param filter - The filter used to select the document to update - * @param update - The update operations to be applied to the document + * @param update - The modifications to apply * @param options - Optional settings for the command */ async updateOne( filter: Filter, - update: UpdateFilter | Partial, + update: UpdateFilter | Document[], options?: UpdateOptions ): Promise> { return executeOperation( @@ -390,13 +394,17 @@ export class Collection { /** * Update multiple documents in a collection * - * @param filter - The filter used to select the documents to update - * @param update - The update operations to be applied to the documents + * The value of `update` can be either: + * - UpdateFilter - A document that contains update operator expressions, + * - Document[] - an aggregation pipeline. + * + * @param filter - The filter used to select the document to update + * @param update - The modifications to apply * @param options - Optional settings for the command */ async updateMany( filter: Filter, - update: UpdateFilter, + update: UpdateFilter | Document[], options?: UpdateOptions ): Promise> { return executeOperation( diff --git a/src/mongo_types.ts b/src/mongo_types.ts index adfec0af67d..7de27b75eb3 100644 --- a/src/mongo_types.ts +++ b/src/mongo_types.ts @@ -237,7 +237,11 @@ export type SetFields = ({ readonly [key in KeysOfAType | undefined>]?: | OptionalId> | AddToSetOperators>>>; -} & NotAcceptedFields | undefined>) & { +} & IsAny< + TSchema[keyof TSchema], + object, + NotAcceptedFields | undefined> +>) & { readonly [key: string]: AddToSetOperators | any; }; diff --git a/test/types/community/collection/bulkWrite.test-d.ts b/test/types/community/collection/bulkWrite.test-d.ts index 5c8ee78ecf1..f47044eb926 100644 --- a/test/types/community/collection/bulkWrite.test-d.ts +++ b/test/types/community/collection/bulkWrite.test-d.ts @@ -1,6 +1,6 @@ import { expectError } from 'tsd'; -import { MongoClient, ObjectId } from '../../../mongodb'; +import { type Collection, type Document, MongoClient, ObjectId } from '../../../mongodb'; // TODO(NODE-3347): Improve these tests to use more expect assertions @@ -297,3 +297,197 @@ collectionType.bulkWrite([ } } ]); + +{ + // NODE-5647 - Type error with $addToSet in bulkWrite + interface TestDocument { + readonly myId: number; + readonly mySet: number[]; + readonly myAny: any; + } + const collection = undefined as unknown as Collection; + expectError( + collection.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 'value of other type' } + } + } + } + ]) + ); + collection.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 0 } + } + } + } + ]); + collection.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: { + $addToSet: { myAny: 1 } + } + } + } + ]); + collection.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: [ + { + $addToSet: { myAny: 0 } + } + ] + } + } + ]); + expectError( + collection.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 'value of other type' } + } + } + } + ]) + ); + collection.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 0 } + } + } + } + ]); + collection.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: { + $addToSet: { myAny: 1 } + } + } + } + ]); + collection.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: [ + { + $addToSet: { mySet: 0 } + } + ] + } + } + ]); + + interface IndexSingatureTestDocument extends Document { + readonly myId: number; + readonly mySet: number[]; + } + const indexSingatureCollection = undefined as unknown as Collection; + indexSingatureCollection.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 0 } + } + } + } + ]); + indexSingatureCollection.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: [ + { + $addToSet: { mySet: 0 } + } + ] + } + } + ]); + indexSingatureCollection.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 0 } + } + } + } + ]); + indexSingatureCollection.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: [ + { + $addToSet: { mySet: 0 } + } + ] + } + } + ]); + + const collectionOfAnyType = undefined as unknown as Collection; + collectionOfAnyType.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 0 } + } + } + } + ]); + collectionOfAnyType.bulkWrite([ + { + updateOne: { + filter: { myId: 0 }, + update: [ + { + $addToSet: { mySet: 0 } + } + ] + } + } + ]); + collectionOfAnyType.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: { + $addToSet: { mySet: 0 } + } + } + } + ]); + collectionOfAnyType.bulkWrite([ + { + updateMany: { + filter: { myId: 0 }, + update: [ + { + $addToSet: { mySet: 0 } + } + ] + } + } + ]); +} diff --git a/test/types/community/collection/updateX.test-d.ts b/test/types/community/collection/updateX.test-d.ts index b729b20b4d9..5ea59cd5256 100644 --- a/test/types/community/collection/updateX.test-d.ts +++ b/test/types/community/collection/updateX.test-d.ts @@ -439,3 +439,66 @@ export async function testPushWithId(): Promise { collectionWithSchema.updateMany({}, {}) ); } + +{ + // NODE-5647 - Type error with $addToSet in bulkWrite + interface TestDocument { + readonly myId: number; + readonly mySet: number[]; + readonly myAny: any; + } + const collection = undefined as unknown as Collection; + expectError(collection.updateOne({ myId: 0 }, { $addToSet: { mySet: 'value of other type' } })); + collection.updateOne({ myId: 0 }, { $addToSet: { mySet: 0 } }); + collection.updateOne({ myId: 0 }, { $addToSet: { myAny: 1 } }); + collection.updateOne({ myId: 0 }, [ + { + $addToSet: { mySet: 0 } + } + ]); + expectError(collection.updateMany({ myId: 0 }, { $addToSet: { mySet: 'value of other type' } })); + collection.updateMany({ myId: 0 }, { $addToSet: { mySet: 0 } }); + collection.updateMany({ myId: 0 }, { $addToSet: { myAny: 1 } }); + collection.updateMany({ myId: 0 }, [ + { + $addToSet: { mySet: 0 } + } + ]); + + interface IndexSingatureTestDocument extends Document { + readonly myId: number; + readonly mySet: number[]; + readonly myAny: any; + } + const indexSingatureCollection = undefined as unknown as Collection; + indexSingatureCollection.updateOne({ myId: 0 }, { $addToSet: { mySet: 0 } }); + indexSingatureCollection.updateOne({ myId: 0 }, { $addToSet: { myAny: 1 } }); + indexSingatureCollection.updateOne({ myId: 0 }, [ + { + $addToSet: { mySet: 0 } + } + ]); + indexSingatureCollection.updateMany({ myId: 0 }, { $addToSet: { mySet: 0 } }); + indexSingatureCollection.updateMany({ myId: 0 }, { $addToSet: { myAny: 1 } }); + indexSingatureCollection.updateMany({ myId: 0 }, [ + { + $addToSet: { mySet: 0 } + } + ]); + + const collectionOfAnyType = undefined as unknown as Collection; + collectionOfAnyType.updateOne({ myId: 0 }, { $addToSet: { mySet: 0 } }); + collectionOfAnyType.updateOne({ myId: 0 }, { $addToSet: { myAny: 1 } }); + collectionOfAnyType.updateOne({ myId: 0 }, [ + { + $addToSet: { mySet: 0 } + } + ]); + collectionOfAnyType.updateMany({ myId: 0 }, { $addToSet: { mySet: 0 } }); + collectionOfAnyType.updateMany({ myId: 0 }, { $addToSet: { myAny: 1 } }); + collectionOfAnyType.updateMany({ myId: 0 }, [ + { + $addToSet: { mySet: 0 } + } + ]); +}