@opra/mongodb 1.0.10 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,8 @@ exports.default = prepareProjection;
4
4
  exports.prepare = prepare;
5
5
  const common_1 = require("@opra/common");
6
6
  function prepareProjection(dataType, projection) {
7
+ if (projection === '*')
8
+ return undefined;
7
9
  if (projection && typeof projection === 'object' && !Array.isArray(projection))
8
10
  return projection;
9
11
  const out = {};
@@ -64,6 +64,16 @@ var MongoAdapter;
64
64
  };
65
65
  return { method: 'get', key, options };
66
66
  }
67
+ case 'Entity.Replace': {
68
+ const data = await ctx.getBody();
69
+ const keyParam = operation.parameters.find(p => p.keyParam) || controller.parameters.find(p => p.keyParam);
70
+ const key = keyParam && ctx.pathParams[String(keyParam.name)];
71
+ const options = {
72
+ projection: ctx.queryParams.projection,
73
+ filter: ctx.queryParams.filter,
74
+ };
75
+ return { method: 'replace', key, data, options };
76
+ }
67
77
  case 'Entity.Update': {
68
78
  const data = await ctx.getBody();
69
79
  const keyParam = operation.parameters.find(p => p.keyParam) || controller.parameters.find(p => p.keyParam);
@@ -74,8 +74,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
74
74
  options,
75
75
  };
76
76
  return this._executeCommand(command, async () => {
77
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
78
- command.options = { ...command.options, filter };
77
+ const documentFilter = await this._getDocumentFilter(command);
78
+ if (documentFilter) {
79
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
80
+ command.options = { ...command.options, filter };
81
+ }
79
82
  return this._count(command);
80
83
  });
81
84
  }
@@ -95,8 +98,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
95
98
  options,
96
99
  };
97
100
  return this._executeCommand(command, async () => {
98
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
99
- command.options = { ...command.options, filter };
101
+ const documentFilter = await this._getDocumentFilter(command);
102
+ if (documentFilter) {
103
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
104
+ command.options = { ...command.options, filter };
105
+ }
100
106
  return this._delete(command);
101
107
  });
102
108
  }
@@ -114,8 +120,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
114
120
  options,
115
121
  };
116
122
  return this._executeCommand(command, async () => {
117
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
118
- command.options = { ...command.options, filter };
123
+ const documentFilter = await this._getDocumentFilter(command);
124
+ if (documentFilter) {
125
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
126
+ command.options = { ...command.options, filter };
127
+ }
119
128
  return this._deleteMany(command);
120
129
  });
121
130
  }
@@ -134,8 +143,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
134
143
  options,
135
144
  };
136
145
  return this._executeCommand(command, async () => {
137
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
138
- command.options = { ...command.options, filter };
146
+ const documentFilter = await this._getDocumentFilter(command);
147
+ if (documentFilter) {
148
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
149
+ command.options = { ...command.options, filter };
150
+ }
139
151
  return this._distinct(command);
140
152
  });
141
153
  }
@@ -155,10 +167,12 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
155
167
  options,
156
168
  };
157
169
  return this._executeCommand(command, async () => {
158
- const documentFilter = await this._getDocumentFilter(command);
159
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
160
170
  const findCommand = command;
161
- findCommand.options = { ...command.options, filter, projection: ['_id'] };
171
+ const documentFilter = await this._getDocumentFilter(command);
172
+ if (documentFilter) {
173
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
174
+ findCommand.options = { ...command.options, filter, projection: ['_id'] };
175
+ }
162
176
  return !!(await this._findById(findCommand));
163
177
  });
164
178
  }
@@ -181,8 +195,10 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
181
195
  };
182
196
  return this._executeCommand(command, async () => {
183
197
  const documentFilter = await this._getDocumentFilter(command);
184
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
185
- command.options = { ...command.options, filter };
198
+ if (documentFilter) {
199
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
200
+ command.options = { ...command.options, filter };
201
+ }
186
202
  return this._findById(command);
187
203
  });
188
204
  }
@@ -194,8 +210,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
194
210
  options,
195
211
  };
196
212
  return this._executeCommand(command, async () => {
197
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
198
- command.options = { ...command.options, filter };
213
+ const documentFilter = await this._getDocumentFilter(command);
214
+ if (documentFilter) {
215
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
216
+ command.options = { ...command.options, filter };
217
+ }
199
218
  return this._findOne(command);
200
219
  });
201
220
  }
@@ -207,9 +226,14 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
207
226
  options,
208
227
  };
209
228
  return this._executeCommand(command, async () => {
210
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
229
+ const documentFilter = await this._getDocumentFilter(command);
230
+ command.options = command.options || {};
231
+ if (documentFilter) {
232
+ command.options.filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
233
+ }
211
234
  const limit = command.options?.limit || this.defaultLimit;
212
- command.options = { ...command.options, filter, limit };
235
+ if (limit)
236
+ command.options.limit = limit;
213
237
  return this._findMany(command);
214
238
  });
215
239
  }
@@ -221,8 +245,14 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
221
245
  options,
222
246
  };
223
247
  return this._executeCommand(command, async () => {
224
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
225
- command.options = { ...command.options, filter, limit: command.options?.limit || this.defaultLimit };
248
+ const documentFilter = await this._getDocumentFilter(command);
249
+ command.options = command.options || {};
250
+ if (documentFilter) {
251
+ command.options.filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
252
+ }
253
+ const limit = command.options?.limit || this.defaultLimit;
254
+ if (limit)
255
+ command.options.limit = limit;
226
256
  return this._findManyWithCount(command);
227
257
  });
228
258
  }
@@ -232,6 +262,25 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
232
262
  throw new common_1.ResourceNotAvailableError(this.getResourceName(), id);
233
263
  return out;
234
264
  }
265
+ async replace(id, input, options) {
266
+ const command = {
267
+ crud: 'replace',
268
+ method: 'replace',
269
+ documentId: id,
270
+ byId: true,
271
+ input,
272
+ options,
273
+ };
274
+ input._id = id;
275
+ return this._executeCommand(command, async () => {
276
+ const documentFilter = await this._getDocumentFilter(command);
277
+ if (documentFilter) {
278
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
279
+ command.options = { ...command.options, filter };
280
+ }
281
+ return await this._replace(command);
282
+ });
283
+ }
235
284
  async update(id, input, options) {
236
285
  const isUpdateFilter = Array.isArray(input) || !!Object.keys(input).find(x => x.startsWith('$'));
237
286
  const command = {
@@ -244,8 +293,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
244
293
  options,
245
294
  };
246
295
  return this._executeCommand(command, async () => {
247
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
248
- command.options = { ...command.options, filter };
296
+ const documentFilter = await this._getDocumentFilter(command);
297
+ if (documentFilter) {
298
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
299
+ command.options = { ...command.options, filter };
300
+ }
249
301
  return this._update(command);
250
302
  });
251
303
  }
@@ -269,8 +321,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
269
321
  options,
270
322
  };
271
323
  return this._executeCommand(command, async () => {
272
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
273
- command.options = { ...command.options, filter };
324
+ const documentFilter = await this._getDocumentFilter(command);
325
+ if (documentFilter) {
326
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
327
+ command.options = { ...command.options, filter };
328
+ }
274
329
  return this._updateOnly(command);
275
330
  });
276
331
  }
@@ -292,8 +347,11 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
292
347
  options,
293
348
  };
294
349
  return this._executeCommand(command, async () => {
295
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
296
- command.options = { ...command.options, filter };
350
+ const documentFilter = await this._getDocumentFilter(command);
351
+ if (documentFilter) {
352
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
353
+ command.options = { ...command.options, filter };
354
+ }
297
355
  return this._updateMany(command);
298
356
  });
299
357
  }
@@ -131,10 +131,11 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
131
131
  const { options } = command;
132
132
  const db = this.getDatabase();
133
133
  const collection = await this.getCollection(db);
134
+ const projection = mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection);
134
135
  const out = await collection.findOne(filter || {}, {
135
136
  ...(0, lodash_omit_1.default)(options, 'filter'),
136
137
  session: options?.session ?? this.getSession(),
137
- projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection),
138
+ projection,
138
139
  limit: undefined,
139
140
  skip: undefined,
140
141
  sort: undefined,
@@ -309,6 +310,36 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
309
310
  if (out)
310
311
  return outputCodec(out);
311
312
  }
313
+ /**
314
+ * Replaces a document with the given id in the collection
315
+ *
316
+ * @param {MongoEntityService.ReplaceCommand<T>} command
317
+ */
318
+ async _replace(command) {
319
+ const input = command.input;
320
+ (0, valgen_1.isNotNullish)(input, { label: 'input' });
321
+ (0, valgen_1.isNotNullish)(input._id, { label: 'input._id' });
322
+ const inputCodec = this._getInputCodec('replace');
323
+ const document = inputCodec(input);
324
+ const { options } = command;
325
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
326
+ mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
327
+ options?.filter,
328
+ ]);
329
+ const db = this.getDatabase();
330
+ const collection = await this.getCollection(db);
331
+ const out = await collection.findOneAndReplace(filter || {}, document, {
332
+ upsert: undefined,
333
+ ...options,
334
+ returnDocument: 'after',
335
+ includeResultMetadata: false,
336
+ session: options?.session ?? this.getSession(),
337
+ projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection),
338
+ });
339
+ const outputCodec = this._getOutputCodec('replace');
340
+ if (out)
341
+ return outputCodec(out);
342
+ }
312
343
  /**
313
344
  * Updates a document in the collection with the specified ID.
314
345
  *
@@ -382,36 +413,42 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
382
413
  /** Call before[X] hooks */
383
414
  if (command.crud === 'create')
384
415
  await this._beforeCreate(command);
385
- else if (command.crud === 'update' && command.byId) {
386
- await this._beforeUpdate(command);
387
- }
388
- else if (command.crud === 'update' && !command.byId) {
389
- await this._beforeUpdateMany(command);
390
- }
391
416
  else if (command.crud === 'delete' && command.byId) {
392
417
  await this._beforeDelete(command);
393
418
  }
394
419
  else if (command.crud === 'delete' && !command.byId) {
395
420
  await this._beforeDeleteMany(command);
396
421
  }
422
+ else if (command.crud === 'replace') {
423
+ await this._beforeReplace(command);
424
+ }
425
+ else if (command.crud === 'update' && command.byId) {
426
+ await this._beforeUpdate(command);
427
+ }
428
+ else if (command.crud === 'update' && !command.byId) {
429
+ await this._beforeUpdateMany(command);
430
+ }
397
431
  /** Call command function */
398
432
  return commandFn();
399
433
  });
400
434
  /** Call after[X] hooks */
401
435
  if (command.crud === 'create')
402
436
  await this._afterCreate(command, result);
403
- else if (command.crud === 'update' && command.byId) {
404
- await this._afterUpdate(command, result);
405
- }
406
- else if (command.crud === 'update' && !command.byId) {
407
- await this._afterUpdateMany(command, result);
408
- }
409
437
  else if (command.crud === 'delete' && command.byId) {
410
438
  await this._afterDelete(command, result);
411
439
  }
412
440
  else if (command.crud === 'delete' && !command.byId) {
413
441
  await this._afterDeleteMany(command, result);
414
442
  }
443
+ else if (command.crud === 'replace') {
444
+ await this._afterReplace(command, result);
445
+ }
446
+ else if (command.crud === 'update' && command.byId) {
447
+ await this._afterUpdate(command, result);
448
+ }
449
+ else if (command.crud === 'update' && !command.byId) {
450
+ await this._afterUpdateMany(command, result);
451
+ }
415
452
  return result;
416
453
  }
417
454
  catch (e) {
@@ -425,31 +462,31 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
425
462
  // Do nothing
426
463
  }
427
464
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
428
- async _beforeUpdate(command) {
465
+ async _beforeDelete(command) {
429
466
  // Do nothing
430
467
  }
431
468
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
432
- async _beforeUpdateMany(command) {
469
+ async _beforeDeleteMany(command) {
433
470
  // Do nothing
434
471
  }
435
472
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
436
- async _beforeDelete(command) {
473
+ async _beforeReplace(command) {
437
474
  // Do nothing
438
475
  }
439
476
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
440
- async _beforeDeleteMany(command) {
477
+ async _beforeUpdate(command) {
441
478
  // Do nothing
442
479
  }
443
480
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
444
- async _afterCreate(command, result) {
481
+ async _beforeUpdateMany(command) {
445
482
  // Do nothing
446
483
  }
447
484
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
448
- async _afterUpdate(command, result) {
485
+ async _afterCreate(command, result) {
449
486
  // Do nothing
450
487
  }
451
488
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
452
- async _afterUpdateMany(command, affected) {
489
+ async _afterReplace(command, result) {
453
490
  // Do nothing
454
491
  }
455
492
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -460,5 +497,13 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
460
497
  async _afterDeleteMany(command, affected) {
461
498
  // Do nothing
462
499
  }
500
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
501
+ async _afterUpdate(command, result) {
502
+ // Do nothing
503
+ }
504
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
505
+ async _afterUpdateMany(command, affected) {
506
+ // Do nothing
507
+ }
463
508
  }
464
509
  exports.MongoEntityService = MongoEntityService;
@@ -1,5 +1,7 @@
1
1
  import { ComplexType, parseFieldsProjection } from '@opra/common';
2
2
  export default function prepareProjection(dataType, projection) {
3
+ if (projection === '*')
4
+ return undefined;
3
5
  if (projection && typeof projection === 'object' && !Array.isArray(projection))
4
6
  return projection;
5
7
  const out = {};
@@ -60,6 +60,16 @@ export var MongoAdapter;
60
60
  };
61
61
  return { method: 'get', key, options };
62
62
  }
63
+ case 'Entity.Replace': {
64
+ const data = await ctx.getBody();
65
+ const keyParam = operation.parameters.find(p => p.keyParam) || controller.parameters.find(p => p.keyParam);
66
+ const key = keyParam && ctx.pathParams[String(keyParam.name)];
67
+ const options = {
68
+ projection: ctx.queryParams.projection,
69
+ filter: ctx.queryParams.filter,
70
+ };
71
+ return { method: 'replace', key, data, options };
72
+ }
63
73
  case 'Entity.Update': {
64
74
  const data = await ctx.getBody();
65
75
  const keyParam = operation.parameters.find(p => p.keyParam) || controller.parameters.find(p => p.keyParam);
@@ -70,8 +70,11 @@ export class MongoCollectionService extends MongoEntityService {
70
70
  options,
71
71
  };
72
72
  return this._executeCommand(command, async () => {
73
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
74
- command.options = { ...command.options, filter };
73
+ const documentFilter = await this._getDocumentFilter(command);
74
+ if (documentFilter) {
75
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
76
+ command.options = { ...command.options, filter };
77
+ }
75
78
  return this._count(command);
76
79
  });
77
80
  }
@@ -91,8 +94,11 @@ export class MongoCollectionService extends MongoEntityService {
91
94
  options,
92
95
  };
93
96
  return this._executeCommand(command, async () => {
94
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
95
- command.options = { ...command.options, filter };
97
+ const documentFilter = await this._getDocumentFilter(command);
98
+ if (documentFilter) {
99
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
100
+ command.options = { ...command.options, filter };
101
+ }
96
102
  return this._delete(command);
97
103
  });
98
104
  }
@@ -110,8 +116,11 @@ export class MongoCollectionService extends MongoEntityService {
110
116
  options,
111
117
  };
112
118
  return this._executeCommand(command, async () => {
113
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
114
- command.options = { ...command.options, filter };
119
+ const documentFilter = await this._getDocumentFilter(command);
120
+ if (documentFilter) {
121
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
122
+ command.options = { ...command.options, filter };
123
+ }
115
124
  return this._deleteMany(command);
116
125
  });
117
126
  }
@@ -130,8 +139,11 @@ export class MongoCollectionService extends MongoEntityService {
130
139
  options,
131
140
  };
132
141
  return this._executeCommand(command, async () => {
133
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
134
- command.options = { ...command.options, filter };
142
+ const documentFilter = await this._getDocumentFilter(command);
143
+ if (documentFilter) {
144
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
145
+ command.options = { ...command.options, filter };
146
+ }
135
147
  return this._distinct(command);
136
148
  });
137
149
  }
@@ -151,10 +163,12 @@ export class MongoCollectionService extends MongoEntityService {
151
163
  options,
152
164
  };
153
165
  return this._executeCommand(command, async () => {
154
- const documentFilter = await this._getDocumentFilter(command);
155
- const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
156
166
  const findCommand = command;
157
- findCommand.options = { ...command.options, filter, projection: ['_id'] };
167
+ const documentFilter = await this._getDocumentFilter(command);
168
+ if (documentFilter) {
169
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
170
+ findCommand.options = { ...command.options, filter, projection: ['_id'] };
171
+ }
158
172
  return !!(await this._findById(findCommand));
159
173
  });
160
174
  }
@@ -177,8 +191,10 @@ export class MongoCollectionService extends MongoEntityService {
177
191
  };
178
192
  return this._executeCommand(command, async () => {
179
193
  const documentFilter = await this._getDocumentFilter(command);
180
- const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
181
- command.options = { ...command.options, filter };
194
+ if (documentFilter) {
195
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
196
+ command.options = { ...command.options, filter };
197
+ }
182
198
  return this._findById(command);
183
199
  });
184
200
  }
@@ -190,8 +206,11 @@ export class MongoCollectionService extends MongoEntityService {
190
206
  options,
191
207
  };
192
208
  return this._executeCommand(command, async () => {
193
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
194
- command.options = { ...command.options, filter };
209
+ const documentFilter = await this._getDocumentFilter(command);
210
+ if (documentFilter) {
211
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
212
+ command.options = { ...command.options, filter };
213
+ }
195
214
  return this._findOne(command);
196
215
  });
197
216
  }
@@ -203,9 +222,14 @@ export class MongoCollectionService extends MongoEntityService {
203
222
  options,
204
223
  };
205
224
  return this._executeCommand(command, async () => {
206
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
225
+ const documentFilter = await this._getDocumentFilter(command);
226
+ command.options = command.options || {};
227
+ if (documentFilter) {
228
+ command.options.filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
229
+ }
207
230
  const limit = command.options?.limit || this.defaultLimit;
208
- command.options = { ...command.options, filter, limit };
231
+ if (limit)
232
+ command.options.limit = limit;
209
233
  return this._findMany(command);
210
234
  });
211
235
  }
@@ -217,8 +241,14 @@ export class MongoCollectionService extends MongoEntityService {
217
241
  options,
218
242
  };
219
243
  return this._executeCommand(command, async () => {
220
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
221
- command.options = { ...command.options, filter, limit: command.options?.limit || this.defaultLimit };
244
+ const documentFilter = await this._getDocumentFilter(command);
245
+ command.options = command.options || {};
246
+ if (documentFilter) {
247
+ command.options.filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
248
+ }
249
+ const limit = command.options?.limit || this.defaultLimit;
250
+ if (limit)
251
+ command.options.limit = limit;
222
252
  return this._findManyWithCount(command);
223
253
  });
224
254
  }
@@ -228,6 +258,25 @@ export class MongoCollectionService extends MongoEntityService {
228
258
  throw new ResourceNotAvailableError(this.getResourceName(), id);
229
259
  return out;
230
260
  }
261
+ async replace(id, input, options) {
262
+ const command = {
263
+ crud: 'replace',
264
+ method: 'replace',
265
+ documentId: id,
266
+ byId: true,
267
+ input,
268
+ options,
269
+ };
270
+ input._id = id;
271
+ return this._executeCommand(command, async () => {
272
+ const documentFilter = await this._getDocumentFilter(command);
273
+ if (documentFilter) {
274
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
275
+ command.options = { ...command.options, filter };
276
+ }
277
+ return await this._replace(command);
278
+ });
279
+ }
231
280
  async update(id, input, options) {
232
281
  const isUpdateFilter = Array.isArray(input) || !!Object.keys(input).find(x => x.startsWith('$'));
233
282
  const command = {
@@ -240,8 +289,11 @@ export class MongoCollectionService extends MongoEntityService {
240
289
  options,
241
290
  };
242
291
  return this._executeCommand(command, async () => {
243
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
244
- command.options = { ...command.options, filter };
292
+ const documentFilter = await this._getDocumentFilter(command);
293
+ if (documentFilter) {
294
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
295
+ command.options = { ...command.options, filter };
296
+ }
245
297
  return this._update(command);
246
298
  });
247
299
  }
@@ -265,8 +317,11 @@ export class MongoCollectionService extends MongoEntityService {
265
317
  options,
266
318
  };
267
319
  return this._executeCommand(command, async () => {
268
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
269
- command.options = { ...command.options, filter };
320
+ const documentFilter = await this._getDocumentFilter(command);
321
+ if (documentFilter) {
322
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
323
+ command.options = { ...command.options, filter };
324
+ }
270
325
  return this._updateOnly(command);
271
326
  });
272
327
  }
@@ -288,8 +343,11 @@ export class MongoCollectionService extends MongoEntityService {
288
343
  options,
289
344
  };
290
345
  return this._executeCommand(command, async () => {
291
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
292
- command.options = { ...command.options, filter };
346
+ const documentFilter = await this._getDocumentFilter(command);
347
+ if (documentFilter) {
348
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
349
+ command.options = { ...command.options, filter };
350
+ }
293
351
  return this._updateMany(command);
294
352
  });
295
353
  }
@@ -127,10 +127,11 @@ export class MongoEntityService extends MongoService {
127
127
  const { options } = command;
128
128
  const db = this.getDatabase();
129
129
  const collection = await this.getCollection(db);
130
+ const projection = MongoAdapter.prepareProjection(this.dataType, options?.projection);
130
131
  const out = await collection.findOne(filter || {}, {
131
132
  ...omit(options, 'filter'),
132
133
  session: options?.session ?? this.getSession(),
133
- projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
134
+ projection,
134
135
  limit: undefined,
135
136
  skip: undefined,
136
137
  sort: undefined,
@@ -305,6 +306,36 @@ export class MongoEntityService extends MongoService {
305
306
  if (out)
306
307
  return outputCodec(out);
307
308
  }
309
+ /**
310
+ * Replaces a document with the given id in the collection
311
+ *
312
+ * @param {MongoEntityService.ReplaceCommand<T>} command
313
+ */
314
+ async _replace(command) {
315
+ const input = command.input;
316
+ isNotNullish(input, { label: 'input' });
317
+ isNotNullish(input._id, { label: 'input._id' });
318
+ const inputCodec = this._getInputCodec('replace');
319
+ const document = inputCodec(input);
320
+ const { options } = command;
321
+ const filter = MongoAdapter.prepareFilter([
322
+ MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
323
+ options?.filter,
324
+ ]);
325
+ const db = this.getDatabase();
326
+ const collection = await this.getCollection(db);
327
+ const out = await collection.findOneAndReplace(filter || {}, document, {
328
+ upsert: undefined,
329
+ ...options,
330
+ returnDocument: 'after',
331
+ includeResultMetadata: false,
332
+ session: options?.session ?? this.getSession(),
333
+ projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
334
+ });
335
+ const outputCodec = this._getOutputCodec('replace');
336
+ if (out)
337
+ return outputCodec(out);
338
+ }
308
339
  /**
309
340
  * Updates a document in the collection with the specified ID.
310
341
  *
@@ -378,36 +409,42 @@ export class MongoEntityService extends MongoService {
378
409
  /** Call before[X] hooks */
379
410
  if (command.crud === 'create')
380
411
  await this._beforeCreate(command);
381
- else if (command.crud === 'update' && command.byId) {
382
- await this._beforeUpdate(command);
383
- }
384
- else if (command.crud === 'update' && !command.byId) {
385
- await this._beforeUpdateMany(command);
386
- }
387
412
  else if (command.crud === 'delete' && command.byId) {
388
413
  await this._beforeDelete(command);
389
414
  }
390
415
  else if (command.crud === 'delete' && !command.byId) {
391
416
  await this._beforeDeleteMany(command);
392
417
  }
418
+ else if (command.crud === 'replace') {
419
+ await this._beforeReplace(command);
420
+ }
421
+ else if (command.crud === 'update' && command.byId) {
422
+ await this._beforeUpdate(command);
423
+ }
424
+ else if (command.crud === 'update' && !command.byId) {
425
+ await this._beforeUpdateMany(command);
426
+ }
393
427
  /** Call command function */
394
428
  return commandFn();
395
429
  });
396
430
  /** Call after[X] hooks */
397
431
  if (command.crud === 'create')
398
432
  await this._afterCreate(command, result);
399
- else if (command.crud === 'update' && command.byId) {
400
- await this._afterUpdate(command, result);
401
- }
402
- else if (command.crud === 'update' && !command.byId) {
403
- await this._afterUpdateMany(command, result);
404
- }
405
433
  else if (command.crud === 'delete' && command.byId) {
406
434
  await this._afterDelete(command, result);
407
435
  }
408
436
  else if (command.crud === 'delete' && !command.byId) {
409
437
  await this._afterDeleteMany(command, result);
410
438
  }
439
+ else if (command.crud === 'replace') {
440
+ await this._afterReplace(command, result);
441
+ }
442
+ else if (command.crud === 'update' && command.byId) {
443
+ await this._afterUpdate(command, result);
444
+ }
445
+ else if (command.crud === 'update' && !command.byId) {
446
+ await this._afterUpdateMany(command, result);
447
+ }
411
448
  return result;
412
449
  }
413
450
  catch (e) {
@@ -421,31 +458,31 @@ export class MongoEntityService extends MongoService {
421
458
  // Do nothing
422
459
  }
423
460
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
424
- async _beforeUpdate(command) {
461
+ async _beforeDelete(command) {
425
462
  // Do nothing
426
463
  }
427
464
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
428
- async _beforeUpdateMany(command) {
465
+ async _beforeDeleteMany(command) {
429
466
  // Do nothing
430
467
  }
431
468
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
432
- async _beforeDelete(command) {
469
+ async _beforeReplace(command) {
433
470
  // Do nothing
434
471
  }
435
472
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
436
- async _beforeDeleteMany(command) {
473
+ async _beforeUpdate(command) {
437
474
  // Do nothing
438
475
  }
439
476
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
440
- async _afterCreate(command, result) {
477
+ async _beforeUpdateMany(command) {
441
478
  // Do nothing
442
479
  }
443
480
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
444
- async _afterUpdate(command, result) {
481
+ async _afterCreate(command, result) {
445
482
  // Do nothing
446
483
  }
447
484
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
448
- async _afterUpdateMany(command, affected) {
485
+ async _afterReplace(command, result) {
449
486
  // Do nothing
450
487
  }
451
488
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -456,4 +493,12 @@ export class MongoEntityService extends MongoService {
456
493
  async _afterDeleteMany(command, affected) {
457
494
  // Do nothing
458
495
  }
496
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
497
+ async _afterUpdate(command, result) {
498
+ // Do nothing
499
+ }
500
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
501
+ async _afterUpdateMany(command, affected) {
502
+ // Do nothing
503
+ }
459
504
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/mongodb",
3
- "version": "1.0.10",
3
+ "version": "1.1.1",
4
4
  "description": "Opra MongoDB adapter package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -11,9 +11,9 @@
11
11
  "valgen": "^5.12.0"
12
12
  },
13
13
  "peerDependencies": {
14
- "@opra/common": "^1.0.10",
15
- "@opra/core": "^1.0.10",
16
- "@opra/http": "^1.0.10",
14
+ "@opra/common": "^1.1.1",
15
+ "@opra/core": "^1.1.1",
16
+ "@opra/http": "^1.1.1",
17
17
  "mongodb": ">= 6.0.0"
18
18
  },
19
19
  "type": "module",
@@ -1,4 +1,4 @@
1
1
  import { ComplexType, FieldsProjection } from '@opra/common';
2
2
  import mongodb, { type Document } from 'mongodb';
3
- export default function prepareProjection(dataType: ComplexType, projection?: string | string[] | Document): mongodb.Document | undefined;
3
+ export default function prepareProjection(dataType: ComplexType, projection?: string | string[] | Document | '*'): mongodb.Document | undefined;
4
4
  export declare function prepare(dataType: ComplexType, target: mongodb.Document, projection?: FieldsProjection): void;
@@ -15,7 +15,7 @@ export declare namespace MongoAdapter {
15
15
  const prepareProjection: typeof _prepareProjection;
16
16
  const prepareSort: typeof _prepareSort;
17
17
  interface TransformedRequest {
18
- method: 'create' | 'delete' | 'deleteMany' | 'get' | 'findMany' | 'update' | 'updateMany';
18
+ method: 'create' | 'delete' | 'deleteMany' | 'get' | 'findMany' | 'replace' | 'update' | 'updateMany';
19
19
  key?: any;
20
20
  data?: any;
21
21
  options: any;
@@ -152,6 +152,18 @@ export declare class MongoCollectionService<T extends mongodb.Document> extends
152
152
  */
153
153
  get(id: MongoAdapter.AnyId, options: RequiredSome<MongoEntityService.FindOneOptions<T>, 'projection'>): Promise<PartialDTO<T>>;
154
154
  get(id: MongoAdapter.AnyId, options?: MongoEntityService.FindOneOptions<T>): Promise<T>;
155
+ /**
156
+ * Replace a document in the MongoDB collection.
157
+ * Interceptors will be called before performing db operation
158
+ *
159
+ * @param {MongoAdapter.AnyId} id - The id of the document to replace.
160
+ * @param {PartialDTO<T>} input - The input data
161
+ * @param {MongoEntityService.ReplaceOptions} [options] - The options for replacing the document.
162
+ * @returns {Promise<PartialDTO<T>>} A promise that resolves to the replaced document.
163
+ * @throws {Error} if an unknown error occurs while replacing the document.
164
+ */
165
+ replace(id: MongoAdapter.AnyId, input: PartialDTO<T>, options: RequiredSome<MongoEntityService.ReplaceOptions<T>, 'projection'>): Promise<PartialDTO<T>>;
166
+ replace(id: MongoAdapter.AnyId, input: PartialDTO<T>, options?: MongoEntityService.CreateOptions): Promise<T>;
155
167
  /**
156
168
  * Updates a document with the given id in the collection.
157
169
  *
@@ -32,6 +32,8 @@ export declare namespace MongoEntityService {
32
32
  }
33
33
  interface FindManyOptions<T> extends MongoService.FindManyOptions<T> {
34
34
  }
35
+ interface ReplaceOptions<T> extends MongoService.ReplaceOptions<T> {
36
+ }
35
37
  interface UpdateOneOptions<T> extends MongoService.UpdateOneOptions<T> {
36
38
  }
37
39
  interface UpdateManyOptions<T> extends MongoService.UpdateManyOptions<T> {
@@ -78,6 +80,11 @@ export declare namespace MongoEntityService {
78
80
  inputRaw?: mongodb.UpdateFilter<T>;
79
81
  options?: UpdateManyOptions<T>;
80
82
  }
83
+ interface ReplaceCommand<T> extends StrictOmit<CommandInfo, 'nestedId'> {
84
+ crud: 'replace';
85
+ input: PartialDTO<T>;
86
+ options?: ReplaceOptions<T>;
87
+ }
81
88
  }
82
89
  /**
83
90
  * @class MongoEntityService
@@ -161,6 +168,12 @@ export declare class MongoEntityService<T extends mongodb.Document> extends Mong
161
168
  * @param {MongoEntityService.UpdateOneCommand<T>} command
162
169
  */
163
170
  protected _update(command: MongoEntityService.UpdateOneCommand<T>): Promise<PartialDTO<T> | undefined>;
171
+ /**
172
+ * Replaces a document with the given id in the collection
173
+ *
174
+ * @param {MongoEntityService.ReplaceCommand<T>} command
175
+ */
176
+ protected _replace(command: MongoEntityService.ReplaceCommand<T>): Promise<PartialDTO<T> | undefined>;
164
177
  /**
165
178
  * Updates a document in the collection with the specified ID.
166
179
  *
@@ -175,13 +188,15 @@ export declare class MongoEntityService<T extends mongodb.Document> extends Mong
175
188
  protected _updateMany(command: MongoEntityService.UpdateManyCommand<T>): Promise<number>;
176
189
  protected _executeCommand(command: MongoEntityService.CommandInfo, commandFn: () => any): Promise<any>;
177
190
  protected _beforeCreate(command: MongoEntityService.CreateCommand<T>): Promise<void>;
178
- protected _beforeUpdate(command: MongoEntityService.UpdateOneCommand<T>): Promise<void>;
179
- protected _beforeUpdateMany(command: MongoEntityService.UpdateManyCommand<T>): Promise<void>;
180
191
  protected _beforeDelete(command: MongoEntityService.DeleteCommand<T>): Promise<void>;
181
192
  protected _beforeDeleteMany(command: MongoEntityService.DeleteCommand<T>): Promise<void>;
193
+ protected _beforeReplace(command: MongoEntityService.ReplaceCommand<T>): Promise<void>;
194
+ protected _beforeUpdate(command: MongoEntityService.UpdateOneCommand<T>): Promise<void>;
195
+ protected _beforeUpdateMany(command: MongoEntityService.UpdateManyCommand<T>): Promise<void>;
182
196
  protected _afterCreate(command: MongoEntityService.CreateCommand<T>, result: PartialDTO<T>): Promise<void>;
183
- protected _afterUpdate(command: MongoEntityService.UpdateOneCommand<T>, result?: PartialDTO<T>): Promise<void>;
184
- protected _afterUpdateMany(command: MongoEntityService.UpdateManyCommand<T>, affected: number): Promise<void>;
197
+ protected _afterReplace(command: MongoEntityService.ReplaceCommand<T>, result: PartialDTO<T>): Promise<void>;
185
198
  protected _afterDelete(command: MongoEntityService.DeleteCommand<T>, affected: number): Promise<void>;
186
199
  protected _afterDeleteMany(command: MongoEntityService.DeleteCommand<T>, affected: number): Promise<void>;
200
+ protected _afterUpdate(command: MongoEntityService.UpdateOneCommand<T>, result?: PartialDTO<T>): Promise<void>;
201
+ protected _afterUpdateMany(command: MongoEntityService.UpdateManyCommand<T>, affected: number): Promise<void>;
187
202
  }
@@ -20,7 +20,7 @@ export declare namespace MongoService {
20
20
  idGenerator?: MongoService<any>['idGenerator'];
21
21
  onError?: MongoService<any>['onError'];
22
22
  }
23
- type CrudOp = 'create' | 'read' | 'update' | 'delete';
23
+ type CrudOp = 'create' | 'read' | 'replace' | 'update' | 'delete';
24
24
  interface CommandInfo {
25
25
  crud: CrudOp;
26
26
  method: string;
@@ -37,7 +37,7 @@ export declare namespace MongoService {
37
37
  * @interface
38
38
  */
39
39
  interface CreateOptions extends mongodb.InsertOneOptions {
40
- projection?: string[];
40
+ projection?: string | string[] | Document | '*';
41
41
  }
42
42
  /**
43
43
  * Represents options for "count" operation
@@ -99,11 +99,20 @@ export declare namespace MongoService {
99
99
  */
100
100
  interface FindManyOptions<T> extends mongodb.AggregateOptions {
101
101
  filter?: MongoAdapter.FilterInput<T>;
102
- projection?: string | string[] | Document;
102
+ projection?: string | string[] | Document | '*';
103
103
  sort?: string[];
104
104
  limit?: number;
105
105
  skip?: number;
106
106
  }
107
+ /**
108
+ * Represents options for "replace" operation
109
+ *
110
+ * @interface
111
+ */
112
+ interface ReplaceOptions<T> extends StrictOmit<mongodb.FindOneAndReplaceOptions, 'projection'> {
113
+ projection?: string | string[] | Document | '*';
114
+ filter?: MongoAdapter.FilterInput<T>;
115
+ }
107
116
  /**
108
117
  * Represents options for "update" operation
109
118
  *
@@ -111,7 +120,7 @@ export declare namespace MongoService {
111
120
  * @template T - The type of the document.
112
121
  */
113
122
  interface UpdateOneOptions<T> extends StrictOmit<mongodb.FindOneAndUpdateOptions, 'projection' | 'returnDocument' | 'includeResultMetadata'> {
114
- projection?: string | string[] | Document;
123
+ projection?: string | string[] | Document | '*';
115
124
  filter?: MongoAdapter.FilterInput<T>;
116
125
  }
117
126
  /**