@opra/mongodb 0.32.6 → 0.33.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.
- package/cjs/mongo-array-service.js +212 -159
- package/cjs/mongo-collection-service.js +194 -107
- package/cjs/mongo-service.js +48 -34
- package/cjs/mongo-singleton-service.js +85 -58
- package/esm/mongo-array-service.js +213 -160
- package/esm/mongo-collection-service.js +195 -108
- package/esm/mongo-service.js +48 -34
- package/esm/mongo-singleton-service.js +86 -59
- package/package.json +4 -4
- package/types/mongo-array-service.d.ts +74 -20
- package/types/mongo-collection-service.d.ts +60 -9
- package/types/mongo-service.d.ts +22 -25
- package/types/mongo-singleton-service.d.ts +31 -7
- package/types/types.d.ts +2 -1
|
@@ -33,11 +33,11 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
33
33
|
* @param {AnyId} id - The ID of the resource to assert.
|
|
34
34
|
* @param {MongoCollectionService.ExistsOptions} [options] - Optional options for checking the existence.
|
|
35
35
|
* @returns {Promise<void>} - A Promise that resolves when the resource exists.
|
|
36
|
-
* @throws {
|
|
36
|
+
* @throws {ResourceNotAvailableError} - If the resource does not exist.
|
|
37
37
|
*/
|
|
38
38
|
async assert(id, options) {
|
|
39
39
|
if (!(await this.exists(id, options)))
|
|
40
|
-
throw new common_1.
|
|
40
|
+
throw new common_1.ResourceNotAvailableError(this.getResourceName(), id);
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Creates a new document in the MongoDB collection.
|
|
@@ -48,14 +48,16 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
48
48
|
* @throws {Error} if an unknown error occurs while creating the document.
|
|
49
49
|
*/
|
|
50
50
|
async create(input, options) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
const info = {
|
|
52
|
+
crud: 'create',
|
|
53
|
+
method: 'create',
|
|
54
|
+
documentId: input._id,
|
|
55
|
+
input,
|
|
56
|
+
options
|
|
57
|
+
};
|
|
58
|
+
return this._intercept(() => this._create(input, options), info);
|
|
59
|
+
}
|
|
60
|
+
async _create(input, options) {
|
|
59
61
|
const encode = this.getEncoder('create');
|
|
60
62
|
const doc = encode(input, { coerce: true });
|
|
61
63
|
doc._id = doc._id || this._generateId();
|
|
@@ -63,16 +65,16 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
63
65
|
if (r.insertedId) {
|
|
64
66
|
if (!options)
|
|
65
67
|
return doc;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
const out = await this._findById(doc._id, {
|
|
69
|
+
...options,
|
|
70
|
+
filter: undefined,
|
|
71
|
+
skip: undefined
|
|
72
|
+
});
|
|
73
|
+
if (out)
|
|
74
|
+
return out;
|
|
73
75
|
}
|
|
74
76
|
/* istanbul ignore next */
|
|
75
|
-
throw new
|
|
77
|
+
throw new common_1.InternalServerError(`Unknown error while creating document for "${this.getResourceName()}"`);
|
|
76
78
|
}
|
|
77
79
|
/**
|
|
78
80
|
* Returns the count of documents in the collection based on the provided options.
|
|
@@ -81,13 +83,21 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
81
83
|
* @return {Promise<number>} - A promise that resolves to the count of documents in the collection.
|
|
82
84
|
*/
|
|
83
85
|
async count(options) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
const info = {
|
|
87
|
+
crud: 'read',
|
|
88
|
+
method: 'count',
|
|
89
|
+
options
|
|
90
|
+
};
|
|
91
|
+
return this._intercept(async () => {
|
|
92
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
93
|
+
await this._getDocumentFilter(info),
|
|
94
|
+
options?.filter
|
|
95
|
+
]);
|
|
96
|
+
return this._count({ ...options, filter });
|
|
97
|
+
}, info);
|
|
98
|
+
}
|
|
99
|
+
async _count(options) {
|
|
100
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
91
101
|
return this.__countDocuments(filter, (0, lodash_omit_1.default)(options, 'filter'));
|
|
92
102
|
}
|
|
93
103
|
/**
|
|
@@ -98,17 +108,24 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
98
108
|
* @return {Promise<number>} - A Promise that resolves to the number of documents deleted.
|
|
99
109
|
*/
|
|
100
110
|
async delete(id, options) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
const info = {
|
|
112
|
+
crud: 'delete',
|
|
113
|
+
method: 'delete',
|
|
114
|
+
documentId: id,
|
|
115
|
+
options
|
|
116
|
+
};
|
|
117
|
+
return this._intercept(async () => {
|
|
118
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
119
|
+
await this._getDocumentFilter(info),
|
|
120
|
+
options?.filter
|
|
121
|
+
]);
|
|
122
|
+
return this._delete(id, { ...options, filter });
|
|
123
|
+
}, info);
|
|
124
|
+
}
|
|
125
|
+
async _delete(id, options) {
|
|
108
126
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
109
127
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
110
|
-
options?.filter
|
|
111
|
-
await this._getDocumentFilter(),
|
|
128
|
+
options?.filter
|
|
112
129
|
]);
|
|
113
130
|
const r = await this.__deleteOne(filter, options);
|
|
114
131
|
return r.deletedCount;
|
|
@@ -120,13 +137,21 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
120
137
|
* @return {Promise<number>} - A promise that resolves to the number of documents deleted.
|
|
121
138
|
*/
|
|
122
139
|
async deleteMany(options) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
140
|
+
const info = {
|
|
141
|
+
crud: 'delete',
|
|
142
|
+
method: 'delete',
|
|
143
|
+
options
|
|
144
|
+
};
|
|
145
|
+
return this._intercept(async () => {
|
|
146
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
147
|
+
await this._getDocumentFilter(info),
|
|
148
|
+
options?.filter,
|
|
149
|
+
]);
|
|
150
|
+
return this._deleteMany({ ...options, filter });
|
|
151
|
+
}, info);
|
|
152
|
+
}
|
|
153
|
+
async _deleteMany(options) {
|
|
154
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
130
155
|
const r = await this.__deleteMany(filter, (0, lodash_omit_1.default)(options, 'filter'));
|
|
131
156
|
return r.deletedCount;
|
|
132
157
|
}
|
|
@@ -134,18 +159,20 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
134
159
|
* Checks if an object with the given id exists.
|
|
135
160
|
*
|
|
136
161
|
* @param {AnyId} id - The id of the object to check.
|
|
137
|
-
* @param {MongoCollectionService.ExistsOptions} [options] - The options for the
|
|
162
|
+
* @param {MongoCollectionService.ExistsOptions} [options] - The options for the query (optional).
|
|
138
163
|
* @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
|
|
139
164
|
*/
|
|
140
165
|
async exists(id, options) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
166
|
+
return !!(await this.findById(id, { ...options, pick: ['_id'], omit: undefined, include: undefined }));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Checks if an object with the given arguments exists.
|
|
170
|
+
*
|
|
171
|
+
* @param {MongoCollectionService.ExistsOneOptions} [options] - The options for the query (optional).
|
|
172
|
+
* @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
|
|
173
|
+
*/
|
|
174
|
+
async existsOne(options) {
|
|
175
|
+
return !!(await this.findOne({ ...options, pick: ['_id'], omit: undefined, include: undefined }));
|
|
149
176
|
}
|
|
150
177
|
/**
|
|
151
178
|
* Finds a document by its ID.
|
|
@@ -155,18 +182,36 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
155
182
|
* @return {Promise<PartialDTO<T | undefined>>} - A promise resolving to the found document, or undefined if not found.
|
|
156
183
|
*/
|
|
157
184
|
async findById(id, options) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
185
|
+
const info = {
|
|
186
|
+
crud: 'read',
|
|
187
|
+
method: 'findById',
|
|
188
|
+
documentId: id,
|
|
189
|
+
options
|
|
190
|
+
};
|
|
191
|
+
return this._intercept(async () => {
|
|
192
|
+
const documentFilter = await this._getDocumentFilter(info);
|
|
193
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
194
|
+
documentFilter,
|
|
195
|
+
options?.filter,
|
|
196
|
+
]);
|
|
197
|
+
return this._findById(id, { ...options, filter });
|
|
198
|
+
}, info);
|
|
199
|
+
}
|
|
200
|
+
async _findById(id, options) {
|
|
165
201
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
166
202
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
167
203
|
options?.filter
|
|
168
204
|
]);
|
|
169
|
-
|
|
205
|
+
const mongoOptions = {
|
|
206
|
+
...options,
|
|
207
|
+
limit: undefined,
|
|
208
|
+
skip: undefined,
|
|
209
|
+
sort: undefined,
|
|
210
|
+
projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
211
|
+
};
|
|
212
|
+
const decode = this.getDecoder();
|
|
213
|
+
const out = await this.__findOne(filter, mongoOptions);
|
|
214
|
+
return out ? decode(out, { coerce: true }) : undefined;
|
|
170
215
|
}
|
|
171
216
|
/**
|
|
172
217
|
* Finds a document in the collection that matches the specified options.
|
|
@@ -175,13 +220,21 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
175
220
|
* @return {Promise<PartialDTO<T> | undefined>} A promise that resolves with the found document or undefined if no document is found.
|
|
176
221
|
*/
|
|
177
222
|
async findOne(options) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
223
|
+
const info = {
|
|
224
|
+
crud: 'read',
|
|
225
|
+
method: 'findOne',
|
|
226
|
+
options
|
|
227
|
+
};
|
|
228
|
+
return this._intercept(async () => {
|
|
229
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
230
|
+
await this._getDocumentFilter(info),
|
|
231
|
+
options?.filter,
|
|
232
|
+
]);
|
|
233
|
+
return this._findOne({ ...options, filter });
|
|
234
|
+
}, info);
|
|
235
|
+
}
|
|
236
|
+
async _findOne(options) {
|
|
237
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
185
238
|
const mongoOptions = {
|
|
186
239
|
...options,
|
|
187
240
|
sort: options?.sort ? mongo_adapter_js_1.MongoAdapter.prepareSort(options.sort) : undefined,
|
|
@@ -208,12 +261,20 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
208
261
|
* @return A Promise that resolves to an array of partial outputs of type T.
|
|
209
262
|
*/
|
|
210
263
|
async findMany(options) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
264
|
+
const info = {
|
|
265
|
+
crud: 'read',
|
|
266
|
+
method: 'findMany',
|
|
267
|
+
options
|
|
268
|
+
};
|
|
269
|
+
return this._intercept(async () => {
|
|
270
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
271
|
+
await this._getDocumentFilter(info),
|
|
272
|
+
options?.filter,
|
|
273
|
+
]);
|
|
274
|
+
return this._findMany({ ...options, filter });
|
|
275
|
+
}, info);
|
|
276
|
+
}
|
|
277
|
+
async _findMany(options) {
|
|
217
278
|
const mongoOptions = {
|
|
218
279
|
...(0, lodash_omit_1.default)(options, ['pick', 'include', 'omit', 'sort', 'skip', 'limit', 'filter', 'count'])
|
|
219
280
|
};
|
|
@@ -229,10 +290,9 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
229
290
|
}
|
|
230
291
|
});
|
|
231
292
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
dataStages.push({ $match: optionsFilter });
|
|
293
|
+
if (options?.filter) {
|
|
294
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
295
|
+
dataStages.push({ $match: filter });
|
|
236
296
|
}
|
|
237
297
|
if (options?.skip)
|
|
238
298
|
dataStages.push({ $skip: options.skip });
|
|
@@ -271,12 +331,12 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
271
331
|
* @param {MongoCollectionService.FindOneOptions} [options] - Optional options for the findOne operation.
|
|
272
332
|
* @returns {Promise<PartialDTO<T>>} - A promise that resolves to the retrieved document,
|
|
273
333
|
* or rejects with a ResourceNotFoundError if the document does not exist.
|
|
274
|
-
* @throws {
|
|
334
|
+
* @throws {ResourceNotAvailableError} - If the document with the specified ID does not exist.
|
|
275
335
|
*/
|
|
276
336
|
async get(id, options) {
|
|
277
337
|
const out = await this.findById(id, options);
|
|
278
338
|
if (!out)
|
|
279
|
-
throw new common_1.
|
|
339
|
+
throw new common_1.ResourceNotAvailableError(this.getResourceName(), id);
|
|
280
340
|
return out;
|
|
281
341
|
}
|
|
282
342
|
/**
|
|
@@ -289,14 +349,22 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
289
349
|
* undefined if the document was not found.
|
|
290
350
|
*/
|
|
291
351
|
async update(id, input, options) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
352
|
+
const info = {
|
|
353
|
+
crud: 'update',
|
|
354
|
+
method: 'update',
|
|
355
|
+
documentId: id,
|
|
356
|
+
input,
|
|
357
|
+
options,
|
|
358
|
+
};
|
|
359
|
+
return this._intercept(async () => {
|
|
360
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
361
|
+
await this._getDocumentFilter(info),
|
|
362
|
+
options?.filter
|
|
363
|
+
]);
|
|
364
|
+
return this._update(id, input, { ...options, filter });
|
|
365
|
+
}, info);
|
|
366
|
+
}
|
|
367
|
+
async _update(id, input, options) {
|
|
300
368
|
const encode = this.getEncoder('update');
|
|
301
369
|
const doc = encode(input, { coerce: true });
|
|
302
370
|
const patch = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
@@ -308,8 +376,7 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
308
376
|
};
|
|
309
377
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
310
378
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
311
|
-
options?.filter
|
|
312
|
-
await this._getDocumentFilter()
|
|
379
|
+
options?.filter
|
|
313
380
|
]);
|
|
314
381
|
const decode = this.getDecoder();
|
|
315
382
|
const out = await this.__findOneAndUpdate(filter, patch, mongoOptions);
|
|
@@ -324,18 +391,25 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
324
391
|
* @returns {Promise<number>} - A promise that resolves to the number of documents modified.
|
|
325
392
|
*/
|
|
326
393
|
async updateOnly(id, input, options) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
394
|
+
const info = {
|
|
395
|
+
crud: 'update',
|
|
396
|
+
method: 'update',
|
|
397
|
+
documentId: id,
|
|
398
|
+
input,
|
|
399
|
+
options,
|
|
400
|
+
};
|
|
401
|
+
return this._intercept(async () => {
|
|
402
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
403
|
+
await this._getDocumentFilter(info),
|
|
404
|
+
options?.filter
|
|
405
|
+
]);
|
|
406
|
+
return this._updateOnly(id, input, { ...options, filter });
|
|
407
|
+
}, info);
|
|
408
|
+
}
|
|
409
|
+
async _updateOnly(id, input, options) {
|
|
335
410
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
336
411
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
337
|
-
options?.filter
|
|
338
|
-
await this._getDocumentFilter()
|
|
412
|
+
options?.filter
|
|
339
413
|
]);
|
|
340
414
|
const encode = this.getEncoder('update');
|
|
341
415
|
const doc = encode(input, { coerce: true });
|
|
@@ -359,13 +433,21 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
359
433
|
* @return {Promise<number>} - A promise that resolves to the number of documents matched and modified.
|
|
360
434
|
*/
|
|
361
435
|
async updateMany(input, options) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
436
|
+
const info = {
|
|
437
|
+
crud: 'update',
|
|
438
|
+
method: 'updateMany',
|
|
439
|
+
input,
|
|
440
|
+
options,
|
|
441
|
+
};
|
|
442
|
+
return this._intercept(async () => {
|
|
443
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
444
|
+
await this._getDocumentFilter(info),
|
|
445
|
+
options?.filter
|
|
446
|
+
]);
|
|
447
|
+
return this._updateMany(input, { ...options, filter });
|
|
448
|
+
}, info);
|
|
449
|
+
}
|
|
450
|
+
async _updateMany(input, options) {
|
|
369
451
|
const encode = this.getEncoder('update');
|
|
370
452
|
const doc = encode(input, { coerce: true });
|
|
371
453
|
if (!Object.keys(doc).length)
|
|
@@ -376,7 +458,7 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
376
458
|
...(0, lodash_omit_1.default)(options, 'filter'),
|
|
377
459
|
upsert: undefined
|
|
378
460
|
};
|
|
379
|
-
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(
|
|
461
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
380
462
|
const r = await this.__updateMany(filter, patch, mongoOptions);
|
|
381
463
|
return r.matchedCount;
|
|
382
464
|
}
|
|
@@ -398,9 +480,14 @@ class MongoCollectionService extends mongo_service_js_1.MongoService {
|
|
|
398
480
|
* @returns {FilterInput | Promise<FilterInput> | undefined} The common filter or a Promise
|
|
399
481
|
* that resolves to the common filter, or undefined if not available.
|
|
400
482
|
*/
|
|
401
|
-
_getDocumentFilter() {
|
|
483
|
+
_getDocumentFilter(args) {
|
|
402
484
|
return typeof this.$documentFilter === 'function' ?
|
|
403
|
-
this.$documentFilter(this) : this.$documentFilter;
|
|
485
|
+
this.$documentFilter(args, this) : this.$documentFilter;
|
|
486
|
+
}
|
|
487
|
+
async _intercept(callback, args) {
|
|
488
|
+
if (this.$interceptor)
|
|
489
|
+
return this.$interceptor(callback, args, this);
|
|
490
|
+
return callback();
|
|
404
491
|
}
|
|
405
492
|
}
|
|
406
493
|
exports.MongoCollectionService = MongoCollectionService;
|
package/cjs/mongo-service.js
CHANGED
|
@@ -47,7 +47,7 @@ class MongoService extends core_1.ApiService {
|
|
|
47
47
|
* Retrieves the encoder for the specified operation.
|
|
48
48
|
*
|
|
49
49
|
* @param {String} operation - The operation to retrieve the encoder for. Valid values are 'create' and 'update'.
|
|
50
|
-
* @returns {
|
|
50
|
+
* @returns {IsObject.Validator<T>} - The encoder for the specified operation.
|
|
51
51
|
*/
|
|
52
52
|
getEncoder(operation) {
|
|
53
53
|
let encoder = this._encoders[operation];
|
|
@@ -60,7 +60,7 @@ class MongoService extends core_1.ApiService {
|
|
|
60
60
|
/**
|
|
61
61
|
* Retrieves the decoder.
|
|
62
62
|
*
|
|
63
|
-
* @returns {
|
|
63
|
+
* @returns {IsObject.Validator<T>} - The encoder for the specified operation.
|
|
64
64
|
*/
|
|
65
65
|
getDecoder() {
|
|
66
66
|
let decoder = this._decoder;
|
|
@@ -70,6 +70,48 @@ class MongoService extends core_1.ApiService {
|
|
|
70
70
|
this._decoder = decoder;
|
|
71
71
|
return decoder;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Executes the provided function within a transaction.
|
|
75
|
+
*
|
|
76
|
+
* @param {WithTransactionCallback} callback - The function to be executed within the transaction.
|
|
77
|
+
* @param {TransactionOptions} [options] - Optional options for the transaction.
|
|
78
|
+
* @returns {Promise<any>} - A promise that resolves with the result of the function execution within the transaction.
|
|
79
|
+
*/
|
|
80
|
+
async withTransaction(callback, options) {
|
|
81
|
+
let session = this.getSession();
|
|
82
|
+
if (session)
|
|
83
|
+
return callback(session);
|
|
84
|
+
// Backup old session property
|
|
85
|
+
const hasOldSession = this.hasOwnProperty('session');
|
|
86
|
+
const oldSessionGetter = hasOldSession ? this.session : undefined;
|
|
87
|
+
const db = this.getDatabase();
|
|
88
|
+
const client = db.client;
|
|
89
|
+
session = client.startSession();
|
|
90
|
+
this.session = session;
|
|
91
|
+
const oldInTransaction = session.inTransaction();
|
|
92
|
+
try {
|
|
93
|
+
if (!oldInTransaction)
|
|
94
|
+
session.startTransaction(options);
|
|
95
|
+
const out = await callback(session);
|
|
96
|
+
if (!oldInTransaction)
|
|
97
|
+
await session.commitTransaction();
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
if (!oldInTransaction)
|
|
102
|
+
await session.abortTransaction();
|
|
103
|
+
throw e;
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
// Restore old session property
|
|
107
|
+
if (hasOldSession) {
|
|
108
|
+
this.session = oldSessionGetter;
|
|
109
|
+
await session.endSession();
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
delete this.session;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
73
115
|
/**
|
|
74
116
|
* Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,
|
|
75
117
|
* one will be added to each of the documents missing it by the driver, mutating the document. This behavior
|
|
@@ -379,59 +421,31 @@ class MongoService extends core_1.ApiService {
|
|
|
379
421
|
return out;
|
|
380
422
|
throw new Error('resourceName is not defined');
|
|
381
423
|
}
|
|
382
|
-
/**
|
|
383
|
-
* Compares the current instance with the provided attributes and returns true if they match, false otherwise.
|
|
384
|
-
* This method is protected and should only be called by subclasses.
|
|
385
|
-
*
|
|
386
|
-
* @param {MongoService<any>} service - The service instance to compare.
|
|
387
|
-
* @param {RequestContext} context - The request context.
|
|
388
|
-
* @param {Object} attributes - Optional attributes object for comparison.
|
|
389
|
-
* @return {boolean} - True if the instance matches the provided attributes, false otherwise.
|
|
390
|
-
* @protected
|
|
391
|
-
*/
|
|
392
|
-
_instanceCompare(service, context, attributes) {
|
|
393
|
-
return super._instanceCompare(service, context, attributes) &&
|
|
394
|
-
(!attributes?.db ||
|
|
395
|
-
(typeof service.db === 'object' && service.db === attributes.db) ||
|
|
396
|
-
(typeof service.db === 'function' && service.getDatabase() === attributes.db)) &&
|
|
397
|
-
(!attributes?.session ||
|
|
398
|
-
(typeof service.session === 'object' && service.session === attributes?.session) ||
|
|
399
|
-
(typeof service.session === 'function' && service.getSession() === attributes?.session));
|
|
400
|
-
}
|
|
401
424
|
/**
|
|
402
425
|
* Generates an encoder for the specified operation.
|
|
403
426
|
*
|
|
404
427
|
* @param {string} operation - The operation to generate the encoder for. Must be either 'create' or 'update'.
|
|
405
428
|
* @protected
|
|
406
|
-
* @returns {
|
|
429
|
+
* @returns {IsObject.Validator} - The generated encoder for the specified operation.
|
|
407
430
|
*/
|
|
408
431
|
_generateEncoder(operation) {
|
|
409
|
-
let encoder = this._encoders[operation];
|
|
410
|
-
if (encoder)
|
|
411
|
-
return encoder;
|
|
412
432
|
const dataType = this.getDataType();
|
|
413
433
|
const options = {};
|
|
414
434
|
if (operation === 'update') {
|
|
415
435
|
options.omit = ['_id'];
|
|
416
436
|
options.partial = true;
|
|
417
437
|
}
|
|
418
|
-
|
|
419
|
-
this._encoders[operation] = encoder;
|
|
420
|
-
return encoder;
|
|
438
|
+
return dataType.generateCodec('encode', options);
|
|
421
439
|
}
|
|
422
440
|
/**
|
|
423
441
|
* Generates an encoder for the specified operation.
|
|
424
442
|
*
|
|
425
443
|
* @protected
|
|
426
|
-
* @returns {
|
|
444
|
+
* @returns {IsObject.Validator} - The generated encoder for the specified operation.
|
|
427
445
|
*/
|
|
428
446
|
_generateDecoder() {
|
|
429
|
-
let decoder = this._decoder;
|
|
430
|
-
if (decoder)
|
|
431
|
-
return decoder;
|
|
432
447
|
const dataType = this.getDataType();
|
|
433
|
-
|
|
434
|
-
return decoder;
|
|
448
|
+
return dataType.generateCodec('decode', { partial: true });
|
|
435
449
|
}
|
|
436
450
|
}
|
|
437
451
|
exports.MongoService = MongoService;
|