@opra/mongodb 0.33.2 → 0.33.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.
- package/cjs/mongo-collection-service.js +72 -21
- package/cjs/mongo-service.js +71 -66
- package/esm/mongo-collection-service.js +72 -21
- package/esm/mongo-service.js +71 -66
- package/package.json +3 -3
- package/types/mongo-collection-service.d.ts +27 -16
- package/types/mongo-service.d.ts +53 -70
|
@@ -155,6 +155,24 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
155
155
|
const r = await this.__deleteMany(filter, (0, lodash_omit_1.default)(options, 'filter'));
|
|
156
156
|
return r.deletedCount;
|
|
157
157
|
}
|
|
158
|
+
async distinct(field, options) {
|
|
159
|
+
const info = {
|
|
160
|
+
crud: 'read',
|
|
161
|
+
method: 'distinct',
|
|
162
|
+
options
|
|
163
|
+
};
|
|
164
|
+
return this._intercept(async () => {
|
|
165
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
166
|
+
await this._getDocumentFilter(info),
|
|
167
|
+
options?.filter,
|
|
168
|
+
]);
|
|
169
|
+
return this._distinct(field, { ...options, filter });
|
|
170
|
+
}, info);
|
|
171
|
+
}
|
|
172
|
+
async _distinct(field, options) {
|
|
173
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
174
|
+
return await this.__distinct(field, filter, (0, lodash_omit_1.default)(options, 'filter'));
|
|
175
|
+
}
|
|
158
176
|
/**
|
|
159
177
|
* Checks if an object with the given id exists.
|
|
160
178
|
*
|
|
@@ -365,21 +383,33 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
365
383
|
}, info);
|
|
366
384
|
}
|
|
367
385
|
async _update(id, input, options) {
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
const
|
|
386
|
+
const isUpdateFilter = Array.isArray(input) ||
|
|
387
|
+
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
388
|
+
const isDocument = !Array.isArray(input) &&
|
|
389
|
+
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
390
|
+
if (isUpdateFilter && isDocument)
|
|
391
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
392
|
+
let update;
|
|
393
|
+
if (isDocument) {
|
|
394
|
+
const encode = this.getEncoder('update');
|
|
395
|
+
const doc = encode(input, { coerce: true });
|
|
396
|
+
update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
397
|
+
update.$set = update.$set || {};
|
|
398
|
+
}
|
|
399
|
+
else
|
|
400
|
+
update = input;
|
|
401
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
402
|
+
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
403
|
+
options?.filter
|
|
404
|
+
]);
|
|
371
405
|
const mongoOptions = {
|
|
372
406
|
...options,
|
|
373
407
|
includeResultMetadata: false,
|
|
374
408
|
upsert: undefined,
|
|
375
409
|
projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
376
410
|
};
|
|
377
|
-
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
378
|
-
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
379
|
-
options?.filter
|
|
380
|
-
]);
|
|
381
411
|
const decode = this.getDecoder();
|
|
382
|
-
const out = await this.__findOneAndUpdate(filter,
|
|
412
|
+
const out = await this.__findOneAndUpdate(filter, update, mongoOptions);
|
|
383
413
|
return out ? decode(out, { coerce: true }) : undefined;
|
|
384
414
|
}
|
|
385
415
|
/**
|
|
@@ -407,22 +437,33 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
407
437
|
}, info);
|
|
408
438
|
}
|
|
409
439
|
async _updateOnly(id, input, options) {
|
|
440
|
+
const isUpdateFilter = Array.isArray(input) ||
|
|
441
|
+
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
442
|
+
const isDocument = !Array.isArray(input) &&
|
|
443
|
+
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
444
|
+
if (isUpdateFilter && isDocument)
|
|
445
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
446
|
+
let update;
|
|
447
|
+
if (isDocument) {
|
|
448
|
+
const encode = this.getEncoder('update');
|
|
449
|
+
const doc = encode(input, { coerce: true });
|
|
450
|
+
update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
451
|
+
if (!Object.keys(doc).length)
|
|
452
|
+
return 0;
|
|
453
|
+
}
|
|
454
|
+
else
|
|
455
|
+
update = input;
|
|
410
456
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
411
457
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
412
458
|
options?.filter
|
|
413
459
|
]);
|
|
414
|
-
const encode = this.getEncoder('update');
|
|
415
|
-
const doc = encode(input, { coerce: true });
|
|
416
|
-
if (!Object.keys(doc).length)
|
|
417
|
-
return 0;
|
|
418
|
-
const patch = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
419
460
|
const mongoOptions = {
|
|
420
461
|
...options,
|
|
421
462
|
includeResultMetadata: false,
|
|
422
463
|
upsert: undefined,
|
|
423
464
|
projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
424
465
|
};
|
|
425
|
-
const out = await this.__updateOne(filter,
|
|
466
|
+
const out = await this.__updateOne(filter, update, mongoOptions);
|
|
426
467
|
return out.matchedCount;
|
|
427
468
|
}
|
|
428
469
|
/**
|
|
@@ -448,18 +489,28 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
448
489
|
}, info);
|
|
449
490
|
}
|
|
450
491
|
async _updateMany(input, options) {
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
492
|
+
const isUpdateFilter = Array.isArray(input) ||
|
|
493
|
+
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
494
|
+
const isDocument = !Array.isArray(input) &&
|
|
495
|
+
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
496
|
+
if (isUpdateFilter && isDocument)
|
|
497
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
498
|
+
let update;
|
|
499
|
+
if (isDocument) {
|
|
500
|
+
const encode = this.getEncoder('update');
|
|
501
|
+
const doc = encode(input, { coerce: true });
|
|
502
|
+
update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
503
|
+
if (!Object.keys(doc).length)
|
|
504
|
+
return 0;
|
|
505
|
+
}
|
|
506
|
+
else
|
|
507
|
+
update = input;
|
|
457
508
|
const mongoOptions = {
|
|
458
509
|
...(0, lodash_omit_1.default)(options, 'filter'),
|
|
459
510
|
upsert: undefined
|
|
460
511
|
};
|
|
461
512
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
462
|
-
const r = await this.__updateMany(filter,
|
|
513
|
+
const r = await this.__updateMany(filter, update, mongoOptions);
|
|
463
514
|
return r.matchedCount;
|
|
464
515
|
}
|
|
465
516
|
/**
|
package/cjs/mongo-service.js
CHANGED
|
@@ -12,8 +12,8 @@ class MongoService extends core_1.ApiService {
|
|
|
12
12
|
/**
|
|
13
13
|
* Constructs a new instance
|
|
14
14
|
*
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
15
|
+
* @param dataType - The data type of the array elements.
|
|
16
|
+
* @param [options] - The options for the array service.
|
|
17
17
|
* @constructor
|
|
18
18
|
*/
|
|
19
19
|
constructor(dataType, options) {
|
|
@@ -37,7 +37,6 @@ class MongoService extends core_1.ApiService {
|
|
|
37
37
|
/**
|
|
38
38
|
* Retrieves the data type of the document
|
|
39
39
|
*
|
|
40
|
-
* @returns {ComplexType} The complex data type of the field.
|
|
41
40
|
* @throws {NotAcceptableError} If the data type is not a ComplexType.
|
|
42
41
|
*/
|
|
43
42
|
getDataType() {
|
|
@@ -46,8 +45,7 @@ class MongoService extends core_1.ApiService {
|
|
|
46
45
|
/**
|
|
47
46
|
* Retrieves the encoder for the specified operation.
|
|
48
47
|
*
|
|
49
|
-
* @param
|
|
50
|
-
* @returns {IsObject.Validator<T>} - The encoder for the specified operation.
|
|
48
|
+
* @param operation - The operation to retrieve the encoder for. Valid values are 'create' and 'update'.
|
|
51
49
|
*/
|
|
52
50
|
getEncoder(operation) {
|
|
53
51
|
let encoder = this._encoders[operation];
|
|
@@ -59,8 +57,6 @@ class MongoService extends core_1.ApiService {
|
|
|
59
57
|
}
|
|
60
58
|
/**
|
|
61
59
|
* Retrieves the decoder.
|
|
62
|
-
*
|
|
63
|
-
* @returns {IsObject.Validator<T>} - The encoder for the specified operation.
|
|
64
60
|
*/
|
|
65
61
|
getDecoder() {
|
|
66
62
|
let decoder = this._decoder;
|
|
@@ -73,9 +69,8 @@ class MongoService extends core_1.ApiService {
|
|
|
73
69
|
/**
|
|
74
70
|
* Executes the provided function within a transaction.
|
|
75
71
|
*
|
|
76
|
-
* @param
|
|
77
|
-
* @param
|
|
78
|
-
* @returns {Promise<any>} - A promise that resolves with the result of the function execution within the transaction.
|
|
72
|
+
* @param callback - The function to be executed within the transaction.
|
|
73
|
+
* @param [options] - Optional options for the transaction.
|
|
79
74
|
*/
|
|
80
75
|
async withTransaction(callback, options) {
|
|
81
76
|
let session = this.getSession();
|
|
@@ -104,12 +99,12 @@ class MongoService extends core_1.ApiService {
|
|
|
104
99
|
}
|
|
105
100
|
finally {
|
|
106
101
|
// Restore old session property
|
|
107
|
-
if (hasOldSession)
|
|
102
|
+
if (hasOldSession)
|
|
108
103
|
this.session = oldSessionGetter;
|
|
109
|
-
await session.endSession();
|
|
110
|
-
}
|
|
111
104
|
else
|
|
112
105
|
delete this.session;
|
|
106
|
+
if (!oldInTransaction)
|
|
107
|
+
await session.endSession();
|
|
113
108
|
}
|
|
114
109
|
}
|
|
115
110
|
/**
|
|
@@ -117,9 +112,8 @@ class MongoService extends core_1.ApiService {
|
|
|
117
112
|
* one will be added to each of the documents missing it by the driver, mutating the document. This behavior
|
|
118
113
|
* can be overridden by setting the **forceServerObjectId** flag.
|
|
119
114
|
*
|
|
120
|
-
* @param
|
|
121
|
-
* @param
|
|
122
|
-
* @returns {Promise<mongodb.InsertOneWriteOpResult<mongodb.OptionalId<T>>>} - A promise that resolves with the result of the insert operation.
|
|
115
|
+
* @param doc - The document to insert
|
|
116
|
+
* @param options - Optional settings for the command
|
|
123
117
|
* @protected
|
|
124
118
|
*/
|
|
125
119
|
async __insertOne(doc, options) {
|
|
@@ -140,9 +134,8 @@ class MongoService extends core_1.ApiService {
|
|
|
140
134
|
/**
|
|
141
135
|
* Gets the number of documents matching the filter.
|
|
142
136
|
*
|
|
143
|
-
* @param
|
|
144
|
-
* @param
|
|
145
|
-
* @returns {Promise<number>} - The number of documents matching the filter.
|
|
137
|
+
* @param filter - The filter used to match documents.
|
|
138
|
+
* @param options - The options for counting documents.
|
|
146
139
|
* @protected
|
|
147
140
|
*/
|
|
148
141
|
async __countDocuments(filter, options) {
|
|
@@ -164,9 +157,9 @@ class MongoService extends core_1.ApiService {
|
|
|
164
157
|
/**
|
|
165
158
|
* Delete a document from a collection
|
|
166
159
|
*
|
|
167
|
-
* @param
|
|
168
|
-
* @param
|
|
169
|
-
* @
|
|
160
|
+
* @param filter - The filter used to select the document to remove
|
|
161
|
+
* @param options - Optional settings for the command
|
|
162
|
+
* @protected
|
|
170
163
|
*/
|
|
171
164
|
async __deleteOne(filter, options) {
|
|
172
165
|
const db = this.getDatabase();
|
|
@@ -184,12 +177,10 @@ class MongoService extends core_1.ApiService {
|
|
|
184
177
|
}
|
|
185
178
|
}
|
|
186
179
|
/**
|
|
187
|
-
*
|
|
180
|
+
* Delete multiple documents from a collection
|
|
188
181
|
*
|
|
189
|
-
* @param
|
|
190
|
-
*
|
|
191
|
-
* @param {mongodb.DeleteOptions} [options] - The options for the delete operation.
|
|
192
|
-
* @returns {Promise<mongodb.DeleteResult>} A promise that resolves with the delete result object.
|
|
182
|
+
* @param filter - The filter used to select the documents to remove
|
|
183
|
+
* @param options - Optional settings for the command
|
|
193
184
|
* @protected
|
|
194
185
|
*/
|
|
195
186
|
async __deleteMany(filter, options) {
|
|
@@ -208,12 +199,33 @@ class MongoService extends core_1.ApiService {
|
|
|
208
199
|
}
|
|
209
200
|
}
|
|
210
201
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
202
|
+
* Gets the number of documents matching the filter.
|
|
203
|
+
*
|
|
204
|
+
* @param field - Field of the document to find distinct values for
|
|
205
|
+
* @param filter - The filter for filtering the set of documents to which we apply the distinct filter.
|
|
206
|
+
* @param options - Optional settings for the command
|
|
207
|
+
* @protected
|
|
208
|
+
*/
|
|
209
|
+
async __distinct(field, filter, options) {
|
|
210
|
+
const db = this.getDatabase();
|
|
211
|
+
const collection = await this.getCollection(db);
|
|
212
|
+
options = {
|
|
213
|
+
...options,
|
|
214
|
+
session: options?.session || this.getSession()
|
|
215
|
+
};
|
|
216
|
+
try {
|
|
217
|
+
return await collection.distinct(field, filter || {}, options);
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
await this.$onError?.(e, this);
|
|
221
|
+
throw e;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Execute an aggregation framework pipeline against the collection, needs MongoDB \>= 2.2
|
|
213
226
|
*
|
|
214
|
-
* @param
|
|
215
|
-
* @param
|
|
216
|
-
* @returns {Promise<mongodb.ChangeStream<T>>} - A promise that resolves to a Change Stream that represents the result of the aggregation.
|
|
227
|
+
* @param pipeline - An array of aggregation pipelines to execute
|
|
228
|
+
* @param options - Optional settings for the command
|
|
217
229
|
* @protected
|
|
218
230
|
*/
|
|
219
231
|
async __aggregate(pipeline, options) {
|
|
@@ -234,10 +246,9 @@ class MongoService extends core_1.ApiService {
|
|
|
234
246
|
/**
|
|
235
247
|
* Fetches the first document that matches the filter
|
|
236
248
|
*
|
|
237
|
-
* @param
|
|
238
|
-
* @param
|
|
249
|
+
* @param filter - Query for find Operation
|
|
250
|
+
* @param options - Optional settings for the command
|
|
239
251
|
* @protected
|
|
240
|
-
* @returns {Promise<PartialDTO<T> | undefined>} - A promise that resolves to the first matching document, or undefined if no match is found
|
|
241
252
|
*/
|
|
242
253
|
async __findOne(filter, options) {
|
|
243
254
|
const db = this.getDatabase();
|
|
@@ -255,11 +266,11 @@ class MongoService extends core_1.ApiService {
|
|
|
255
266
|
}
|
|
256
267
|
}
|
|
257
268
|
/**
|
|
258
|
-
* Creates a cursor for a filter that can be used to iterate over results from MongoDB
|
|
269
|
+
* Creates a cursor for a filter that can be used to iterate over results from MongoDB
|
|
259
270
|
*
|
|
260
|
-
* @param
|
|
261
|
-
*
|
|
262
|
-
* @
|
|
271
|
+
* @param filter - The filter predicate. If unspecified,
|
|
272
|
+
* then all documents in the collection will match the predicate
|
|
273
|
+
* @param options - Optional settings for the command
|
|
263
274
|
* @protected
|
|
264
275
|
*/
|
|
265
276
|
async __find(filter, options) {
|
|
@@ -278,13 +289,12 @@ class MongoService extends core_1.ApiService {
|
|
|
278
289
|
}
|
|
279
290
|
}
|
|
280
291
|
/**
|
|
281
|
-
* Update a single document in a collection
|
|
292
|
+
* Update a single document in a collection
|
|
282
293
|
*
|
|
283
|
-
* @param
|
|
284
|
-
* @param
|
|
285
|
-
* @param
|
|
294
|
+
* @param filter - The filter used to select the document to update
|
|
295
|
+
* @param update - The update operations to be applied to the document
|
|
296
|
+
* @param options - Optional settings for the command
|
|
286
297
|
* @protected
|
|
287
|
-
* @returns {Promise<mongodb.UpdateResult>} - A promise that resolves to the result of the update operation.
|
|
288
298
|
*/
|
|
289
299
|
async __updateOne(filter, update, options) {
|
|
290
300
|
const db = this.getDatabase();
|
|
@@ -304,13 +314,12 @@ class MongoService extends core_1.ApiService {
|
|
|
304
314
|
/**
|
|
305
315
|
* Find a document and update it in one atomic operation. Requires a write lock for the duration of the operation.
|
|
306
316
|
*
|
|
307
|
-
* @param
|
|
308
|
-
* @param
|
|
309
|
-
* @param
|
|
310
|
-
* @returns {Promise<T | null>} - A promise that resolves to the updated document or null if no document matched the filter.
|
|
317
|
+
* @param filter - The filter used to select the document to update
|
|
318
|
+
* @param update - Update operations to be performed on the document
|
|
319
|
+
* @param options - Optional settings for the command
|
|
311
320
|
* @protected
|
|
312
321
|
*/
|
|
313
|
-
async __findOneAndUpdate(filter,
|
|
322
|
+
async __findOneAndUpdate(filter, update, options) {
|
|
314
323
|
const db = this.getDatabase();
|
|
315
324
|
const collection = await this.getCollection(db);
|
|
316
325
|
const opts = {
|
|
@@ -320,7 +329,7 @@ class MongoService extends core_1.ApiService {
|
|
|
320
329
|
session: options?.session || this.getSession(),
|
|
321
330
|
};
|
|
322
331
|
try {
|
|
323
|
-
return await collection.findOneAndUpdate(filter || {},
|
|
332
|
+
return await collection.findOneAndUpdate(filter || {}, update, opts);
|
|
324
333
|
}
|
|
325
334
|
catch (e) {
|
|
326
335
|
await this.$onError?.(e, this);
|
|
@@ -328,15 +337,14 @@ class MongoService extends core_1.ApiService {
|
|
|
328
337
|
}
|
|
329
338
|
}
|
|
330
339
|
/**
|
|
331
|
-
* Update multiple documents in a collection
|
|
340
|
+
* Update multiple documents in a collection
|
|
332
341
|
*
|
|
333
|
-
* @param
|
|
334
|
-
* @param
|
|
335
|
-
* @param
|
|
336
|
-
* @return {Promise<mongodb.UpdateResult>} - A Promise that resolves to the result of the update operation.
|
|
342
|
+
* @param filter - The filter used to select the documents to update
|
|
343
|
+
* @param update - The update operations to be applied to the documents
|
|
344
|
+
* @param options - Optional settings for the command
|
|
337
345
|
* @protected
|
|
338
346
|
*/
|
|
339
|
-
async __updateMany(filter,
|
|
347
|
+
async __updateMany(filter, update, options) {
|
|
340
348
|
const db = this.getDatabase();
|
|
341
349
|
const collection = await this.getCollection(db);
|
|
342
350
|
options = {
|
|
@@ -345,7 +353,7 @@ class MongoService extends core_1.ApiService {
|
|
|
345
353
|
upsert: false
|
|
346
354
|
};
|
|
347
355
|
try {
|
|
348
|
-
return await collection.updateMany(filter || {},
|
|
356
|
+
return await collection.updateMany(filter || {}, update, options);
|
|
349
357
|
}
|
|
350
358
|
catch (e) {
|
|
351
359
|
await this.$onError?.(e, this);
|
|
@@ -357,7 +365,6 @@ class MongoService extends core_1.ApiService {
|
|
|
357
365
|
*
|
|
358
366
|
* @protected
|
|
359
367
|
*
|
|
360
|
-
* @returns {Promise<mongodb.Db>} The database connection.
|
|
361
368
|
* @throws {Error} If the context or database is not set.
|
|
362
369
|
*/
|
|
363
370
|
getDatabase() {
|
|
@@ -373,7 +380,6 @@ class MongoService extends core_1.ApiService {
|
|
|
373
380
|
*
|
|
374
381
|
* @protected
|
|
375
382
|
*
|
|
376
|
-
* @returns {Promise<mongodb.ClientSession>} The database connection.
|
|
377
383
|
* @throws {Error} If the context or database is not set.
|
|
378
384
|
*/
|
|
379
385
|
getSession() {
|
|
@@ -384,9 +390,8 @@ class MongoService extends core_1.ApiService {
|
|
|
384
390
|
/**
|
|
385
391
|
* Retrieves a MongoDB collection from the given database.
|
|
386
392
|
*
|
|
387
|
-
* @param
|
|
393
|
+
* @param db - The MongoDB database.
|
|
388
394
|
* @protected
|
|
389
|
-
* @returns {Promise<mongodb.Collection<T>>} A promise that resolves to the MongoDB collection.
|
|
390
395
|
*/
|
|
391
396
|
async getCollection(db) {
|
|
392
397
|
return db.collection(this.getCollectionName());
|
|
@@ -395,7 +400,7 @@ class MongoService extends core_1.ApiService {
|
|
|
395
400
|
* Retrieves the collection name.
|
|
396
401
|
*
|
|
397
402
|
* @protected
|
|
398
|
-
* @returns
|
|
403
|
+
* @returns The collection name.
|
|
399
404
|
* @throws {Error} If the collection name is not defined.
|
|
400
405
|
*/
|
|
401
406
|
getCollectionName() {
|
|
@@ -410,7 +415,7 @@ class MongoService extends core_1.ApiService {
|
|
|
410
415
|
* Retrieves the resource name.
|
|
411
416
|
*
|
|
412
417
|
* @protected
|
|
413
|
-
* @returns {string} The
|
|
418
|
+
* @returns {string} The resource name.
|
|
414
419
|
* @throws {Error} If the collection name is not defined.
|
|
415
420
|
*/
|
|
416
421
|
getResourceName() {
|
|
@@ -424,9 +429,9 @@ class MongoService extends core_1.ApiService {
|
|
|
424
429
|
/**
|
|
425
430
|
* Generates an encoder for the specified operation.
|
|
426
431
|
*
|
|
427
|
-
* @param
|
|
432
|
+
* @param operation - The operation to generate the encoder for. Must be either 'create' or 'update'.
|
|
428
433
|
* @protected
|
|
429
|
-
* @returns
|
|
434
|
+
* @returns - The generated encoder for the specified operation.
|
|
430
435
|
*/
|
|
431
436
|
_generateEncoder(operation) {
|
|
432
437
|
const dataType = this.getDataType();
|
|
@@ -441,7 +446,7 @@ class MongoService extends core_1.ApiService {
|
|
|
441
446
|
* Generates an encoder for the specified operation.
|
|
442
447
|
*
|
|
443
448
|
* @protected
|
|
444
|
-
* @returns
|
|
449
|
+
* @returns - The generated encoder for the specified operation.
|
|
445
450
|
*/
|
|
446
451
|
_generateDecoder() {
|
|
447
452
|
const dataType = this.getDataType();
|
|
@@ -151,6 +151,24 @@ export class MongoCollectionService extends MongoService {
|
|
|
151
151
|
const r = await this.__deleteMany(filter, omit(options, 'filter'));
|
|
152
152
|
return r.deletedCount;
|
|
153
153
|
}
|
|
154
|
+
async distinct(field, options) {
|
|
155
|
+
const info = {
|
|
156
|
+
crud: 'read',
|
|
157
|
+
method: 'distinct',
|
|
158
|
+
options
|
|
159
|
+
};
|
|
160
|
+
return this._intercept(async () => {
|
|
161
|
+
const filter = MongoAdapter.prepareFilter([
|
|
162
|
+
await this._getDocumentFilter(info),
|
|
163
|
+
options?.filter,
|
|
164
|
+
]);
|
|
165
|
+
return this._distinct(field, { ...options, filter });
|
|
166
|
+
}, info);
|
|
167
|
+
}
|
|
168
|
+
async _distinct(field, options) {
|
|
169
|
+
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
170
|
+
return await this.__distinct(field, filter, omit(options, 'filter'));
|
|
171
|
+
}
|
|
154
172
|
/**
|
|
155
173
|
* Checks if an object with the given id exists.
|
|
156
174
|
*
|
|
@@ -361,21 +379,33 @@ export class MongoCollectionService extends MongoService {
|
|
|
361
379
|
}, info);
|
|
362
380
|
}
|
|
363
381
|
async _update(id, input, options) {
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
const
|
|
382
|
+
const isUpdateFilter = Array.isArray(input) ||
|
|
383
|
+
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
384
|
+
const isDocument = !Array.isArray(input) &&
|
|
385
|
+
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
386
|
+
if (isUpdateFilter && isDocument)
|
|
387
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
388
|
+
let update;
|
|
389
|
+
if (isDocument) {
|
|
390
|
+
const encode = this.getEncoder('update');
|
|
391
|
+
const doc = encode(input, { coerce: true });
|
|
392
|
+
update = MongoAdapter.preparePatch(doc);
|
|
393
|
+
update.$set = update.$set || {};
|
|
394
|
+
}
|
|
395
|
+
else
|
|
396
|
+
update = input;
|
|
397
|
+
const filter = MongoAdapter.prepareFilter([
|
|
398
|
+
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
399
|
+
options?.filter
|
|
400
|
+
]);
|
|
367
401
|
const mongoOptions = {
|
|
368
402
|
...options,
|
|
369
403
|
includeResultMetadata: false,
|
|
370
404
|
upsert: undefined,
|
|
371
405
|
projection: MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
372
406
|
};
|
|
373
|
-
const filter = MongoAdapter.prepareFilter([
|
|
374
|
-
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
375
|
-
options?.filter
|
|
376
|
-
]);
|
|
377
407
|
const decode = this.getDecoder();
|
|
378
|
-
const out = await this.__findOneAndUpdate(filter,
|
|
408
|
+
const out = await this.__findOneAndUpdate(filter, update, mongoOptions);
|
|
379
409
|
return out ? decode(out, { coerce: true }) : undefined;
|
|
380
410
|
}
|
|
381
411
|
/**
|
|
@@ -403,22 +433,33 @@ export class MongoCollectionService extends MongoService {
|
|
|
403
433
|
}, info);
|
|
404
434
|
}
|
|
405
435
|
async _updateOnly(id, input, options) {
|
|
436
|
+
const isUpdateFilter = Array.isArray(input) ||
|
|
437
|
+
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
438
|
+
const isDocument = !Array.isArray(input) &&
|
|
439
|
+
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
440
|
+
if (isUpdateFilter && isDocument)
|
|
441
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
442
|
+
let update;
|
|
443
|
+
if (isDocument) {
|
|
444
|
+
const encode = this.getEncoder('update');
|
|
445
|
+
const doc = encode(input, { coerce: true });
|
|
446
|
+
update = MongoAdapter.preparePatch(doc);
|
|
447
|
+
if (!Object.keys(doc).length)
|
|
448
|
+
return 0;
|
|
449
|
+
}
|
|
450
|
+
else
|
|
451
|
+
update = input;
|
|
406
452
|
const filter = MongoAdapter.prepareFilter([
|
|
407
453
|
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
408
454
|
options?.filter
|
|
409
455
|
]);
|
|
410
|
-
const encode = this.getEncoder('update');
|
|
411
|
-
const doc = encode(input, { coerce: true });
|
|
412
|
-
if (!Object.keys(doc).length)
|
|
413
|
-
return 0;
|
|
414
|
-
const patch = MongoAdapter.preparePatch(doc);
|
|
415
456
|
const mongoOptions = {
|
|
416
457
|
...options,
|
|
417
458
|
includeResultMetadata: false,
|
|
418
459
|
upsert: undefined,
|
|
419
460
|
projection: MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
420
461
|
};
|
|
421
|
-
const out = await this.__updateOne(filter,
|
|
462
|
+
const out = await this.__updateOne(filter, update, mongoOptions);
|
|
422
463
|
return out.matchedCount;
|
|
423
464
|
}
|
|
424
465
|
/**
|
|
@@ -444,18 +485,28 @@ export class MongoCollectionService extends MongoService {
|
|
|
444
485
|
}, info);
|
|
445
486
|
}
|
|
446
487
|
async _updateMany(input, options) {
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
488
|
+
const isUpdateFilter = Array.isArray(input) ||
|
|
489
|
+
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
490
|
+
const isDocument = !Array.isArray(input) &&
|
|
491
|
+
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
492
|
+
if (isUpdateFilter && isDocument)
|
|
493
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
494
|
+
let update;
|
|
495
|
+
if (isDocument) {
|
|
496
|
+
const encode = this.getEncoder('update');
|
|
497
|
+
const doc = encode(input, { coerce: true });
|
|
498
|
+
update = MongoAdapter.preparePatch(doc);
|
|
499
|
+
if (!Object.keys(doc).length)
|
|
500
|
+
return 0;
|
|
501
|
+
}
|
|
502
|
+
else
|
|
503
|
+
update = input;
|
|
453
504
|
const mongoOptions = {
|
|
454
505
|
...omit(options, 'filter'),
|
|
455
506
|
upsert: undefined
|
|
456
507
|
};
|
|
457
508
|
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
458
|
-
const r = await this.__updateMany(filter,
|
|
509
|
+
const r = await this.__updateMany(filter, update, mongoOptions);
|
|
459
510
|
return r.matchedCount;
|
|
460
511
|
}
|
|
461
512
|
/**
|