@opra/mongodb 1.0.0-alpha.2 → 1.0.0-alpha.21

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.
@@ -1,5 +1,6 @@
1
- import omit from 'lodash.omit';
2
1
  import { ComplexType, NotAcceptableError, ResourceNotAvailableError } from '@opra/common';
2
+ import omit from 'lodash.omit';
3
+ import { isNotNullish } from 'valgen';
3
4
  import { MongoAdapter } from './mongo-adapter.js';
4
5
  import { MongoService } from './mongo-service.js';
5
6
  /**
@@ -21,7 +22,19 @@ export class MongoNestedService extends MongoService {
21
22
  this.fieldName = fieldName;
22
23
  this.nestedKey = options?.nestedKey || '_id';
23
24
  this.defaultLimit = options?.defaultLimit || 10;
24
- this.$nestedFilter = options?.$nestedFilter;
25
+ this.nestedFilter = options?.nestedFilter;
26
+ }
27
+ /**
28
+ * Retrieves the data type of the array field
29
+ *
30
+ * @returns {ComplexType} The complex data type of the field.
31
+ * @throws {NotAcceptableError} If the data type is not a ComplexType.
32
+ */
33
+ get dataType() {
34
+ const t = super.dataType.getField(this.fieldName).type;
35
+ if (!(t instanceof ComplexType))
36
+ throw new NotAcceptableError(`Data type "${t.name}" is not a ComplexType`);
37
+ return t;
25
38
  }
26
39
  /**
27
40
  * Asserts whether a resource with the specified parentId and id exists.
@@ -34,8 +47,9 @@ export class MongoNestedService extends MongoService {
34
47
  * @throws {ResourceNotAvailableError} - If the resource does not exist.
35
48
  */
36
49
  async assert(documentId, id, options) {
37
- if (!(await this.exists(documentId, id, options)))
50
+ if (!(await this.exists(documentId, id, options))) {
38
51
  throw new ResourceNotAvailableError(this.getResourceName() + '.' + this.nestedKey, documentId + '/' + id);
52
+ }
39
53
  }
40
54
  /**
41
55
  * Adds a single item into the array field.
@@ -47,24 +61,21 @@ export class MongoNestedService extends MongoService {
47
61
  * @throws {ResourceNotAvailableError} - If the parent document is not found.
48
62
  */
49
63
  async create(documentId, input, options) {
50
- const id = input._id || this._generateId();
51
- if (id != null)
52
- input._id = id;
53
- const info = {
64
+ const command = {
54
65
  crud: 'create',
55
66
  method: 'create',
56
67
  byId: false,
57
68
  documentId,
58
- nestedId: id,
59
69
  input,
60
70
  options,
61
71
  };
62
- return this._intercept(() => this._create(documentId, input, options), info);
72
+ return this._executeCommand(command, () => this._create(command));
63
73
  }
64
- async _create(documentId, input, options) {
65
- const encode = this.getEncoder('create');
66
- const doc = encode(input);
67
- doc._id = doc._id || this._generateId();
74
+ async _create(command) {
75
+ const inputCodec = this.getInputCodec('create');
76
+ const { documentId, options } = command;
77
+ const doc = inputCodec(command.input);
78
+ doc._id = doc._id || this._generateId(command);
68
79
  const docFilter = MongoAdapter.prepareKeyValues(documentId, ['_id']);
69
80
  const r = await this._dbUpdateOne(docFilter, {
70
81
  $push: { [this.fieldName]: doc },
@@ -72,12 +83,20 @@ export class MongoNestedService extends MongoService {
72
83
  if (r.matchedCount) {
73
84
  if (!options)
74
85
  return doc;
75
- const id = doc[this.nestedKey];
76
- const out = await this._findById(documentId, id, {
77
- ...options,
78
- filter: undefined,
79
- skip: undefined,
80
- });
86
+ const findCommand = {
87
+ crud: 'read',
88
+ method: 'findById',
89
+ byId: true,
90
+ documentId,
91
+ nestedId: doc[this.nestedKey],
92
+ options: {
93
+ ...options,
94
+ sort: undefined,
95
+ filter: undefined,
96
+ skip: undefined,
97
+ },
98
+ };
99
+ const out = await this._findById(findCommand);
81
100
  if (out)
82
101
  return out;
83
102
  }
@@ -91,20 +110,22 @@ export class MongoNestedService extends MongoService {
91
110
  * @returns {Promise<number>} - A promise that resolves to the count of documents.
92
111
  */
93
112
  async count(documentId, options) {
94
- const info = {
113
+ const command = {
95
114
  crud: 'read',
96
115
  method: 'count',
97
116
  byId: false,
98
117
  documentId,
99
118
  options,
100
119
  };
101
- return this._intercept(async () => {
102
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
103
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
104
- return this._count(documentId, { ...options, filter, documentFilter });
105
- }, info);
120
+ return this._executeCommand(command, async () => {
121
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
122
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
123
+ command.options = { ...command.options, filter, documentFilter };
124
+ return this._count(command);
125
+ });
106
126
  }
107
- async _count(documentId, options) {
127
+ async _count(command) {
128
+ const { documentId, options } = command;
108
129
  const matchFilter = MongoAdapter.prepareFilter([
109
130
  MongoAdapter.prepareKeyValues(documentId, ['_id']),
110
131
  options?.documentFilter,
@@ -137,7 +158,7 @@ export class MongoNestedService extends MongoService {
137
158
  * @return {Promise<number>} - A Promise that resolves to the number of elements deleted (1 if successful, 0 if not).
138
159
  */
139
160
  async delete(documentId, nestedId, options) {
140
- const info = {
161
+ const command = {
141
162
  crud: 'delete',
142
163
  method: 'delete',
143
164
  byId: true,
@@ -145,13 +166,17 @@ export class MongoNestedService extends MongoService {
145
166
  nestedId,
146
167
  options,
147
168
  };
148
- return this._intercept(async () => {
149
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
150
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
151
- return this._delete(documentId, nestedId, { ...options, filter, documentFilter });
152
- }, info);
169
+ return this._executeCommand(command, async () => {
170
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
171
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
172
+ command.options = { ...command.options, filter, documentFilter };
173
+ return this._delete(command);
174
+ });
153
175
  }
154
- async _delete(documentId, nestedId, options) {
176
+ async _delete(command) {
177
+ const { documentId, nestedId, options } = command;
178
+ isNotNullish(documentId, { label: 'documentId' });
179
+ isNotNullish(documentId, { label: 'nestedId' });
155
180
  const matchFilter = MongoAdapter.prepareFilter([
156
181
  MongoAdapter.prepareKeyValues(documentId, ['_id']),
157
182
  options?.documentFilter,
@@ -170,20 +195,22 @@ export class MongoNestedService extends MongoService {
170
195
  * @returns {Promise<number>} - A Promise that resolves to the number of items deleted.
171
196
  */
172
197
  async deleteMany(documentId, options) {
173
- const info = {
198
+ const command = {
174
199
  crud: 'delete',
175
200
  method: 'deleteMany',
176
201
  byId: false,
177
202
  documentId,
178
203
  options,
179
204
  };
180
- return this._intercept(async () => {
181
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
182
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
183
- return this._deleteMany(documentId, { ...options, filter, documentFilter });
184
- }, info);
205
+ return this._executeCommand(command, async () => {
206
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
207
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
208
+ command.options = { ...command.options, filter, documentFilter };
209
+ return this._deleteMany(command);
210
+ });
185
211
  }
186
- async _deleteMany(documentId, options) {
212
+ async _deleteMany(command) {
213
+ const { documentId, options } = command;
187
214
  const matchFilter = MongoAdapter.prepareFilter([
188
215
  MongoAdapter.prepareKeyValues(documentId, ['_id']),
189
216
  options?.documentFilter,
@@ -207,7 +234,24 @@ export class MongoNestedService extends MongoService {
207
234
  * @returns {Promise<boolean>} - A promise that resolves to a boolean indicating if the record exists or not.
208
235
  */
209
236
  async exists(documentId, nestedId, options) {
210
- return !!(await this.findById(documentId, nestedId, { ...options, projection: ['_id'] }));
237
+ const command = {
238
+ crud: 'read',
239
+ method: 'exists',
240
+ byId: true,
241
+ documentId,
242
+ nestedId,
243
+ options,
244
+ };
245
+ return this._executeCommand(command, async () => {
246
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
247
+ const filter = MongoAdapter.prepareFilter([
248
+ await this._getNestedFilter(command),
249
+ documentFilter,
250
+ command.options?.filter,
251
+ ]);
252
+ command.options = { ...command.options, filter };
253
+ return !!(await this._findById(command));
254
+ });
211
255
  }
212
256
  /**
213
257
  * Checks if an object with the given arguments exists.
@@ -217,7 +261,20 @@ export class MongoNestedService extends MongoService {
217
261
  * @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
218
262
  */
219
263
  async existsOne(documentId, options) {
220
- return !!(await this.findOne(documentId, { ...options, projection: ['_id'] }));
264
+ const command = {
265
+ crud: 'read',
266
+ method: 'exists',
267
+ byId: false,
268
+ documentId,
269
+ options,
270
+ };
271
+ return this._executeCommand(command, async () => {
272
+ const documentFilter = await this._getDocumentFilter(command);
273
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
274
+ const findCommand = command;
275
+ findCommand.options = { ...command.options, filter, documentFilter, projection: ['_id'] };
276
+ return !!(await this._findOne(findCommand));
277
+ });
221
278
  }
222
279
  /**
223
280
  * Finds an element in array field by its parent ID and ID.
@@ -228,7 +285,7 @@ export class MongoNestedService extends MongoService {
228
285
  * @returns {Promise<PartialDTO<T> | undefined>} - A promise that resolves to the found document or undefined if not found.
229
286
  */
230
287
  async findById(documentId, nestedId, options) {
231
- const info = {
288
+ const command = {
232
289
  crud: 'read',
233
290
  method: 'findById',
234
291
  byId: true,
@@ -236,24 +293,32 @@ export class MongoNestedService extends MongoService {
236
293
  nestedId,
237
294
  options,
238
295
  };
239
- return this._intercept(async () => {
240
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
241
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
242
- return this._findById(documentId, nestedId, { ...options, filter, documentFilter });
243
- }, info);
296
+ return this._executeCommand(command, async () => {
297
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
298
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
299
+ command.options = { ...command.options, filter, documentFilter };
300
+ return this._findById(command);
301
+ });
244
302
  }
245
- async _findById(documentId, nestedId, options) {
303
+ async _findById(command) {
304
+ const { documentId, nestedId, options } = command;
305
+ isNotNullish(documentId, { label: 'documentId' });
306
+ isNotNullish(nestedId, { label: 'nestedId' });
246
307
  const filter = MongoAdapter.prepareFilter([
247
308
  MongoAdapter.prepareKeyValues(nestedId, [this.nestedKey]),
248
309
  options?.filter,
249
310
  ]);
250
- const rows = await this._findMany(documentId, {
251
- ...options,
252
- filter,
253
- limit: 1,
254
- skip: undefined,
255
- sort: undefined,
256
- });
311
+ const findManyCommand = {
312
+ ...command,
313
+ options: {
314
+ ...options,
315
+ filter,
316
+ limit: 1,
317
+ skip: undefined,
318
+ sort: undefined,
319
+ },
320
+ };
321
+ const rows = await this._findMany(findManyCommand);
257
322
  return rows?.[0];
258
323
  }
259
324
  /**
@@ -264,24 +329,31 @@ export class MongoNestedService extends MongoService {
264
329
  * @returns {Promise<PartialDTO<T> | undefined>} A promise that resolves to the first matching document, or `undefined` if no match is found.
265
330
  */
266
331
  async findOne(documentId, options) {
267
- const info = {
332
+ const command = {
268
333
  crud: 'read',
269
334
  method: 'findOne',
270
335
  byId: false,
271
336
  documentId,
272
337
  options,
273
338
  };
274
- return this._intercept(async () => {
275
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
276
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
277
- return this._findOne(documentId, { ...options, filter, documentFilter });
278
- }, info);
279
- }
280
- async _findOne(documentId, options) {
281
- const rows = await this._findMany(documentId, {
282
- ...options,
283
- limit: 1,
339
+ return this._executeCommand(command, async () => {
340
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
341
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
342
+ command.options = { ...command.options, filter, documentFilter };
343
+ return this._findOne(command);
284
344
  });
345
+ }
346
+ async _findOne(command) {
347
+ const { documentId, options } = command;
348
+ isNotNullish(documentId, { label: 'documentId' });
349
+ const findManyCommand = {
350
+ ...command,
351
+ options: {
352
+ ...options,
353
+ limit: 1,
354
+ },
355
+ };
356
+ const rows = await this._findMany(findManyCommand);
285
357
  return rows?.[0];
286
358
  }
287
359
  /**
@@ -292,28 +364,31 @@ export class MongoNestedService extends MongoService {
292
364
  * @returns {Promise<PartialDTO<T>[]>} - The found documents.
293
365
  */
294
366
  async findMany(documentId, options) {
295
- const args = {
367
+ const command = {
296
368
  crud: 'read',
297
369
  method: 'findMany',
298
370
  byId: false,
299
371
  documentId,
300
372
  options,
301
373
  };
302
- return this._intercept(async () => {
303
- const documentFilter = await this._getDocumentFilter(args);
304
- const nestedFilter = await this._getNestedFilter(args);
305
- return this._findMany(documentId, {
306
- ...options,
307
- documentFilter,
374
+ return this._executeCommand(command, async () => {
375
+ const documentFilter = await this._getDocumentFilter(command);
376
+ const nestedFilter = await this._getNestedFilter(command);
377
+ command.options = {
378
+ ...command.options,
308
379
  nestedFilter,
309
- limit: options?.limit || this.defaultLimit,
310
- });
311
- }, args);
380
+ documentFilter,
381
+ limit: command.options?.limit || this.defaultLimit,
382
+ };
383
+ return this._findMany(command);
384
+ });
312
385
  }
313
- async _findMany(documentId, options) {
386
+ async _findMany(command) {
387
+ const { documentId, options } = command;
388
+ isNotNullish(documentId, { label: 'documentId' });
314
389
  const matchFilter = MongoAdapter.prepareFilter([
315
390
  MongoAdapter.prepareKeyValues(documentId, ['_id']),
316
- options.documentFilter,
391
+ options?.documentFilter,
317
392
  ]);
318
393
  const mongoOptions = {
319
394
  ...omit(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
@@ -324,7 +399,7 @@ export class MongoNestedService extends MongoService {
324
399
  { $unwind: { path: '$' + this.fieldName } },
325
400
  { $replaceRoot: { newRoot: '$' + this.fieldName } },
326
401
  ];
327
- if (options?.filter || options.nestedFilter) {
402
+ if (options?.filter || options?.nestedFilter) {
328
403
  const optionsFilter = MongoAdapter.prepareFilter([options?.filter, options.nestedFilter]);
329
404
  stages.push({ $match: optionsFilter });
330
405
  }
@@ -336,14 +411,14 @@ export class MongoNestedService extends MongoService {
336
411
  stages.push({ $sort: sort });
337
412
  }
338
413
  stages.push({ $limit: limit });
339
- const dataType = this.getDataType();
414
+ const dataType = this.dataType;
340
415
  const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
341
416
  if (projection)
342
417
  stages.push({ $project: projection });
343
- const decode = this.getDecoder();
344
418
  const cursor = await this._dbAggregate(stages, mongoOptions);
345
419
  try {
346
- const out = await (await cursor.toArray()).map((r) => decode(r));
420
+ const outputCodec = this.getOutputCodec('find');
421
+ const out = await (await cursor.toArray()).map((r) => outputCodec(r));
347
422
  return out;
348
423
  }
349
424
  finally {
@@ -359,28 +434,31 @@ export class MongoNestedService extends MongoService {
359
434
  * @returns {Promise<PartialDTO<T>[]>} - The found documents.
360
435
  */
361
436
  async findManyWithCount(documentId, options) {
362
- const args = {
437
+ const command = {
363
438
  crud: 'read',
364
439
  method: 'findMany',
365
440
  byId: false,
366
441
  documentId,
367
442
  options,
368
443
  };
369
- return this._intercept(async () => {
370
- const documentFilter = await this._getDocumentFilter(args);
371
- const nestedFilter = await this._getNestedFilter(args);
372
- return this._findManyWithCount(documentId, {
373
- ...options,
374
- documentFilter,
444
+ return this._executeCommand(command, async () => {
445
+ const documentFilter = await this._getDocumentFilter(command);
446
+ const nestedFilter = await this._getNestedFilter(command);
447
+ command.options = {
448
+ ...command.options,
375
449
  nestedFilter,
376
- limit: options?.limit || this.defaultLimit,
377
- });
378
- }, args);
450
+ documentFilter,
451
+ limit: command.options?.limit || this.defaultLimit,
452
+ };
453
+ return this._findManyWithCount(command);
454
+ });
379
455
  }
380
- async _findManyWithCount(documentId, options) {
456
+ async _findManyWithCount(command) {
457
+ const { documentId, options } = command;
458
+ isNotNullish(documentId, { label: 'documentId' });
381
459
  const matchFilter = MongoAdapter.prepareFilter([
382
460
  MongoAdapter.prepareKeyValues(documentId, ['_id']),
383
- options.documentFilter,
461
+ options?.documentFilter,
384
462
  ]);
385
463
  const mongoOptions = {
386
464
  ...omit(options, ['pick', 'include', 'omit', 'sort', 'skip', 'limit', 'filter', 'count']),
@@ -398,8 +476,8 @@ export class MongoNestedService extends MongoService {
398
476
  },
399
477
  },
400
478
  ];
401
- if (options?.filter || options.nestedFilter) {
402
- const optionsFilter = MongoAdapter.prepareFilter([options?.filter, options.nestedFilter]);
479
+ if (options?.filter || options?.nestedFilter) {
480
+ const optionsFilter = MongoAdapter.prepareFilter([options?.filter, options?.nestedFilter]);
403
481
  dataStages.push({ $match: optionsFilter });
404
482
  }
405
483
  if (options?.skip)
@@ -410,19 +488,19 @@ export class MongoNestedService extends MongoService {
410
488
  dataStages.push({ $sort: sort });
411
489
  }
412
490
  dataStages.push({ $limit: limit });
413
- const dataType = this.getDataType();
491
+ const dataType = this.dataType;
414
492
  const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
415
493
  if (projection)
416
494
  dataStages.push({ $project: projection });
417
- const decode = this.getDecoder();
418
495
  const cursor = await this._dbAggregate(stages, {
419
496
  ...mongoOptions,
420
497
  });
421
498
  try {
422
499
  const facetResult = await cursor.toArray();
500
+ const outputCodec = this.getOutputCodec('find');
423
501
  return {
424
502
  count: facetResult[0].count[0].totalMatches || 0,
425
- items: facetResult[0].data.map((r) => decode(r)),
503
+ items: facetResult[0].data.map((r) => outputCodec(r)),
426
504
  };
427
505
  }
428
506
  finally {
@@ -441,8 +519,9 @@ export class MongoNestedService extends MongoService {
441
519
  */
442
520
  async get(documentId, nestedId, options) {
443
521
  const out = await this.findById(documentId, nestedId, options);
444
- if (!out)
522
+ if (!out) {
445
523
  throw new ResourceNotAvailableError(this.getResourceName() + '.' + this.nestedKey, documentId + '/' + nestedId);
524
+ }
446
525
  return out;
447
526
  }
448
527
  /**
@@ -451,21 +530,44 @@ export class MongoNestedService extends MongoService {
451
530
  * @param {AnyId} documentId - The ID of the document to update.
452
531
  * @param {AnyId} nestedId - The ID of the item to update within the document.
453
532
  * @param {PatchDTO<T>} input - The new data to update the item with.
454
- * @param {MongoNestedService.UpdateOptions<T>} [options] - Additional update options.
533
+ * @param {MongoNestedService.UpdateOneOptions<T>} [options] - Additional update options.
455
534
  * @returns {Promise<PartialDTO<T> | undefined>} The updated item or undefined if it does not exist.
456
535
  * @throws {Error} If an error occurs while updating the item.
457
536
  */
458
537
  async update(documentId, nestedId, input, options) {
459
- const r = await this.updateOnly(documentId, nestedId, input, options);
460
- if (!r)
461
- return;
462
- const out = await this._findById(documentId, nestedId, {
463
- ...options,
464
- sort: undefined,
538
+ const command = {
539
+ crud: 'update',
540
+ method: 'update',
541
+ byId: true,
542
+ documentId,
543
+ nestedId,
544
+ input,
545
+ options,
546
+ };
547
+ return this._executeCommand(command, async () => {
548
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
549
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
550
+ command.options = {
551
+ ...command.options,
552
+ filter,
553
+ documentFilter,
554
+ };
555
+ const r = await this._updateOnly(command);
556
+ if (r) {
557
+ const findCommand = {
558
+ crud: 'read',
559
+ method: 'findById',
560
+ byId: true,
561
+ documentId,
562
+ nestedId,
563
+ options: { ...options, sort: undefined },
564
+ };
565
+ const out = this._findById(findCommand);
566
+ if (out)
567
+ return out;
568
+ }
569
+ throw new ResourceNotAvailableError(this.getResourceName() + '.' + this.nestedKey, documentId + '/' + nestedId);
465
570
  });
466
- if (out)
467
- return out;
468
- throw new ResourceNotAvailableError(this.getResourceName() + '.' + this.nestedKey, documentId + '/' + nestedId);
469
571
  }
470
572
  /**
471
573
  * Update an array element with new data. Returns 1 if document updated 0 otherwise.
@@ -473,29 +575,45 @@ export class MongoNestedService extends MongoService {
473
575
  * @param {MongoAdapter.AnyId} documentId - The ID of the parent document.
474
576
  * @param {MongoAdapter.AnyId} nestedId - The ID of the document to update.
475
577
  * @param {PatchDTO<T>} input - The partial input object containing the fields to update.
476
- * @param {MongoNestedService.UpdateOptions<T>} [options] - Optional update options.
578
+ * @param {MongoNestedService.UpdateOneOptions<T>} [options] - Optional update options.
477
579
  * @returns {Promise<number>} - A promise that resolves to the number of elements updated.
478
580
  */
479
581
  async updateOnly(documentId, nestedId, input, options) {
480
- const info = {
582
+ const command = {
481
583
  crud: 'update',
482
584
  method: 'update',
483
585
  byId: true,
484
586
  documentId,
485
587
  nestedId,
588
+ input,
486
589
  options,
487
590
  };
488
- return this._intercept(async () => {
489
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
490
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
491
- return this._updateOnly(documentId, nestedId, input, { ...options, filter, documentFilter });
492
- }, info);
591
+ return this._executeCommand(command, async () => {
592
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
593
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
594
+ command.options = {
595
+ ...command.options,
596
+ filter,
597
+ documentFilter,
598
+ };
599
+ return await this._updateOnly(command);
600
+ });
493
601
  }
494
- async _updateOnly(documentId, nestedId, input, options) {
602
+ async _updateOnly(command) {
603
+ const { documentId, nestedId, options } = command;
604
+ isNotNullish(documentId, { label: 'documentId' });
605
+ isNotNullish(nestedId, { label: 'nestedId' });
495
606
  let filter = MongoAdapter.prepareKeyValues(nestedId, [this.nestedKey]);
496
607
  if (options?.filter)
497
608
  filter = MongoAdapter.prepareFilter([filter, options?.filter]);
498
- return await this._updateMany(documentId, input, { ...options, filter });
609
+ const updateManyCommand = {
610
+ ...command,
611
+ options: {
612
+ ...command.options,
613
+ filter,
614
+ },
615
+ };
616
+ return await this._updateMany(updateManyCommand);
499
617
  }
500
618
  /**
501
619
  * Updates multiple array elements in document
@@ -506,7 +624,7 @@ export class MongoNestedService extends MongoService {
506
624
  * @returns {Promise<number>} - A promise that resolves to the number of documents updated.
507
625
  */
508
626
  async updateMany(documentId, input, options) {
509
- const info = {
627
+ const command = {
510
628
  crud: 'update',
511
629
  method: 'updateMany',
512
630
  documentId,
@@ -514,15 +632,19 @@ export class MongoNestedService extends MongoService {
514
632
  input,
515
633
  options,
516
634
  };
517
- return this._intercept(async () => {
518
- const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info)]);
519
- const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(info), options?.filter]);
520
- return this._updateMany(documentId, input, { ...options, filter, documentFilter });
521
- }, info);
635
+ return this._executeCommand(command, async () => {
636
+ const documentFilter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command)]);
637
+ const filter = MongoAdapter.prepareFilter([await this._getNestedFilter(command), command.options?.filter]);
638
+ command.options = { ...command.options, filter, documentFilter };
639
+ return this._updateMany(command);
640
+ });
522
641
  }
523
- async _updateMany(documentId, input, options) {
524
- const encode = this.getEncoder('update');
525
- const doc = encode(input, { coerce: true });
642
+ async _updateMany(command) {
643
+ const { documentId, input } = command;
644
+ isNotNullish(documentId, { label: 'documentId' });
645
+ let options = command.options;
646
+ const inputCodec = this.getInputCodec('update');
647
+ const doc = inputCodec(input);
526
648
  if (!Object.keys(doc).length)
527
649
  return 0;
528
650
  const matchFilter = MongoAdapter.prepareFilter([
@@ -539,22 +661,18 @@ export class MongoNestedService extends MongoService {
539
661
  fieldPrefix: this.fieldName + (options?.filter ? '.$[elem].' : '.$[].'),
540
662
  });
541
663
  const r = await this._dbUpdateOne(matchFilter, update, options);
542
- if (options?.count)
543
- return await this._count(documentId, options);
664
+ if (options?.count) {
665
+ const countCommand = {
666
+ crud: 'read',
667
+ method: 'count',
668
+ byId: false,
669
+ documentId,
670
+ options,
671
+ };
672
+ return await this._count(countCommand);
673
+ }
544
674
  return r.modifiedCount || 0;
545
675
  }
546
- /**
547
- * Retrieves the data type of the array field
548
- *
549
- * @returns {ComplexType} The complex data type of the field.
550
- * @throws {NotAcceptableError} If the data type is not a ComplexType.
551
- */
552
- getDataType() {
553
- const t = super.getDataType().getField(this.fieldName).type;
554
- if (!(t instanceof ComplexType))
555
- throw new NotAcceptableError(`Data type "${t.name}" is not a ComplexType`);
556
- return t;
557
- }
558
676
  /**
559
677
  * Retrieves the common filter used for querying array elements.
560
678
  * This method is mostly used for security issues like securing multi-tenant applications.
@@ -564,6 +682,6 @@ export class MongoNestedService extends MongoService {
564
682
  * that resolves to the common filter, or undefined if not available.
565
683
  */
566
684
  _getNestedFilter(args) {
567
- return typeof this.$nestedFilter === 'function' ? this.$nestedFilter(args, this) : this.$nestedFilter;
685
+ return typeof this.nestedFilter === 'function' ? this.nestedFilter(args, this) : this.nestedFilter;
568
686
  }
569
687
  }