@opra/mongodb 0.32.2 → 0.32.4

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,74 +4,109 @@ import { ComplexType, NotAcceptableError, ResourceNotFoundError } from '@opra/co
4
4
  import { MongoAdapter } from './mongo-adapter.js';
5
5
  import { MongoService } from './mongo-service.js';
6
6
  /**
7
- *
8
- * @class MongoArrayService
7
+ * A class that provides methods to perform operations on an array field in a MongoDB collection.
8
+ * @template T The type of the array item.
9
9
  */
10
10
  export class MongoArrayService extends MongoService {
11
+ /**
12
+ * Constructs a new instance
13
+ *
14
+ * @param {Type | string} dataType - The data type of the array elements.
15
+ * @param {string} fieldName - The name of the field in the document representing the array.
16
+ * @param {MongoArrayService.Options} [options] - The options for the array service.
17
+ * @constructor
18
+ */
11
19
  constructor(dataType, fieldName, options) {
12
20
  super(dataType, options);
13
- this._encoders = {};
14
21
  this.fieldName = fieldName;
15
22
  this.defaultLimit = options?.defaultLimit || 10;
16
23
  this.collectionKey = options?.collectionKey || '_id';
17
24
  this.arrayKey = options?.arrayKey || '_id';
18
- }
19
- getArrayDataType() {
20
- const t = this.getDataType()
21
- .getField(this.fieldName).type;
22
- if (!(t instanceof ComplexType))
23
- throw new NotAcceptableError(`Data type "${t.name}" is not a ComplexType`);
24
- return t;
25
+ this.$documentFilter = options?.documentFilter;
26
+ this.$arrayFilter = options?.arrayFilter;
27
+ this.$interceptor = this.$interceptor || options?.interceptor;
25
28
  }
26
29
  /**
27
- * Checks if array item exists. Throws error if not.
30
+ * Asserts whether a resource with the specified parentId and id exists.
31
+ * Throws a ResourceNotFoundError if the resource does not exist.
28
32
  *
29
- * @param parentId
30
- * @param id
33
+ * @param {AnyId} documentId - The ID of the parent document.
34
+ * @param {AnyId} id - The ID of the resource.
35
+ * @param {MongoArrayService.ExistsOptions} [options] - Optional parameters for checking resource existence.
36
+ * @return {Promise<void>} - A promise that resolves with no value upon success.
37
+ * @throws {ResourceNotFoundError} - If the resource does not exist.
31
38
  */
32
- async assert(parentId, id) {
33
- if (!(await this.exists(parentId, id)))
34
- throw new ResourceNotFoundError((this.resourceName || this.getCollectionName()) + '.' + this.arrayKey, parentId + '/' + id);
39
+ async assert(documentId, id, options) {
40
+ if (!(await this.exists(documentId, id, options)))
41
+ throw new ResourceNotFoundError(this.getResourceName() + '.' + this.arrayKey, documentId + '/' + id);
35
42
  }
36
43
  /**
37
- * Adds a single item into array field.
44
+ * Adds a single item into the array field.
38
45
  *
39
- * @param parentId
40
- * @param input
41
- * @param options
46
+ * @param {AnyId} documentId - The ID of the parent document.
47
+ * @param {T} input - The item to be added to the array field.
48
+ * @param {MongoArrayService.CreateOptions} [options] - Optional options for the create operation.
49
+ * @return {Promise<PartialDTO<T>>} - A promise that resolves with the partial output of the created item.
50
+ * @throws {ResourceNotFoundError} - If the parent document is not found.
42
51
  */
43
- async create(parentId, input, options) {
44
- const encode = this._getEncoder('create');
52
+ async create(documentId, input, options) {
53
+ if (this.$interceptor && !options?.__interceptor__)
54
+ return this.$interceptor(() => this.create(documentId, input, { ...options, __interceptor__: true }), {
55
+ crud: 'create',
56
+ method: 'create',
57
+ documentId,
58
+ itemId: input._id,
59
+ input,
60
+ options
61
+ }, this);
62
+ const encode = this.getEncoder('create');
45
63
  const doc = encode(input);
46
- doc[this.arrayKey] = doc[this.arrayKey] || this._generateId();
47
- const docFilter = MongoAdapter.prepareKeyValues(parentId, [this.collectionKey]);
64
+ doc._id = doc._id || this._generateId();
65
+ const docFilter = MongoAdapter.prepareKeyValues(documentId, [this.collectionKey]);
48
66
  const r = await this.__updateOne(docFilter, {
49
67
  $push: { [this.fieldName]: doc }
50
68
  }, options);
51
- if (r.modifiedCount)
69
+ if (r.modifiedCount) {
70
+ if (!options)
71
+ return doc;
52
72
  try {
53
- return this.get(parentId, doc[this.arrayKey], { ...options, filter: undefined, skip: undefined });
73
+ return this.get(documentId, doc[this.arrayKey], { ...options, filter: undefined, skip: undefined });
54
74
  }
55
75
  catch (e) {
56
76
  Error.captureStackTrace(e);
57
77
  throw e;
58
78
  }
59
- throw new ResourceNotFoundError(this.resourceName || this.getCollectionName(), parentId);
79
+ }
80
+ throw new ResourceNotFoundError(this.getResourceName(), documentId);
60
81
  }
61
82
  /**
62
- * Gets the number of array items matching the filter.
63
- * @param parentId
64
- * @param options
83
+ * Counts the number of documents in the collection that match the specified parentId and options.
84
+ *
85
+ * @param {AnyId} documentId - The ID of the parent document.
86
+ * @param {object} options - Optional parameters for counting.
87
+ * @param {object} options.filter - The filter object to apply to the count operation.
88
+ * @returns {Promise<number>} - A promise that resolves to the count of documents.
65
89
  */
66
- async count(parentId, options) {
67
- const matchFilter = MongoAdapter.prepareKeyValues(parentId, [this.collectionKey]);
90
+ async count(documentId, options) {
91
+ if (this.$interceptor && !options?.__interceptor__)
92
+ return this.$interceptor(() => this.count(documentId, { ...options, __interceptor__: true }), {
93
+ crud: 'read',
94
+ method: 'count',
95
+ documentId,
96
+ options
97
+ }, this);
98
+ const matchFilter = MongoAdapter.prepareFilter([
99
+ MongoAdapter.prepareKeyValues(documentId, [this.collectionKey]),
100
+ await this._getDocumentFilter()
101
+ ]);
68
102
  const stages = [
69
103
  { $match: matchFilter },
70
104
  { $unwind: { path: "$" + this.fieldName } },
71
105
  { $replaceRoot: { newRoot: "$" + this.fieldName } }
72
106
  ];
73
- if (options?.filter) {
74
- const optionsFilter = MongoAdapter.prepareFilter(options.filter);
107
+ const contextArrayFilter = await this._getArrayFilter();
108
+ if (options?.filter || contextArrayFilter) {
109
+ const optionsFilter = MongoAdapter.prepareFilter([options?.filter, contextArrayFilter]);
75
110
  stages.push({ $match: optionsFilter });
76
111
  }
77
112
  stages.push({ $count: '*' });
@@ -85,35 +120,62 @@ export class MongoArrayService extends MongoService {
85
120
  }
86
121
  }
87
122
  /**
88
- * Removes one item from an array field
123
+ * Deletes an element from an array within a document in the MongoDB collection.
89
124
  *
90
- * @param parentId
91
- * @param id
92
- * @param options
125
+ * @param {AnyId} documentId - The ID of the parent document.
126
+ * @param {AnyId} id - The ID of the element to delete from the array.
127
+ * @param {MongoArrayService.DeleteOptions<T>} [options] - Additional options for the delete operation.
128
+ * @return {Promise<number>} - A Promise that resolves to the number of elements deleted (1 if successful, 0 if not).
93
129
  */
94
- async delete(parentId, id, options) {
95
- const matchFilter = MongoAdapter.prepareKeyValues(parentId, [this.collectionKey]);
130
+ async delete(documentId, id, options) {
131
+ if (this.$interceptor && !options?.__interceptor__)
132
+ return this.$interceptor(() => this.delete(documentId, id, { ...options, __interceptor__: true }), {
133
+ crud: 'delete',
134
+ method: 'delete',
135
+ documentId,
136
+ itemId: id,
137
+ options
138
+ }, this);
139
+ const matchFilter = MongoAdapter.prepareFilter([
140
+ MongoAdapter.prepareKeyValues(documentId, [this.collectionKey]),
141
+ await this._getDocumentFilter()
142
+ ]);
96
143
  const pullFilter = MongoAdapter.prepareFilter([
97
144
  MongoAdapter.prepareKeyValues(id, [this.arrayKey]),
98
- options?.filter
99
- ]);
145
+ options?.filter,
146
+ await this._getArrayFilter()
147
+ ]) || {};
100
148
  const r = await this.__updateOne(matchFilter, {
101
149
  $pull: { [this.fieldName]: pullFilter }
102
150
  }, options);
103
151
  return r.modifiedCount ? 1 : 0;
104
152
  }
105
153
  /**
106
- * Removes multiple items from an array field
154
+ * Deletes multiple items from a collection based on the parent ID and optional filter.
107
155
  *
108
- * @param parentId
109
- * @param options
156
+ * @param {AnyId} documentId - The ID of the parent document.
157
+ * @param {MongoArrayService.DeleteManyOptions<T>} options - Optional options to specify a filter.
158
+ * @returns {Promise<number>} - A Promise that resolves to the number of items deleted.
110
159
  */
111
- async deleteMany(parentId, options) {
112
- const docFilter = MongoAdapter.prepareKeyValues(parentId, [this.collectionKey]);
160
+ async deleteMany(documentId, options) {
161
+ if (this.$interceptor && !options?.__interceptor__)
162
+ return this.$interceptor(() => this.deleteMany(documentId, { ...options, __interceptor__: true }), {
163
+ crud: 'delete',
164
+ method: 'deleteMany',
165
+ documentId,
166
+ options
167
+ }, this);
168
+ const matchFilter = MongoAdapter.prepareFilter([
169
+ MongoAdapter.prepareKeyValues(documentId, [this.collectionKey]),
170
+ await this._getDocumentFilter()
171
+ ]);
113
172
  // Count matching items, we will use this as result
114
- const matchCount = await this.count(parentId, options);
115
- const pullFilter = MongoAdapter.prepareFilter(options?.filter) || {};
116
- const r = await this.__updateOne(docFilter, {
173
+ const matchCount = await this.count(documentId, options);
174
+ const pullFilter = MongoAdapter.prepareFilter([
175
+ options?.filter,
176
+ await this._getArrayFilter()
177
+ ]) || {};
178
+ const r = await this.__updateOne(matchFilter, {
117
179
  $pull: { [this.fieldName]: pullFilter }
118
180
  }, options);
119
181
  if (r.modifiedCount)
@@ -121,48 +183,87 @@ export class MongoArrayService extends MongoService {
121
183
  return 0;
122
184
  }
123
185
  /**
124
- * Returns true if item exists, false otherwise
186
+ * Checks if an array element with the given parentId and id exists.
125
187
  *
126
- * @param parentId
127
- * @param id
188
+ * @param {AnyId} documentId - The ID of the parent document.
189
+ * @param {AnyId} id - The id of the record.
190
+ * @param {MongoArrayService.ExistsOptions} [options] - The options for the exists method.
191
+ * @returns {Promise<boolean>} - A promise that resolves to a boolean indicating if the record exists or not.
128
192
  */
129
- async exists(parentId, id) {
130
- return !!(await this.findById(parentId, id, { pick: ['_id'] }));
193
+ async exists(documentId, id, options) {
194
+ if (this.$interceptor && !options?.__interceptor__)
195
+ return this.$interceptor(() => this.exists(documentId, id, { ...options, __interceptor__: true }), {
196
+ crud: 'read',
197
+ method: 'exists',
198
+ documentId,
199
+ itemId: id,
200
+ options
201
+ }, this);
202
+ return !!(await this.findById(documentId, id, { ...options, pick: ['_id'] }));
131
203
  }
132
204
  /**
133
- * Fetches the first item in an array field that matches by id.
205
+ * Finds an element in array field by its parent ID and ID.
134
206
  *
135
- * @param parentId
136
- * @param id
137
- * @param options
207
+ * @param {AnyId} documentId - The ID of the document.
208
+ * @param {AnyId} id - The ID of the document.
209
+ * @param {MongoArrayService.FindOneOptions} [options] - The optional options for the operation.
210
+ * @returns {Promise<PartialDTO<T> | undefined>} - A promise that resolves to the found document or undefined if not found.
138
211
  */
139
- async findById(parentId, id, options) {
140
- let filter = MongoAdapter.prepareKeyValues(id, [this.arrayKey]);
141
- if (options?.filter)
142
- filter = MongoAdapter.prepareFilter([filter, options?.filter]);
143
- return await this.findOne(parentId, { ...options, filter });
212
+ async findById(documentId, id, options) {
213
+ if (this.$interceptor && !options?.__interceptor__)
214
+ return this.$interceptor(() => this.findOne(documentId, { ...options, __interceptor__: true }), {
215
+ crud: 'read',
216
+ method: 'findById',
217
+ documentId,
218
+ itemId: id,
219
+ options
220
+ }, this);
221
+ const filter = MongoAdapter.prepareFilter([
222
+ MongoAdapter.prepareKeyValues(id, [this.arrayKey]),
223
+ options?.filter
224
+ ]);
225
+ return await this.findOne(documentId, { ...options, filter });
144
226
  }
145
227
  /**
146
- * Fetches the first item in an array field that matches the filter. Returns undefined if not found.
228
+ * Finds the first array element that matches the given parentId.
147
229
  *
148
- * @param parentId
149
- * @param options
230
+ * @param {AnyId} documentId - The ID of the document.
231
+ * @param {MongoArrayService.FindOneOptions} [options] - Optional options to customize the query.
232
+ * @returns {Promise<PartialDTO<T> | undefined>} A promise that resolves to the first matching document, or `undefined` if no match is found.
150
233
  */
151
- async findOne(parentId, options) {
152
- const rows = await this.findMany(parentId, {
234
+ async findOne(documentId, options) {
235
+ if (this.$interceptor && !options?.__interceptor__)
236
+ return this.$interceptor(() => this.findOne(documentId, { ...options, __interceptor__: true }), {
237
+ crud: 'read',
238
+ method: 'findOne',
239
+ documentId,
240
+ options
241
+ }, this);
242
+ const rows = await this.findMany(documentId, {
153
243
  ...options,
154
244
  limit: 1
155
245
  });
156
246
  return rows?.[0];
157
247
  }
158
248
  /**
159
- * Fetches all items in an array field that matches the filter
249
+ * Finds multiple elements in an array field.
160
250
  *
161
- * @param parentId
162
- * @param options
251
+ * @param {AnyId} documentId - The ID of the parent document.
252
+ * @param {MongoArrayService.FindManyOptions<T>} [options] - The options for finding the documents.
253
+ * @returns {Promise<PartialDTO<T>[]>} - The found documents.
163
254
  */
164
- async findMany(parentId, options) {
165
- const matchFilter = MongoAdapter.prepareKeyValues(parentId, [this.collectionKey]);
255
+ async findMany(documentId, options) {
256
+ if (this.$interceptor && !options?.__interceptor__)
257
+ return this.$interceptor(() => this.findMany(documentId, { ...options, __interceptor__: true }), {
258
+ crud: 'read',
259
+ method: 'findMany',
260
+ documentId,
261
+ options
262
+ }, this);
263
+ const matchFilter = MongoAdapter.prepareFilter([
264
+ MongoAdapter.prepareKeyValues(documentId, [this.collectionKey]),
265
+ await this._getDocumentFilter()
266
+ ]);
166
267
  const mongoOptions = {
167
268
  ...omit(options, ['pick', 'include', 'omit', 'sort', 'skip', 'limit', 'filter', 'count'])
168
269
  };
@@ -182,8 +283,12 @@ export class MongoArrayService extends MongoService {
182
283
  }
183
284
  });
184
285
  }
185
- if (options?.filter) {
186
- const optionsFilter = MongoAdapter.prepareFilter(options?.filter);
286
+ const contextArrayFilter = await this._getArrayFilter();
287
+ if (options?.filter || contextArrayFilter) {
288
+ const optionsFilter = MongoAdapter.prepareFilter([
289
+ options?.filter,
290
+ contextArrayFilter
291
+ ]);
187
292
  dataStages.push({ $match: optionsFilter });
188
293
  }
189
294
  if (options?.skip)
@@ -194,10 +299,11 @@ export class MongoArrayService extends MongoService {
194
299
  dataStages.push({ $sort: sort });
195
300
  }
196
301
  dataStages.push({ $limit: limit });
197
- const dataType = this.getArrayDataType();
302
+ const dataType = this.getDataType();
198
303
  const projection = MongoAdapter.prepareProjection(dataType, options);
199
304
  if (projection)
200
305
  dataStages.push({ $project: projection });
306
+ const decoder = this.getDecoder();
201
307
  const cursor = await this.__aggregate(stages, {
202
308
  ...mongoOptions
203
309
  });
@@ -205,7 +311,7 @@ export class MongoArrayService extends MongoService {
205
311
  if (options?.count) {
206
312
  const facetResult = await cursor.toArray();
207
313
  this.context.response.totalMatches = facetResult[0].count[0].totalMatches || 0;
208
- return facetResult[0].data;
314
+ return facetResult[0].data.map((r) => decoder(r));
209
315
  }
210
316
  else
211
317
  return await cursor.toArray();
@@ -216,30 +322,44 @@ export class MongoArrayService extends MongoService {
216
322
  }
217
323
  }
218
324
  /**
219
- * Fetches the first item in an array field that matches the item id. Throws error undefined if not found.
325
+ * Retrieves a specific item from the array of a document.
220
326
  *
221
- * @param parentId
222
- * @param id
223
- * @param options
327
+ * @param {AnyId} documentId - The ID of the document.
328
+ * @param {AnyId} id - The ID of the item.
329
+ * @param {MongoArrayService.FindOneOptions<T>} [options] - The options for finding the item.
330
+ * @returns {Promise<PartialDTO<T>>} - The item found.
331
+ * @throws {ResourceNotFoundError} - If the item is not found.
224
332
  */
225
- async get(parentId, id, options) {
226
- const out = await this.findById(parentId, id, options);
333
+ async get(documentId, id, options) {
334
+ const out = await this.findById(documentId, id, options);
227
335
  if (!out)
228
- throw new ResourceNotFoundError((this.resourceName || this.getCollectionName()) + '.' + this.arrayKey, parentId + '/' + id);
336
+ throw new ResourceNotFoundError(this.getResourceName() + '.' + this.arrayKey, documentId + '/' + id);
229
337
  return out;
230
338
  }
231
339
  /**
232
- * Update a single item in array field
340
+ * Updates an array element with new data and returns the updated element
233
341
  *
234
- * @param parentId
235
- * @param id
236
- * @param input
237
- * @param options
342
+ * @param {AnyId} documentId - The ID of the document to update.
343
+ * @param {AnyId} id - The ID of the item to update within the document.
344
+ * @param {PatchDTO<T>} input - The new data to update the item with.
345
+ * @param {MongoArrayService.UpdateOptions<T>} [options] - Additional update options.
346
+ * @returns {Promise<PartialDTO<T> | undefined>} The updated item or undefined if it does not exist.
347
+ * @throws {Error} If an error occurs while updating the item.
238
348
  */
239
- async update(parentId, id, input, options) {
240
- await this.updateOnly(parentId, id, input, options);
349
+ async update(documentId, id, input, options) {
350
+ if (this.$interceptor && !options?.__interceptor__)
351
+ return this.$interceptor(() => this.update(documentId, id, input, { ...options, __interceptor__: true }), {
352
+ crud: 'update',
353
+ method: 'update',
354
+ documentId,
355
+ itemId: id,
356
+ options
357
+ }, this);
358
+ const r = await this.updateOnly(documentId, id, input, options);
359
+ if (!r)
360
+ return;
241
361
  try {
242
- return await this.findById(parentId, id, options);
362
+ return await this.findById(documentId, id, options);
243
363
  }
244
364
  catch (e) {
245
365
  Error.captureStackTrace(e);
@@ -247,93 +367,135 @@ export class MongoArrayService extends MongoService {
247
367
  }
248
368
  }
249
369
  /**
250
- * Update a single item in array field
251
- * Returns how many master documents updated (not array items)
370
+ * Update an array element with new data. Returns 1 if document updated 0 otherwise.
252
371
  *
253
- * @param parentId
254
- * @param id
255
- * @param doc
256
- * @param options
372
+ * @param {AnyId} documentId - The ID of the parent document.
373
+ * @param {AnyId} id - The ID of the document to update.
374
+ * @param {PatchDTO<T>} input - The partial input object containing the fields to update.
375
+ * @param {MongoArrayService.UpdateOptions<T>} [options] - Optional update options.
376
+ * @returns {Promise<number>} - A promise that resolves to the number of elements updated.
257
377
  */
258
- async updateOnly(parentId, id, doc, options) {
378
+ async updateOnly(documentId, id, input, options) {
379
+ if (this.$interceptor && !options?.__interceptor__)
380
+ return this.$interceptor(() => this.updateOnly(documentId, id, input, { ...options, __interceptor__: true }), {
381
+ crud: 'update',
382
+ method: 'updateOnly',
383
+ documentId,
384
+ itemId: id,
385
+ input,
386
+ options
387
+ }, this);
259
388
  let filter = MongoAdapter.prepareKeyValues(id, [this.arrayKey]);
260
389
  if (options?.filter)
261
390
  filter = MongoAdapter.prepareFilter([filter, options?.filter]);
262
- return await this.updateMany(parentId, doc, { ...options, filter });
391
+ return await this.updateMany(documentId, input, { ...options, filter });
263
392
  }
264
393
  /**
265
- * Update multiple items in array field, returns how many master documents updated (not array items)
394
+ * Updates multiple array elements in document
266
395
  *
267
- * @param parentId
268
- * @param input
269
- * @param options
396
+ * @param {AnyId} documentId - The ID of the document to update.
397
+ * @param {PatchDTO<T>} input - The updated data for the document(s).
398
+ * @param {MongoArrayService.UpdateManyOptions<T>} [options] - Additional options for the update operation.
399
+ * @returns {Promise<number>} - A promise that resolves to the number of documents updated.
270
400
  */
271
- async updateMany(parentId, input, options) {
272
- const encode = this._getEncoder('update');
401
+ async updateMany(documentId, input, options) {
402
+ if (this.$interceptor && !options?.__interceptor__)
403
+ return this.$interceptor(() => this.updateMany(documentId, input, { ...options, __interceptor__: true }), {
404
+ crud: 'update',
405
+ method: 'updateMany',
406
+ documentId,
407
+ input,
408
+ options
409
+ }, this);
410
+ const encode = this.getEncoder('update');
273
411
  const doc = encode(input);
412
+ if (!Object.keys(doc).length)
413
+ return 0;
274
414
  const matchFilter = MongoAdapter.prepareFilter([
275
- MongoAdapter.prepareKeyValues(parentId, [this.collectionKey]),
415
+ MongoAdapter.prepareKeyValues(documentId, [this.collectionKey]),
416
+ await this._getDocumentFilter(),
276
417
  { [this.fieldName]: { $exists: true } }
277
418
  ]);
278
- if (options?.filter) {
279
- const elemMatch = MongoAdapter.prepareFilter(options?.filter, { fieldPrefix: 'elem.' });
419
+ const contextArrayFilter = await this._getArrayFilter();
420
+ if (options?.filter || contextArrayFilter) {
421
+ const elemMatch = MongoAdapter.prepareFilter([options?.filter, contextArrayFilter], { fieldPrefix: 'elem.' });
280
422
  options = options || {};
281
423
  options.arrayFilters = [elemMatch];
282
424
  }
283
425
  const update = MongoAdapter.preparePatch(doc, {
284
- fieldPrefix: this.fieldName + (options?.filter ? '.$[elem].' : '.$[].')
426
+ fieldPrefix: this.fieldName + ((options?.filter || contextArrayFilter) ? '.$[elem].' : '.$[].')
285
427
  });
286
428
  const r = await this.__updateOne(matchFilter, update, options);
287
429
  return r.modifiedCount;
288
430
  }
289
431
  /**
290
- * Update multiple items in array field and returns number of updated array items
432
+ * Updates multiple elements and returns the count of elements that were updated.
291
433
  *
292
- * @param parentId
293
- * @param doc
294
- * @param options
434
+ * @param {AnyId} documentId - The ID of the document to update.
435
+ * @param {PatchDTO<T>} input - The partial document to update with.
436
+ * @param {MongoArrayService.UpdateManyOptions<T>} [options] - The options for updating multiple documents.
437
+ * @return {Promise<number>} A promise that resolves to the number of elements updated.
295
438
  */
296
- async updateManyReturnCount(parentId, doc, options) {
297
- const r = await this.updateMany(parentId, doc, options);
439
+ async updateManyReturnCount(documentId, input, options) {
440
+ if (this.$interceptor && !options?.__interceptor__)
441
+ return this.$interceptor(() => this.updateManyReturnCount(documentId, input, { ...options, __interceptor__: true }), {
442
+ crud: 'update',
443
+ method: 'updateManyReturnCount',
444
+ documentId,
445
+ input,
446
+ options
447
+ }, this);
448
+ const r = await this.updateMany(documentId, input, options);
298
449
  return r
299
450
  // Count matching items that fits filter criteria
300
- ? await this.count(parentId, options)
451
+ ? await this.count(documentId, options)
301
452
  : 0;
302
453
  }
303
454
  /**
304
- * Generates Id value
455
+ * Retrieves the data type of the array field
456
+ *
457
+ * @returns {ComplexType} The complex data type of the field.
458
+ * @throws {NotAcceptableError} If the data type is not a ComplexType.
459
+ */
460
+ getDataType() {
461
+ const t = super.getDataType()
462
+ .getField(this.fieldName).type;
463
+ if (!(t instanceof ComplexType))
464
+ throw new NotAcceptableError(`Data type "${t.name}" is not a ComplexType`);
465
+ return t;
466
+ }
467
+ /**
468
+ * Generates an ID.
305
469
  *
306
470
  * @protected
471
+ * @returns {AnyId} The generated ID.
307
472
  */
308
473
  _generateId() {
309
- return new ObjectId();
474
+ return typeof this.$idGenerator === 'function' ?
475
+ this.$idGenerator(this) : new ObjectId();
310
476
  }
311
477
  /**
312
- * Generates a new Validator for encoding or returns from cache if already generated before
313
- * @param operation
478
+ * Retrieves the common filter used for querying documents.
479
+ * This method is mostly used for security issues like securing multi-tenant applications.
480
+ *
314
481
  * @protected
482
+ * @returns {FilterInput | Promise<FilterInput> | undefined} The common filter or a Promise
483
+ * that resolves to the common filter, or undefined if not available.
315
484
  */
316
- _getEncoder(operation) {
317
- let encoder = this._encoders[operation];
318
- if (encoder)
319
- return encoder;
320
- encoder = this._generateEncoder(operation);
321
- this._encoders[operation] = encoder;
322
- return encoder;
485
+ _getDocumentFilter() {
486
+ return typeof this.$documentFilter === 'function' ?
487
+ this.$documentFilter(this) : this.$documentFilter;
323
488
  }
324
489
  /**
325
- * Generates a new Valgen Validator for encode operation
490
+ * Retrieves the common filter used for querying array elements.
491
+ * This method is mostly used for security issues like securing multi-tenant applications.
326
492
  *
327
- * @param operation
328
493
  * @protected
494
+ * @returns {FilterInput | Promise<FilterInput> | undefined} The common filter or a Promise
495
+ * that resolves to the common filter, or undefined if not available.
329
496
  */
330
- _generateEncoder(operation) {
331
- const dataType = this.getArrayDataType();
332
- const options = {};
333
- if (operation === 'update') {
334
- options.omit = ['_id'];
335
- options.partial = true;
336
- }
337
- return dataType.generateCodec('encode', options);
497
+ _getArrayFilter() {
498
+ return typeof this.$arrayFilter === 'function' ?
499
+ this.$arrayFilter(this) : this.$arrayFilter;
338
500
  }
339
501
  }