@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.
- package/cjs/adapter-utils/prepare-filter.js +3 -1
- package/cjs/adapter-utils/prepare-key-values.js +5 -4
- package/cjs/adapter-utils/prepare-patch.js +3 -2
- package/cjs/adapter-utils/prepare-projection.js +2 -3
- package/cjs/adapter-utils/prepare-sort.js +1 -1
- package/cjs/index.js +1 -1
- package/cjs/mongo-adapter.js +9 -4
- package/cjs/mongo-collection-service.js +111 -94
- package/cjs/mongo-entity-service.js +116 -93
- package/cjs/mongo-nested-service.js +262 -144
- package/cjs/mongo-service.js +62 -50
- package/cjs/mongo-singleton-service.js +62 -42
- package/esm/adapter-utils/prepare-filter.js +2 -0
- package/esm/adapter-utils/prepare-key-values.js +4 -3
- package/esm/adapter-utils/prepare-patch.js +2 -1
- package/esm/index.js +1 -1
- package/esm/mongo-adapter.js +9 -4
- package/esm/mongo-collection-service.js +111 -94
- package/esm/mongo-entity-service.js +116 -93
- package/esm/mongo-nested-service.js +262 -144
- package/esm/mongo-service.js +62 -50
- package/esm/mongo-singleton-service.js +62 -42
- package/package.json +12 -6
- package/types/adapter-utils/prepare-projection.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/mongo-adapter.d.ts +1 -1
- package/types/mongo-collection-service.d.ts +32 -62
- package/types/mongo-entity-service.d.ts +73 -47
- package/types/mongo-nested-service.d.ts +63 -28
- package/types/mongo-service.d.ts +44 -41
- package/types/mongo-singleton-service.d.ts +19 -29
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import omit from 'lodash.omit';
|
|
2
|
-
import * as assert from 'node:assert';
|
|
3
1
|
import { InternalServerError } from '@opra/common';
|
|
2
|
+
import omit from 'lodash.omit';
|
|
3
|
+
import { isNotNullish } from 'valgen';
|
|
4
4
|
import { MongoAdapter } from './mongo-adapter.js';
|
|
5
5
|
import { MongoService } from './mongo-service.js';
|
|
6
6
|
/**
|
|
@@ -21,19 +21,27 @@ export class MongoEntityService extends MongoService {
|
|
|
21
21
|
/**
|
|
22
22
|
* Creates a new document in the MongoDB collection.
|
|
23
23
|
*
|
|
24
|
-
* @param {
|
|
25
|
-
* @param {MongoEntityService.CreateOptions} options
|
|
24
|
+
* @param {MongoEntityService.CreateCommand} command
|
|
26
25
|
* @protected
|
|
27
26
|
*/
|
|
28
|
-
async _create(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
async _create(command) {
|
|
28
|
+
isNotNullish(command.input, { label: 'input' });
|
|
29
|
+
isNotNullish(command.input._id, { label: 'input._id' });
|
|
30
|
+
const inputCodec = this.getInputCodec('create');
|
|
31
|
+
const doc = inputCodec(command.input);
|
|
32
|
+
const { options } = command;
|
|
32
33
|
const r = await this._dbInsertOne(doc, options);
|
|
33
34
|
if (r.insertedId) {
|
|
34
|
-
if (!options)
|
|
35
|
+
if (!command.options)
|
|
35
36
|
return doc;
|
|
36
|
-
const
|
|
37
|
+
const findCommand = {
|
|
38
|
+
...command,
|
|
39
|
+
crud: 'read',
|
|
40
|
+
byId: true,
|
|
41
|
+
documentId: doc._id,
|
|
42
|
+
options: omit(options, 'filter'),
|
|
43
|
+
};
|
|
44
|
+
const out = await this._findById(findCommand);
|
|
37
45
|
if (out)
|
|
38
46
|
return out;
|
|
39
47
|
}
|
|
@@ -43,92 +51,103 @@ export class MongoEntityService extends MongoService {
|
|
|
43
51
|
/**
|
|
44
52
|
* Returns the count of documents in the collection based on the provided options.
|
|
45
53
|
*
|
|
46
|
-
* @param {MongoEntityService.
|
|
47
|
-
* @
|
|
54
|
+
* @param {MongoEntityService.CountCommand<T>} command
|
|
55
|
+
* @protected
|
|
48
56
|
*/
|
|
49
|
-
async _count(
|
|
57
|
+
async _count(command) {
|
|
58
|
+
const { options } = command;
|
|
50
59
|
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
51
60
|
return this._dbCountDocuments(filter, omit(options, 'filter'));
|
|
52
61
|
}
|
|
53
62
|
/**
|
|
54
63
|
* Deletes a document from the collection.
|
|
55
64
|
*
|
|
56
|
-
* @param {
|
|
57
|
-
* @
|
|
58
|
-
* @return {Promise<number>} - A Promise that resolves to the number of documents deleted.
|
|
65
|
+
* @param {MongoEntityService.DeleteCommand<T>} command
|
|
66
|
+
* @protected
|
|
59
67
|
*/
|
|
60
|
-
async _delete(
|
|
61
|
-
|
|
62
|
-
const
|
|
68
|
+
async _delete(command) {
|
|
69
|
+
isNotNullish(command.documentId, { label: 'documentId' });
|
|
70
|
+
const { options } = command;
|
|
71
|
+
const filter = MongoAdapter.prepareFilter([
|
|
72
|
+
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
73
|
+
options?.filter,
|
|
74
|
+
]);
|
|
63
75
|
const r = await this._dbDeleteOne(filter, options);
|
|
64
76
|
return r.deletedCount;
|
|
65
77
|
}
|
|
66
78
|
/**
|
|
67
79
|
* Deletes multiple documents from the collection that meet the specified filter criteria.
|
|
68
80
|
*
|
|
69
|
-
* @param {MongoEntityService.
|
|
70
|
-
* @
|
|
81
|
+
* @param {MongoEntityService.DeleteCommand<T>} command
|
|
82
|
+
* @protected
|
|
71
83
|
*/
|
|
72
|
-
async _deleteMany(
|
|
84
|
+
async _deleteMany(command) {
|
|
85
|
+
const { options } = command;
|
|
73
86
|
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
74
87
|
const r = await this._dbDeleteMany(filter, omit(options, 'filter'));
|
|
75
88
|
return r.deletedCount;
|
|
76
89
|
}
|
|
77
90
|
/**
|
|
78
91
|
* The distinct command returns a list of distinct values for the given key across a collection.
|
|
79
|
-
*
|
|
80
|
-
* @param {MongoEntityService.
|
|
92
|
+
*
|
|
93
|
+
* @param {MongoEntityService.DistinctCommand<T>} command
|
|
81
94
|
* @protected
|
|
82
95
|
*/
|
|
83
|
-
async _distinct(
|
|
96
|
+
async _distinct(command) {
|
|
97
|
+
const { options, field } = command;
|
|
84
98
|
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
85
99
|
return await this._dbDistinct(field, filter, omit(options, 'filter'));
|
|
86
100
|
}
|
|
87
101
|
/**
|
|
88
102
|
* Finds a document by its ID.
|
|
89
103
|
*
|
|
90
|
-
* @param {
|
|
91
|
-
* @param {MongoEntityService.FindOneOptions<T>} [options] - The options for the find query.
|
|
92
|
-
* @return {Promise<PartialDTO<T | undefined>>} - A promise resolving to the found document, or undefined if not found.
|
|
104
|
+
* @param { MongoEntityService.FindOneCommand<T>} command
|
|
93
105
|
*/
|
|
94
|
-
async _findById(
|
|
95
|
-
|
|
106
|
+
async _findById(command) {
|
|
107
|
+
isNotNullish(command.documentId, { label: 'documentId' });
|
|
108
|
+
const filter = MongoAdapter.prepareFilter([
|
|
109
|
+
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
110
|
+
command.options?.filter,
|
|
111
|
+
]);
|
|
112
|
+
const { options } = command;
|
|
96
113
|
const mongoOptions = {
|
|
97
114
|
...options,
|
|
98
|
-
projection: MongoAdapter.prepareProjection(this.
|
|
115
|
+
projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
99
116
|
limit: undefined,
|
|
100
117
|
skip: undefined,
|
|
101
118
|
sort: undefined,
|
|
102
119
|
};
|
|
103
|
-
const decode = this.getDecoder();
|
|
104
120
|
const out = await this._dbFindOne(filter, mongoOptions);
|
|
105
|
-
|
|
121
|
+
const outputCodec = this.getOutputCodec('find');
|
|
122
|
+
if (out)
|
|
123
|
+
return outputCodec(out);
|
|
106
124
|
}
|
|
107
125
|
/**
|
|
108
126
|
* Finds a document in the collection that matches the specified options.
|
|
109
127
|
*
|
|
110
|
-
* @param {MongoEntityService.
|
|
111
|
-
* @return {Promise<PartialDTO<T> | undefined>} A promise that resolves with the found document or undefined if no document is found.
|
|
128
|
+
* @param {MongoEntityService.FindOneCommand<T>} command
|
|
112
129
|
*/
|
|
113
|
-
async _findOne(
|
|
130
|
+
async _findOne(command) {
|
|
131
|
+
const { options } = command;
|
|
114
132
|
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
115
133
|
const mongoOptions = {
|
|
116
134
|
...omit(options, 'filter'),
|
|
117
135
|
sort: options?.sort ? MongoAdapter.prepareSort(options.sort) : undefined,
|
|
118
|
-
projection: MongoAdapter.prepareProjection(this.
|
|
136
|
+
projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
119
137
|
limit: undefined,
|
|
120
138
|
};
|
|
121
|
-
const decode = this.getDecoder();
|
|
122
139
|
const out = await this._dbFindOne(filter, mongoOptions);
|
|
123
|
-
|
|
140
|
+
const outputCodec = this.getOutputCodec('find');
|
|
141
|
+
if (out)
|
|
142
|
+
return outputCodec(out);
|
|
124
143
|
}
|
|
125
144
|
/**
|
|
126
145
|
* Finds multiple documents in the MongoDB collection.
|
|
127
146
|
*
|
|
128
|
-
* @param {MongoEntityService.
|
|
129
|
-
* @return A Promise that resolves to an array of partial outputs of type T.
|
|
147
|
+
* @param {MongoEntityService.FindManyCommand<T>} command
|
|
130
148
|
*/
|
|
131
|
-
async _findMany(
|
|
149
|
+
async _findMany(command) {
|
|
150
|
+
const { options } = command;
|
|
132
151
|
const mongoOptions = {
|
|
133
152
|
...omit(options, ['projection', 'sort', 'skip', 'limit', 'filter']),
|
|
134
153
|
};
|
|
@@ -147,16 +166,16 @@ export class MongoEntityService extends MongoService {
|
|
|
147
166
|
stages.push({ $sort: sort });
|
|
148
167
|
}
|
|
149
168
|
stages.push({ $limit: limit });
|
|
150
|
-
const dataType = this.
|
|
169
|
+
const dataType = this.dataType;
|
|
151
170
|
const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
|
|
152
171
|
if (projection)
|
|
153
172
|
stages.push({ $project: projection });
|
|
154
|
-
const decode = this.getDecoder();
|
|
155
173
|
const cursor = await this._dbAggregate(stages, mongoOptions);
|
|
156
174
|
/** Execute db command */
|
|
157
175
|
try {
|
|
158
176
|
/** Fetch the cursor and decode the result objects */
|
|
159
|
-
|
|
177
|
+
const outputCodec = this.getOutputCodec('find');
|
|
178
|
+
return (await cursor.toArray()).map((r) => outputCodec(r));
|
|
160
179
|
}
|
|
161
180
|
finally {
|
|
162
181
|
if (!cursor.closed)
|
|
@@ -167,10 +186,10 @@ export class MongoEntityService extends MongoService {
|
|
|
167
186
|
* Finds multiple documents in the collection and returns both records (max limit)
|
|
168
187
|
* and total count that matched the given criteria
|
|
169
188
|
*
|
|
170
|
-
* @param {MongoEntityService.
|
|
171
|
-
* @return A Promise that resolves to an array of partial outputs of type T.
|
|
189
|
+
* @param {MongoEntityService.FindManyCommand<T>} command
|
|
172
190
|
*/
|
|
173
|
-
async _findManyWithCount(
|
|
191
|
+
async _findManyWithCount(command) {
|
|
192
|
+
const { options } = command;
|
|
174
193
|
const mongoOptions = {
|
|
175
194
|
...omit(options, ['projection', 'sort', 'skip', 'limit', 'filter']),
|
|
176
195
|
};
|
|
@@ -201,11 +220,11 @@ export class MongoEntityService extends MongoService {
|
|
|
201
220
|
dataStages.push({ $sort: sort });
|
|
202
221
|
}
|
|
203
222
|
dataStages.push({ $limit: limit });
|
|
204
|
-
const dataType = this.
|
|
223
|
+
const dataType = this.dataType;
|
|
205
224
|
const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
|
|
206
225
|
if (projection)
|
|
207
226
|
dataStages.push({ $project: projection });
|
|
208
|
-
const
|
|
227
|
+
const outputCodec = this.getOutputCodec('find');
|
|
209
228
|
/** Execute db command */
|
|
210
229
|
const cursor = await this._dbAggregate(stages, mongoOptions);
|
|
211
230
|
try {
|
|
@@ -213,7 +232,7 @@ export class MongoEntityService extends MongoService {
|
|
|
213
232
|
const facetResult = await cursor.toArray();
|
|
214
233
|
return {
|
|
215
234
|
count: facetResult[0].count[0]?.totalMatches || 0,
|
|
216
|
-
items: facetResult[0].data?.map((r) =>
|
|
235
|
+
items: facetResult[0].data?.map((r) => outputCodec(r)),
|
|
217
236
|
};
|
|
218
237
|
}
|
|
219
238
|
finally {
|
|
@@ -224,68 +243,72 @@ export class MongoEntityService extends MongoService {
|
|
|
224
243
|
/**
|
|
225
244
|
* Updates a document with the given id in the collection.
|
|
226
245
|
*
|
|
227
|
-
* @param {
|
|
228
|
-
* @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input object containing the fields to update.
|
|
229
|
-
* @param {MongoEntityService.UpdateOptions<T>} [options] - The options for the update operation.
|
|
230
|
-
* @returns {Promise<PartialDTO<T> | undefined>} A promise that resolves to the updated document or
|
|
231
|
-
* undefined if the document was not found.
|
|
246
|
+
* @param {MongoEntityService.UpdateOneCommand<T>} command
|
|
232
247
|
*/
|
|
233
|
-
async _update(
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
248
|
+
async _update(command) {
|
|
249
|
+
isNotNullish(command.documentId, { label: 'documentId' });
|
|
250
|
+
const { input, inputRaw, options } = command;
|
|
251
|
+
isNotNullish(input || inputRaw, { label: 'input' });
|
|
252
|
+
if (input && inputRaw) {
|
|
237
253
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
254
|
+
}
|
|
238
255
|
let update;
|
|
239
|
-
if (
|
|
240
|
-
const
|
|
241
|
-
const doc =
|
|
256
|
+
if (input) {
|
|
257
|
+
const inputCodec = this.getInputCodec('update');
|
|
258
|
+
const doc = inputCodec(input);
|
|
242
259
|
delete doc._id;
|
|
243
260
|
update = MongoAdapter.preparePatch(doc);
|
|
244
261
|
update.$set = update.$set || {};
|
|
245
262
|
}
|
|
246
263
|
else
|
|
247
|
-
update =
|
|
248
|
-
const filter = MongoAdapter.prepareFilter([
|
|
264
|
+
update = inputRaw;
|
|
265
|
+
const filter = MongoAdapter.prepareFilter([
|
|
266
|
+
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
267
|
+
options?.filter,
|
|
268
|
+
]);
|
|
249
269
|
const mongoOptions = {
|
|
250
270
|
...options,
|
|
251
271
|
includeResultMetadata: false,
|
|
252
272
|
upsert: undefined,
|
|
253
|
-
projection: MongoAdapter.prepareProjection(this.
|
|
273
|
+
projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
254
274
|
};
|
|
255
|
-
const decode = this.getDecoder();
|
|
256
275
|
const out = await this._dbFindOneAndUpdate(filter, update, mongoOptions);
|
|
257
|
-
|
|
276
|
+
const outputCodec = this.getOutputCodec('update');
|
|
277
|
+
if (out)
|
|
278
|
+
return outputCodec(out);
|
|
258
279
|
}
|
|
259
280
|
/**
|
|
260
281
|
* Updates a document in the collection with the specified ID.
|
|
261
282
|
*
|
|
262
|
-
* @param {
|
|
263
|
-
* @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input data to update the document with.
|
|
264
|
-
* @param {MongoEntityService.UpdateOptions<T>} [options] - The options for updating the document.
|
|
265
|
-
* @returns {Promise<number>} - A promise that resolves to the number of documents modified.
|
|
283
|
+
* @param {MongoEntityService.UpdateOneCommand<T>} command
|
|
266
284
|
*/
|
|
267
|
-
async _updateOnly(
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
|
|
285
|
+
async _updateOnly(command) {
|
|
286
|
+
isNotNullish(command.documentId, { label: 'documentId' });
|
|
287
|
+
const { input, inputRaw, options } = command;
|
|
288
|
+
isNotNullish(input || inputRaw, { label: 'input' });
|
|
289
|
+
if (input && inputRaw) {
|
|
271
290
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
291
|
+
}
|
|
272
292
|
let update;
|
|
273
|
-
if (
|
|
274
|
-
const
|
|
275
|
-
const doc =
|
|
293
|
+
if (input) {
|
|
294
|
+
const inputCodec = this.getInputCodec('update');
|
|
295
|
+
const doc = inputCodec(input);
|
|
276
296
|
delete doc._id;
|
|
277
297
|
update = MongoAdapter.preparePatch(doc);
|
|
278
298
|
if (!Object.keys(doc).length)
|
|
279
299
|
return 0;
|
|
280
300
|
}
|
|
281
301
|
else
|
|
282
|
-
update =
|
|
283
|
-
const filter = MongoAdapter.prepareFilter([
|
|
302
|
+
update = inputRaw;
|
|
303
|
+
const filter = MongoAdapter.prepareFilter([
|
|
304
|
+
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
305
|
+
options?.filter,
|
|
306
|
+
]);
|
|
284
307
|
const mongoOptions = {
|
|
285
308
|
...options,
|
|
286
309
|
includeResultMetadata: false,
|
|
287
310
|
upsert: undefined,
|
|
288
|
-
projection: MongoAdapter.prepareProjection(this.
|
|
311
|
+
projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
289
312
|
};
|
|
290
313
|
const out = await this._dbUpdateOne(filter, update, mongoOptions);
|
|
291
314
|
return out.matchedCount;
|
|
@@ -293,26 +316,26 @@ export class MongoEntityService extends MongoService {
|
|
|
293
316
|
/**
|
|
294
317
|
* Updates multiple documents in the collection based on the specified input and options.
|
|
295
318
|
*
|
|
296
|
-
* @param {
|
|
297
|
-
* @param {MongoEntityService.UpdateManyOptions<T>} [options] - The options for updating the documents.
|
|
298
|
-
* @return {Promise<number>} - A promise that resolves to the number of documents matched and modified.
|
|
319
|
+
* @param {MongoEntityService.UpdateManyCommand<T>} command
|
|
299
320
|
*/
|
|
300
|
-
async _updateMany(
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
|
|
321
|
+
async _updateMany(command) {
|
|
322
|
+
isNotNullish(command.input, { label: 'input' });
|
|
323
|
+
const { input, inputRaw, options } = command;
|
|
324
|
+
isNotNullish(input || inputRaw, { label: 'input' });
|
|
325
|
+
if (input && inputRaw) {
|
|
304
326
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
327
|
+
}
|
|
305
328
|
let update;
|
|
306
|
-
if (
|
|
307
|
-
const
|
|
308
|
-
const doc =
|
|
329
|
+
if (input) {
|
|
330
|
+
const inputCodec = this.getInputCodec('update');
|
|
331
|
+
const doc = inputCodec(input);
|
|
309
332
|
delete doc._id;
|
|
310
333
|
update = MongoAdapter.preparePatch(doc);
|
|
311
334
|
if (!Object.keys(doc).length)
|
|
312
335
|
return 0;
|
|
313
336
|
}
|
|
314
337
|
else
|
|
315
|
-
update =
|
|
338
|
+
update = inputRaw;
|
|
316
339
|
const mongoOptions = {
|
|
317
340
|
...omit(options, 'filter'),
|
|
318
341
|
upsert: undefined,
|