Skip to content

Commit 29512da

Browse files
authored
refactor(NODE-3157)!: update find and modify interfaces for 4.0 (#2799)
1 parent c3a1839 commit 29512da

File tree

4 files changed

+127
-113
lines changed

4 files changed

+127
-113
lines changed

src/collection.ts

+12-10
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ import {
4545
FindOneAndDeleteOperation,
4646
FindOneAndReplaceOperation,
4747
FindOneAndUpdateOperation,
48-
FindAndModifyOptions
48+
FindOneAndDeleteOptions,
49+
FindOneAndReplaceOptions,
50+
FindOneAndUpdateOptions
4951
} from './operations/find_and_modify';
5052
import {
5153
InsertOneOperation,
@@ -1096,15 +1098,15 @@ export class Collection {
10961098
*/
10971099
findOneAndDelete(filter: Document): Promise<Document>;
10981100
findOneAndDelete(filter: Document, callback: Callback<Document>): void;
1099-
findOneAndDelete(filter: Document, options: FindAndModifyOptions): Promise<Document>;
1101+
findOneAndDelete(filter: Document, options: FindOneAndDeleteOptions): Promise<Document>;
11001102
findOneAndDelete(
11011103
filter: Document,
1102-
options: FindAndModifyOptions,
1104+
options: FindOneAndDeleteOptions,
11031105
callback: Callback<Document>
11041106
): void;
11051107
findOneAndDelete(
11061108
filter: Document,
1107-
options?: FindAndModifyOptions | Callback<Document>,
1109+
options?: FindOneAndDeleteOptions | Callback<Document>,
11081110
callback?: Callback<Document>
11091111
): Promise<Document> | void {
11101112
if (typeof options === 'function') (callback = options), (options = {});
@@ -1129,18 +1131,18 @@ export class Collection {
11291131
findOneAndReplace(
11301132
filter: Document,
11311133
replacement: Document,
1132-
options: FindAndModifyOptions
1134+
options: FindOneAndReplaceOptions
11331135
): Promise<Document>;
11341136
findOneAndReplace(
11351137
filter: Document,
11361138
replacement: Document,
1137-
options: FindAndModifyOptions,
1139+
options: FindOneAndReplaceOptions,
11381140
callback: Callback<Document>
11391141
): void;
11401142
findOneAndReplace(
11411143
filter: Document,
11421144
replacement: Document,
1143-
options?: FindAndModifyOptions | Callback<Document>,
1145+
options?: FindOneAndReplaceOptions | Callback<Document>,
11441146
callback?: Callback<Document>
11451147
): Promise<Document> | void {
11461148
if (typeof options === 'function') (callback = options), (options = {});
@@ -1165,18 +1167,18 @@ export class Collection {
11651167
findOneAndUpdate(
11661168
filter: Document,
11671169
update: Document,
1168-
options: FindAndModifyOptions
1170+
options: FindOneAndUpdateOptions
11691171
): Promise<Document>;
11701172
findOneAndUpdate(
11711173
filter: Document,
11721174
update: Document,
1173-
options: FindAndModifyOptions,
1175+
options: FindOneAndUpdateOptions,
11741176
callback: Callback<Document>
11751177
): void;
11761178
findOneAndUpdate(
11771179
filter: Document,
11781180
update: Document,
1179-
options?: FindAndModifyOptions | Callback<Document>,
1181+
options?: FindOneAndUpdateOptions | Callback<Document>,
11801182
callback?: Callback<Document>
11811183
): Promise<Document> | void {
11821184
if (typeof options === 'function') (callback = options), (options = {});

src/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,12 @@ export type { DropCollectionOptions, DropDatabaseOptions } from './operations/dr
224224
export type { EstimatedDocumentCountOptions } from './operations/estimated_document_count';
225225
export type { EvalOptions } from './operations/eval';
226226
export type { FindOptions } from './operations/find';
227-
export type { Sort, SortDirection } from './sort';
228-
export type { FindAndModifyOptions } from './operations/find_and_modify';
227+
export type { Sort, SortDirection, SortDirectionForCmd, SortForCmd } from './sort';
228+
export type {
229+
FindOneAndDeleteOptions,
230+
FindOneAndReplaceOptions,
231+
FindOneAndUpdateOptions
232+
} from './operations/find_and_modify';
229233
export type {
230234
IndexSpecification,
231235
CreateIndexesOptions,

src/operations/find_and_modify.ts

+107-99
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,146 @@
11
import { ReadPreference } from '../read_preference';
2-
import {
3-
maxWireVersion,
4-
applyRetryableWrites,
5-
decorateWithCollation,
6-
hasAtomicOperators,
7-
Callback
8-
} from '../utils';
2+
import { maxWireVersion, decorateWithCollation, hasAtomicOperators, Callback } from '../utils';
93
import { MongoError } from '../error';
104
import { CommandOperation, CommandOperationOptions } from './command';
115
import { defineAspects, Aspect } from './operation';
126
import type { Document } from '../bson';
137
import type { Server } from '../sdam/server';
148
import type { Collection } from '../collection';
15-
import { Sort, formatSort } from '../sort';
9+
import { Sort, SortForCmd, formatSort } from '../sort';
1610
import type { ClientSession } from '../sessions';
11+
import type { WriteConcern, WriteConcernSettings } from '../write_concern';
1712

1813
/** @public */
19-
export interface FindAndModifyOptions extends CommandOperationOptions {
20-
/** When false, returns the updated document rather than the original. The default is true. */
21-
returnOriginal?: boolean;
22-
/** Upsert the document if it does not exist. */
23-
upsert?: boolean;
14+
export interface FindOneAndDeleteOptions extends CommandOperationOptions {
15+
/** An optional hint for query optimization. See the {@link https://docs.mongodb.com/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/
16+
hint?: Document;
2417
/** Limits the fields to return for all matching documents. */
2518
projection?: Document;
26-
/** @deprecated use `projection` instead */
27-
fields?: Document;
2819
/** Determines which document the operation modifies if the query selects multiple documents. */
2920
sort?: Sort;
21+
}
22+
23+
/** @public */
24+
export interface FindOneAndReplaceOptions extends CommandOperationOptions {
25+
/** Allow driver to bypass schema validation in MongoDB 3.2 or higher. */
26+
bypassDocumentValidation?: boolean;
27+
/** An optional hint for query optimization. See the {@link https://docs.mongodb.com/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/
28+
hint?: Document;
29+
/** Limits the fields to return for all matching documents. */
30+
projection?: Document;
31+
/** When false, returns the updated document rather than the original. The default is true. */
32+
returnOriginal?: boolean;
33+
/** Determines which document the operation modifies if the query selects multiple documents. */
34+
sort?: Sort;
35+
/** Upsert the document if it does not exist. */
36+
upsert?: boolean;
37+
}
38+
39+
/** @public */
40+
export interface FindOneAndUpdateOptions extends CommandOperationOptions {
3041
/** Optional list of array filters referenced in filtered positional operators */
3142
arrayFilters?: Document[];
3243
/** Allow driver to bypass schema validation in MongoDB 3.2 or higher. */
3344
bypassDocumentValidation?: boolean;
3445
/** An optional hint for query optimization. See the {@link https://docs.mongodb.com/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/
3546
hint?: Document;
47+
/** Limits the fields to return for all matching documents. */
48+
projection?: Document;
49+
/** When false, returns the updated document rather than the original. The default is true. */
50+
returnOriginal?: boolean;
51+
/** Determines which document the operation modifies if the query selects multiple documents. */
52+
sort?: Sort;
53+
/** Upsert the document if it does not exist. */
54+
upsert?: boolean;
55+
}
56+
57+
// TODO: NODE-1812 to deprecate returnOriginal for returnDocument
58+
59+
/** @internal */
60+
interface FindAndModifyCmdBase {
61+
remove: boolean;
62+
new: boolean;
63+
upsert: boolean;
64+
update?: Document;
65+
sort?: SortForCmd;
66+
fields?: Document;
67+
bypassDocumentValidation?: boolean;
68+
arrayFilters?: Document[];
69+
maxTimeMS?: number;
70+
writeConcern?: WriteConcern | WriteConcernSettings;
71+
}
3672

37-
// NOTE: These types are a misuse of options, can we think of a way to remove them?
38-
update?: boolean;
39-
remove?: boolean;
40-
new?: boolean;
73+
function configureFindAndModifyCmdBaseUpdateOpts(
74+
cmdBase: FindAndModifyCmdBase,
75+
options: FindOneAndReplaceOptions | FindOneAndUpdateOptions
76+
): FindAndModifyCmdBase {
77+
cmdBase.new = options.returnOriginal === false;
78+
cmdBase.upsert = options.upsert === true;
79+
80+
if (options.bypassDocumentValidation === true) {
81+
cmdBase.bypassDocumentValidation = options.bypassDocumentValidation;
82+
}
83+
return cmdBase;
4184
}
4285

4386
/** @internal */
44-
export class FindAndModifyOperation extends CommandOperation<Document> {
45-
options: FindAndModifyOptions;
87+
class FindAndModifyOperation extends CommandOperation<Document> {
88+
options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions;
89+
cmdBase: FindAndModifyCmdBase;
4690
collection: Collection;
4791
query: Document;
48-
sort?: Sort;
4992
doc?: Document;
5093

5194
constructor(
5295
collection: Collection,
5396
query: Document,
54-
sort: Sort | undefined,
55-
doc: Document | undefined,
56-
options?: FindAndModifyOptions
97+
options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions
5798
) {
5899
super(collection, options);
59100
this.options = options ?? {};
101+
this.cmdBase = {
102+
remove: false,
103+
new: false,
104+
upsert: false
105+
};
106+
107+
const sort = formatSort(options.sort);
108+
if (sort) {
109+
this.cmdBase.sort = sort;
110+
}
111+
112+
if (options.projection) {
113+
this.cmdBase.fields = options.projection;
114+
}
115+
116+
if (options.maxTimeMS) {
117+
this.cmdBase.maxTimeMS = options.maxTimeMS;
118+
}
119+
120+
// Decorate the findAndModify command with the write Concern
121+
if (options.writeConcern) {
122+
this.cmdBase.writeConcern = options.writeConcern;
123+
}
60124

61125
// force primary read preference
62126
this.readPreference = ReadPreference.primary;
63127

64128
this.collection = collection;
65129
this.query = query;
66-
this.sort = sort;
67-
this.doc = doc;
68130
}
69131

70132
execute(server: Server, session: ClientSession, callback: Callback<Document>): void {
71133
const coll = this.collection;
72134
const query = this.query;
73-
const sort = formatSort(this.sort);
74-
const doc = this.doc;
75-
let options = { ...this.options, ...this.bsonOptions };
135+
const options = { ...this.options, ...this.bsonOptions };
76136

77137
// Create findAndModify command object
78138
const cmd: Document = {
79139
findAndModify: coll.collectionName,
80-
query: query
140+
query: query,
141+
...this.cmdBase
81142
};
82143

83-
if (sort) {
84-
cmd.sort = sort;
85-
}
86-
87-
cmd.new = options.new ? true : false;
88-
cmd.remove = options.remove ? true : false;
89-
cmd.upsert = options.upsert ? true : false;
90-
91-
const projection = options.projection || options.fields;
92-
93-
if (projection) {
94-
cmd.fields = projection;
95-
}
96-
97-
if (options.arrayFilters) {
98-
cmd.arrayFilters = options.arrayFilters;
99-
}
100-
101-
if (doc && !options.remove) {
102-
cmd.update = doc;
103-
}
104-
105-
if (options.maxTimeMS) {
106-
cmd.maxTimeMS = options.maxTimeMS;
107-
}
108-
109-
// No check on the documents
110-
options.checkKeys = false;
111-
112-
// Final options for retryable writes
113-
options = applyRetryableWrites(options, coll.s.db);
114-
115-
// Decorate the findAndModify command with the write Concern
116-
if (options.writeConcern) {
117-
cmd.writeConcern = options.writeConcern;
118-
}
119-
120-
// Have we specified bypassDocumentValidation
121-
if (options.bypassDocumentValidation === true) {
122-
cmd.bypassDocumentValidation = options.bypassDocumentValidation;
123-
}
124-
125144
// Have we specified collation
126145
try {
127146
decorateWithCollation(cmd, coll, options);
@@ -159,18 +178,14 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
159178

160179
/** @internal */
161180
export class FindOneAndDeleteOperation extends FindAndModifyOperation {
162-
constructor(collection: Collection, filter: Document, options: FindAndModifyOptions) {
163-
// Final options
164-
const finalOptions = Object.assign({}, options);
165-
finalOptions.fields = options.projection;
166-
finalOptions.remove = true;
167-
181+
constructor(collection: Collection, filter: Document, options: FindOneAndDeleteOptions) {
168182
// Basic validation
169183
if (filter == null || typeof filter !== 'object') {
170184
throw new TypeError('Filter parameter must be an object');
171185
}
172186

173-
super(collection, filter, finalOptions.sort, undefined, finalOptions);
187+
super(collection, filter, options);
188+
this.cmdBase.remove = true;
174189
}
175190
}
176191

@@ -180,15 +195,8 @@ export class FindOneAndReplaceOperation extends FindAndModifyOperation {
180195
collection: Collection,
181196
filter: Document,
182197
replacement: Document,
183-
options: FindAndModifyOptions
198+
options: FindOneAndReplaceOptions
184199
) {
185-
// Final options
186-
const finalOptions = Object.assign({}, options);
187-
finalOptions.fields = options.projection;
188-
finalOptions.update = true;
189-
finalOptions.new = options.returnOriginal !== void 0 ? !options.returnOriginal : false;
190-
finalOptions.upsert = options.upsert !== void 0 ? !!options.upsert : false;
191-
192200
if (filter == null || typeof filter !== 'object') {
193201
throw new TypeError('Filter parameter must be an object');
194202
}
@@ -201,7 +209,9 @@ export class FindOneAndReplaceOperation extends FindAndModifyOperation {
201209
throw new TypeError('Replacement document must not contain atomic operators');
202210
}
203211

204-
super(collection, filter, finalOptions.sort, replacement, finalOptions);
212+
super(collection, filter, options);
213+
this.cmdBase.update = replacement;
214+
configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
205215
}
206216
}
207217

@@ -211,16 +221,8 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
211221
collection: Collection,
212222
filter: Document,
213223
update: Document,
214-
options: FindAndModifyOptions
224+
options: FindOneAndUpdateOptions
215225
) {
216-
// Final options
217-
const finalOptions = Object.assign({}, options);
218-
finalOptions.fields = options.projection;
219-
finalOptions.update = true;
220-
finalOptions.new =
221-
typeof options.returnOriginal === 'boolean' ? !options.returnOriginal : false;
222-
finalOptions.upsert = typeof options.upsert === 'boolean' ? options.upsert : false;
223-
224226
if (filter == null || typeof filter !== 'object') {
225227
throw new TypeError('Filter parameter must be an object');
226228
}
@@ -233,7 +235,13 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
233235
throw new TypeError('Update document requires atomic operators');
234236
}
235237

236-
super(collection, filter, finalOptions.sort, update, finalOptions);
238+
super(collection, filter, options);
239+
this.cmdBase.update = update;
240+
configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
241+
242+
if (options.arrayFilters) {
243+
this.cmdBase.arrayFilters = options.arrayFilters;
244+
}
237245
}
238246
}
239247

0 commit comments

Comments
 (0)