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

fix(NODE-5791): type error with $addToSet in bulkWrite #3953

Merged
merged 10 commits into from
Jan 3, 2024
16 changes: 12 additions & 4 deletions src/bulk/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,12 @@ export interface ReplaceOneModel<TSchema extends Document = Document> {
export interface UpdateOneModel<TSchema extends Document = Document> {
/** The filter to limit the updated documents. */
filter: Filter<TSchema>;
/** A document or pipeline containing update operators. */
update: UpdateFilter<TSchema> | UpdateFilter<TSchema>[];
/**
* The modifications to apply. The value can be either:
* UpdateFilter<TSchema> - A document that contains update operator expressions,
* Document[] - an aggregation pipeline.
* */
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
update: UpdateFilter<TSchema> | Document[];
/** A set of filters specifying to which array elements an update should apply. */
arrayFilters?: Document[];
/** Specifies a collation. */
Expand All @@ -103,8 +107,12 @@ export interface UpdateOneModel<TSchema extends Document = Document> {
export interface UpdateManyModel<TSchema extends Document = Document> {
/** The filter to limit the updated documents. */
filter: Filter<TSchema>;
/** A document or pipeline containing update operators. */
update: UpdateFilter<TSchema> | UpdateFilter<TSchema>[];
/**
* The modifications to apply. The value can be either:
* UpdateFilter<TSchema> - A document that contains update operator expressions,
* Document[] - an aggregation pipeline.
* */
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
update: UpdateFilter<TSchema> | Document[];
/** A set of filters specifying to which array elements an update should apply. */
arrayFilters?: Document[];
/** Specifies a collation. */
Expand Down
18 changes: 14 additions & 4 deletions src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,17 @@ export class Collection<TSchema extends Document = Document> {
* Update a single document in a collection
*
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
* @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<TSchema>,
update: UpdateFilter<TSchema> | Partial<TSchema>,
/**
* The value of update can be either:
* UpdateFilter<TSchema> - A document that contains update operator expressions,
* Document[] - an aggregation pipeline.
* */
update: UpdateFilter<TSchema> | Document[],
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
options?: UpdateOptions
): Promise<UpdateResult<TSchema>> {
return executeOperation(
Expand Down Expand Up @@ -386,12 +391,17 @@ export class Collection<TSchema extends Document = Document> {
* 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
* @param update - The modifications to apply
* @param options - Optional settings for the command
*/
async updateMany(
filter: Filter<TSchema>,
update: UpdateFilter<TSchema>,
/**
* The value of update can be either:
* UpdateFilter<TSchema> - A document that contains update operator expressions,
* Document[] - an aggregation pipeline.
* */
update: UpdateFilter<TSchema> | Document[],
options?: UpdateOptions
): Promise<UpdateResult<TSchema>> {
return executeOperation(
Expand Down
6 changes: 5 additions & 1 deletion src/mongo_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,11 @@ export type SetFields<TSchema> = ({
readonly [key in KeysOfAType<TSchema, ReadonlyArray<any> | undefined>]?:
| OptionalId<Flatten<TSchema[key]>>
| AddToSetOperators<Array<OptionalId<Flatten<TSchema[key]>>>>;
} & NotAcceptedFields<TSchema, ReadonlyArray<any> | undefined>) & {
} & IsAny<
TSchema[keyof TSchema],
object,
NotAcceptedFields<TSchema, ReadonlyArray<any> | undefined>
>) & {
readonly [key: string]: AddToSetOperators<any> | any;
};

Expand Down
196 changes: 195 additions & 1 deletion test/types/community/collection/bulkWrite.test-d.ts
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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<TestDocument>;
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<IndexSingatureTestDocument>;
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<any>;
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 }
}
]
}
}
]);
}
63 changes: 63 additions & 0 deletions test/types/community/collection/updateX.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,66 @@ export async function testPushWithId(): Promise<void> {
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<TestDocument>;
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<IndexSingatureTestDocument>;
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<any>;
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 }
}
]);
}