Skip to content

Commit 8b2f6d0

Browse files
committed
refactor: Clean up find and modify operation specific logic
1 parent 780ec71 commit 8b2f6d0

File tree

1 file changed

+37
-31
lines changed

1 file changed

+37
-31
lines changed

src/operations/find_and_modify.ts

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,26 @@ interface FindAndModifyOptions extends CommandOperationOptions {
7171
bypassDocumentValidation?: boolean;
7272
/** 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.*/
7373
hint?: Document;
74-
75-
// NOTE: These types are a misuse of options, can we think of a way to remove them?
76-
remove?: boolean;
7774
}
7875

76+
/** @internal */
77+
const OperationTypes = Object.freeze({
78+
deleteOne: 'deleteOne',
79+
replaceOne: 'replaceOne',
80+
updateOne: 'updateOne'
81+
} as const);
82+
83+
/** @internal */
84+
type OperationType = typeof OperationTypes[keyof typeof OperationTypes];
85+
7986
/** @internal */
8087
export class FindAndModifyOperation extends CommandOperation<Document> {
8188
options: FindAndModifyOptions;
8289
collection: Collection;
8390
query: Document;
8491
sort?: Sort;
8592
doc?: Document;
93+
operationType?: OperationType;
8694

8795
constructor(
8896
collection: Collection,
@@ -116,26 +124,36 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
116124
query: query
117125
};
118126

119-
if (sort) {
120-
cmd.sort = sort;
121-
}
122-
123-
if (!options.remove) {
127+
if (this.operationType === OperationTypes.deleteOne) {
128+
cmd.remove = true;
129+
} else {
130+
cmd.remove = false;
131+
// TODO: cmd.new and cmd.upsert were set in two nonequivalent ways, do we want the truthy or the boolean approach?
124132
cmd.new = typeof options.returnOriginal === 'boolean' ? !options.returnOriginal : false;
133+
// TODO: technically, cmd.upsert would previously be set "as is" if it were passed in for delete, do we want to preserve
134+
// that behavior?
125135
cmd.upsert = typeof options.upsert === 'boolean' ? options.upsert : false;
126136
if (doc) {
127137
cmd.update = doc;
128138
}
129139
}
130140

131-
cmd.remove = options.remove ? true : false;
141+
// TODO: arrayFilters is specific to update - do we want to add it to a type-specific block?
142+
if (options.arrayFilters) {
143+
cmd.arrayFilters = options.arrayFilters;
144+
}
132145

133-
if (options.projection) {
134-
cmd.fields = options.projection;
146+
// TODO: bypassDocumentValidation is not applicable to delete - do we want to add it to the else block?
147+
if (options.bypassDocumentValidation === true) {
148+
cmd.bypassDocumentValidation = options.bypassDocumentValidation;
135149
}
136150

137-
if (options.arrayFilters) {
138-
cmd.arrayFilters = options.arrayFilters;
151+
if (sort) {
152+
cmd.sort = sort;
153+
}
154+
155+
if (options.projection) {
156+
cmd.fields = options.projection;
139157
}
140158

141159
if (options.maxTimeMS) {
@@ -147,11 +165,6 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
147165
cmd.writeConcern = options.writeConcern;
148166
}
149167

150-
// Have we specified bypassDocumentValidation
151-
if (options.bypassDocumentValidation === true) {
152-
cmd.bypassDocumentValidation = options.bypassDocumentValidation;
153-
}
154-
155168
// Have we specified collation
156169
try {
157170
decorateWithCollation(cmd, coll, options);
@@ -190,16 +203,13 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
190203
/** @internal */
191204
export class FindOneAndDeleteOperation extends FindAndModifyOperation {
192205
constructor(collection: Collection, filter: Document, options: FindAndModifyOptions) {
193-
// Final options
194-
const finalOptions = Object.assign({}, options);
195-
finalOptions.remove = true;
196-
197206
// Basic validation
198207
if (filter == null || typeof filter !== 'object') {
199208
throw new TypeError('Filter parameter must be an object');
200209
}
201210

202-
super(collection, filter, finalOptions.sort, undefined, finalOptions);
211+
super(collection, filter, options.sort, undefined, options);
212+
this.operationType = OperationTypes.deleteOne;
203213
}
204214
}
205215

@@ -211,9 +221,6 @@ export class FindOneAndReplaceOperation extends FindAndModifyOperation {
211221
replacement: Document,
212222
options: FindAndModifyOptions
213223
) {
214-
// Final options
215-
const finalOptions = Object.assign({}, options);
216-
217224
if (filter == null || typeof filter !== 'object') {
218225
throw new TypeError('Filter parameter must be an object');
219226
}
@@ -226,7 +233,8 @@ export class FindOneAndReplaceOperation extends FindAndModifyOperation {
226233
throw new TypeError('Replacement document must not contain atomic operators');
227234
}
228235

229-
super(collection, filter, finalOptions.sort, replacement, finalOptions);
236+
super(collection, filter, options.sort, replacement, options);
237+
this.operationType = OperationTypes.replaceOne;
230238
}
231239
}
232240

@@ -238,9 +246,6 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
238246
update: Document,
239247
options: FindAndModifyOptions
240248
) {
241-
// Final options
242-
const finalOptions = Object.assign({}, options);
243-
244249
if (filter == null || typeof filter !== 'object') {
245250
throw new TypeError('Filter parameter must be an object');
246251
}
@@ -253,7 +258,8 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
253258
throw new TypeError('Update document requires atomic operators');
254259
}
255260

256-
super(collection, filter, finalOptions.sort, update, finalOptions);
261+
super(collection, filter, options.sort, update, options);
262+
this.operationType = OperationTypes.updateOne;
257263
}
258264
}
259265

0 commit comments

Comments
 (0)