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-3765): make replacement for replaceOne operations without _id #3040

Merged
merged 1 commit into from Dec 8, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bulk/common.ts
Expand Up @@ -33,7 +33,7 @@ import type { Collection } from '../collection';
import type { Topology } from '../sdam/topology';
import type { CommandOperationOptions, CollationOptions } from '../operations/command';
import type { Hint } from '../operations/operation';
import type { Filter, OneOrMore, OptionalId, UpdateFilter } from '../mongo_types';
import type { Filter, OneOrMore, WithoutId, OptionalId, UpdateFilter } from '../mongo_types';

/** @internal */
const kServerError = Symbol('serverError');
Expand Down Expand Up @@ -79,7 +79,7 @@ export interface ReplaceOneModel<TSchema extends Document = Document> {
/** The filter to limit the replaced document. */
filter: Filter<TSchema>;
/** The document with which to replace the matched document. */
replacement: TSchema;
replacement: WithoutId<TSchema>;
/** Specifies a collation. */
collation?: CollationOptions;
/** The index to use. If specified, then the query system will only consider plans using the hinted index. */
Expand Down
27 changes: 17 additions & 10 deletions src/collection.ts
Expand Up @@ -93,6 +93,7 @@ import type {
TODO_NODE_3286,
UpdateFilter,
WithId,
WithoutId,
OptionalId,
Flatten
} from './mongo_types';
Expand Down Expand Up @@ -459,26 +460,29 @@ export class Collection<TSchema extends Document = Document> {
* @param options - Optional settings for the command
* @param callback - An optional callback, a Promise will be returned if none is provided
*/
replaceOne(filter: Filter<TSchema>, replacement: TSchema): Promise<UpdateResult | Document>;
replaceOne(
filter: Filter<TSchema>,
replacement: TSchema,
replacement: WithoutId<TSchema>
): Promise<UpdateResult | Document>;
replaceOne(
filter: Filter<TSchema>,
replacement: WithoutId<TSchema>,
callback: Callback<UpdateResult | Document>
): void;
replaceOne(
filter: Filter<TSchema>,
replacement: TSchema,
replacement: WithoutId<TSchema>,
options: ReplaceOptions
): Promise<UpdateResult | Document>;
replaceOne(
filter: Filter<TSchema>,
replacement: TSchema,
replacement: WithoutId<TSchema>,
options: ReplaceOptions,
callback: Callback<UpdateResult | Document>
): void;
replaceOne(
filter: Filter<TSchema>,
replacement: TSchema,
replacement: WithoutId<TSchema>,
options?: ReplaceOptions | Callback<UpdateResult | Document>,
callback?: Callback<UpdateResult | Document>
): Promise<UpdateResult | Document> | void {
Expand Down Expand Up @@ -1279,26 +1283,29 @@ export class Collection<TSchema extends Document = Document> {
* @param options - Optional settings for the command
* @param callback - An optional callback, a Promise will be returned if none is provided
*/
findOneAndReplace(filter: Filter<TSchema>, replacement: Document): Promise<ModifyResult<TSchema>>;
findOneAndReplace(
filter: Filter<TSchema>,
replacement: Document,
replacement: WithoutId<TSchema>
): Promise<ModifyResult<TSchema>>;
findOneAndReplace(
filter: Filter<TSchema>,
replacement: WithoutId<TSchema>,
callback: Callback<ModifyResult<TSchema>>
): void;
findOneAndReplace(
filter: Filter<TSchema>,
replacement: Document,
replacement: WithoutId<TSchema>,
options: FindOneAndReplaceOptions
): Promise<ModifyResult<TSchema>>;
findOneAndReplace(
filter: Filter<TSchema>,
replacement: Document,
replacement: WithoutId<TSchema>,
options: FindOneAndReplaceOptions,
callback: Callback<ModifyResult<TSchema>>
): void;
findOneAndReplace(
filter: Filter<TSchema>,
replacement: Document,
replacement: WithoutId<TSchema>,
options?: FindOneAndReplaceOptions | Callback<ModifyResult<TSchema>>,
callback?: Callback<ModifyResult<TSchema>>
): Promise<ModifyResult<TSchema>> | void {
Expand Down
32 changes: 32 additions & 0 deletions test/types/community/collection/bulkWrite.test-d.ts
Expand Up @@ -181,6 +181,38 @@ collectionType.bulkWrite([
}
}
]);
// allow a literal replacement doc without an _id
collectionType.bulkWrite([
{
replaceOne: {
filter: {},
replacement: {
dateField: new Date(),
fruitTags: [],
numberField: 0,
readonlyFruitTags: [],
stringField: 'string',
subInterfaceArray: [],
subInterfaceField: { field1: '1', field2: '2' }
},
upsert: true
}
}
]);
// disallow a literal replacement doc with an _id
expectError(
collectionType.bulkWrite([
{
replaceOne: {
filter: {},
replacement: {
_id: new ObjectId()
},
upsert: true
}
}
])
);

expectError(
collectionType.bulkWrite([
Expand Down
19 changes: 19 additions & 0 deletions test/types/community/collection/replaceX.test-d.ts
@@ -0,0 +1,19 @@
import { expectError } from 'tsd';
import { MongoClient, ObjectId } from '../../../../src';

// test collection.replaceX functions
const client = new MongoClient('');
const db = client.db('test');

interface TestModel {
_id: ObjectId;
stringField: string;
}
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved

const collection = db.collection<TestModel>('testCollection');

// should accept a replacement doc without an _id
await collection.replaceOne({}, { stringField: 'b' });

// should not accept a literal replacement doc with an _id
expectError(await collection.replaceOne({}, { _id: new ObjectId(), stringField: 'a' }));