@opra/mongodb 0.33.13 → 1.0.0-alpha.2
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 +20 -28
- package/cjs/adapter-utils/prepare-projection.js +40 -39
- package/cjs/index.js +1 -2
- package/cjs/mongo-adapter.js +66 -1
- package/cjs/mongo-collection-service.js +72 -313
- package/cjs/mongo-entity-service.js +329 -0
- package/cjs/{mongo-array-service.js → mongo-nested-service.js} +231 -225
- package/cjs/mongo-service.js +124 -183
- package/cjs/mongo-singleton-service.js +28 -124
- package/esm/adapter-utils/prepare-filter.js +20 -28
- package/esm/adapter-utils/prepare-projection.js +39 -38
- package/esm/index.js +1 -2
- package/esm/mongo-adapter.js +66 -1
- package/esm/mongo-collection-service.js +73 -313
- package/esm/mongo-entity-service.js +324 -0
- package/esm/mongo-nested-service.js +569 -0
- package/esm/mongo-service.js +125 -184
- package/esm/mongo-singleton-service.js +29 -125
- package/package.json +9 -8
- package/types/adapter-utils/prepare-filter.d.ts +2 -3
- package/types/adapter-utils/prepare-projection.d.ts +4 -13
- package/types/index.d.ts +1 -2
- package/types/mongo-adapter.d.ts +14 -1
- package/types/mongo-collection-service.d.ts +88 -251
- package/types/mongo-entity-service.d.ts +149 -0
- package/types/mongo-nested-service.d.ts +258 -0
- package/types/mongo-service.d.ts +208 -82
- package/types/mongo-singleton-service.d.ts +39 -148
- package/cjs/types.js +0 -2
- package/esm/mongo-array-service.js +0 -563
- package/esm/types.js +0 -1
- package/types/mongo-array-service.d.ts +0 -409
- package/types/types.d.ts +0 -3
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import omit from 'lodash.omit';
|
|
2
1
|
import { ObjectId } from 'mongodb';
|
|
3
|
-
import {
|
|
2
|
+
import { ResourceNotAvailableError } from '@opra/common';
|
|
4
3
|
import { MongoAdapter } from './mongo-adapter.js';
|
|
5
|
-
import {
|
|
4
|
+
import { MongoEntityService } from './mongo-entity-service.js';
|
|
6
5
|
/**
|
|
7
6
|
* @class MongoCollectionService
|
|
8
7
|
* @template T - The type of the documents in the collection.
|
|
9
8
|
*/
|
|
10
|
-
export class MongoCollectionService extends
|
|
9
|
+
export class MongoCollectionService extends MongoEntityService {
|
|
11
10
|
/**
|
|
12
11
|
* Constructs a new instance
|
|
13
12
|
*
|
|
@@ -17,17 +16,14 @@ export class MongoCollectionService extends MongoService {
|
|
|
17
16
|
*/
|
|
18
17
|
constructor(dataType, options) {
|
|
19
18
|
super(dataType, options);
|
|
20
|
-
this.collectionKey = this.collectionKey || options?.collectionKey || '_id';
|
|
21
19
|
this.defaultLimit = this.defaultLimit || options?.defaultLimit || 10;
|
|
22
|
-
this.$documentFilter = this.$documentFilter || options?.documentFilter;
|
|
23
|
-
this.$interceptor = this.$interceptor || options?.interceptor;
|
|
24
20
|
}
|
|
25
21
|
/**
|
|
26
22
|
* Asserts the existence of a resource with the given ID.
|
|
27
23
|
* Throws a ResourceNotFoundError if the resource does not exist.
|
|
28
24
|
*
|
|
29
|
-
* @param {AnyId} id - The ID of the resource to assert.
|
|
30
|
-
* @param {MongoCollectionService.ExistsOptions} [options] - Optional options for checking the existence.
|
|
25
|
+
* @param {MongoAdapter.AnyId} id - The ID of the resource to assert.
|
|
26
|
+
* @param {MongoCollectionService.ExistsOptions<T>} [options] - Optional options for checking the existence.
|
|
31
27
|
* @returns {Promise<void>} - A Promise that resolves when the resource exists.
|
|
32
28
|
* @throws {ResourceNotAvailableError} - If the resource does not exist.
|
|
33
29
|
*/
|
|
@@ -37,42 +33,27 @@ export class MongoCollectionService extends MongoService {
|
|
|
37
33
|
}
|
|
38
34
|
/**
|
|
39
35
|
* Creates a new document in the MongoDB collection.
|
|
36
|
+
* Interceptors will be called before performing db operation
|
|
40
37
|
*
|
|
41
|
-
* @param {
|
|
38
|
+
* @param {PartialDTO<T>} input - The input data for creating the document.
|
|
42
39
|
* @param {MongoCollectionService.CreateOptions} [options] - The options for creating the document.
|
|
43
40
|
* @returns {Promise<PartialDTO<T>>} A promise that resolves to the created document.
|
|
44
41
|
* @throws {Error} if an unknown error occurs while creating the document.
|
|
45
42
|
*/
|
|
46
43
|
async create(input, options) {
|
|
44
|
+
const id = input._id || this._generateId();
|
|
45
|
+
if (id != null)
|
|
46
|
+
input._id = id;
|
|
47
47
|
const info = {
|
|
48
48
|
crud: 'create',
|
|
49
49
|
method: 'create',
|
|
50
50
|
byId: false,
|
|
51
|
-
documentId:
|
|
51
|
+
documentId: id,
|
|
52
52
|
input,
|
|
53
|
-
options
|
|
53
|
+
options,
|
|
54
54
|
};
|
|
55
55
|
return this._intercept(() => this._create(input, options), info);
|
|
56
56
|
}
|
|
57
|
-
async _create(input, options) {
|
|
58
|
-
const encode = this.getEncoder('create');
|
|
59
|
-
const doc = encode(input, { coerce: true });
|
|
60
|
-
doc._id = doc._id || this._generateId();
|
|
61
|
-
const r = await this.__insertOne(doc, options);
|
|
62
|
-
if (r.insertedId) {
|
|
63
|
-
if (!options)
|
|
64
|
-
return doc;
|
|
65
|
-
const out = await this._findById(doc._id, {
|
|
66
|
-
...options,
|
|
67
|
-
filter: undefined,
|
|
68
|
-
skip: undefined
|
|
69
|
-
});
|
|
70
|
-
if (out)
|
|
71
|
-
return out;
|
|
72
|
-
}
|
|
73
|
-
/* istanbul ignore next */
|
|
74
|
-
throw new InternalServerError(`Unknown error while creating document for "${this.getResourceName()}"`);
|
|
75
|
-
}
|
|
76
57
|
/**
|
|
77
58
|
* Returns the count of documents in the collection based on the provided options.
|
|
78
59
|
*
|
|
@@ -84,24 +65,17 @@ export class MongoCollectionService extends MongoService {
|
|
|
84
65
|
crud: 'read',
|
|
85
66
|
method: 'count',
|
|
86
67
|
byId: false,
|
|
87
|
-
options
|
|
68
|
+
options,
|
|
88
69
|
};
|
|
89
70
|
return this._intercept(async () => {
|
|
90
|
-
const filter = MongoAdapter.prepareFilter([
|
|
91
|
-
await this._getDocumentFilter(info),
|
|
92
|
-
options?.filter
|
|
93
|
-
]);
|
|
71
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
94
72
|
return this._count({ ...options, filter });
|
|
95
73
|
}, info);
|
|
96
74
|
}
|
|
97
|
-
async _count(options) {
|
|
98
|
-
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
99
|
-
return this.__countDocuments(filter, omit(options, 'filter'));
|
|
100
|
-
}
|
|
101
75
|
/**
|
|
102
76
|
* Deletes a document from the collection.
|
|
103
77
|
*
|
|
104
|
-
* @param {AnyId} id - The ID of the document to delete.
|
|
78
|
+
* @param {MongoAdapter.AnyId} id - The ID of the document to delete.
|
|
105
79
|
* @param {MongoCollectionService.DeleteOptions<T>} [options] - Optional delete options.
|
|
106
80
|
* @return {Promise<number>} - A Promise that resolves to the number of documents deleted.
|
|
107
81
|
*/
|
|
@@ -109,26 +83,15 @@ export class MongoCollectionService extends MongoService {
|
|
|
109
83
|
const info = {
|
|
110
84
|
crud: 'delete',
|
|
111
85
|
method: 'delete',
|
|
112
|
-
byId:
|
|
86
|
+
byId: true,
|
|
113
87
|
documentId: id,
|
|
114
|
-
options
|
|
88
|
+
options,
|
|
115
89
|
};
|
|
116
90
|
return this._intercept(async () => {
|
|
117
|
-
const filter = MongoAdapter.prepareFilter([
|
|
118
|
-
await this._getDocumentFilter(info),
|
|
119
|
-
options?.filter
|
|
120
|
-
]);
|
|
91
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
121
92
|
return this._delete(id, { ...options, filter });
|
|
122
93
|
}, info);
|
|
123
94
|
}
|
|
124
|
-
async _delete(id, options) {
|
|
125
|
-
const filter = MongoAdapter.prepareFilter([
|
|
126
|
-
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
127
|
-
options?.filter
|
|
128
|
-
]);
|
|
129
|
-
const r = await this.__deleteOne(filter, options);
|
|
130
|
-
return r.deletedCount;
|
|
131
|
-
}
|
|
132
95
|
/**
|
|
133
96
|
* Deletes multiple documents from the collection that meet the specified filter criteria.
|
|
134
97
|
*
|
|
@@ -140,49 +103,40 @@ export class MongoCollectionService extends MongoService {
|
|
|
140
103
|
crud: 'delete',
|
|
141
104
|
method: 'deleteMany',
|
|
142
105
|
byId: false,
|
|
143
|
-
options
|
|
106
|
+
options,
|
|
144
107
|
};
|
|
145
108
|
return this._intercept(async () => {
|
|
146
|
-
const filter = MongoAdapter.prepareFilter([
|
|
147
|
-
await this._getDocumentFilter(info),
|
|
148
|
-
options?.filter,
|
|
149
|
-
]);
|
|
109
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
150
110
|
return this._deleteMany({ ...options, filter });
|
|
151
111
|
}, info);
|
|
152
112
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
113
|
+
/**
|
|
114
|
+
* The distinct command returns a list of distinct values for the given key across a collection.
|
|
115
|
+
* @param {string} field
|
|
116
|
+
* @param {MongoCollectionService.DistinctOptions<T>} [options]
|
|
117
|
+
* @protected
|
|
118
|
+
*/
|
|
158
119
|
async distinct(field, options) {
|
|
159
120
|
const info = {
|
|
160
121
|
crud: 'read',
|
|
161
122
|
method: 'distinct',
|
|
162
123
|
byId: true,
|
|
163
|
-
options
|
|
124
|
+
options,
|
|
164
125
|
};
|
|
165
126
|
return this._intercept(async () => {
|
|
166
|
-
const filter = MongoAdapter.prepareFilter([
|
|
167
|
-
await this._getDocumentFilter(info),
|
|
168
|
-
options?.filter,
|
|
169
|
-
]);
|
|
127
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
170
128
|
return this._distinct(field, { ...options, filter });
|
|
171
129
|
}, info);
|
|
172
130
|
}
|
|
173
|
-
async _distinct(field, options) {
|
|
174
|
-
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
175
|
-
return await this.__distinct(field, filter, omit(options, 'filter'));
|
|
176
|
-
}
|
|
177
131
|
/**
|
|
178
132
|
* Checks if an object with the given id exists.
|
|
179
133
|
*
|
|
180
|
-
* @param {AnyId} id - The id of the object to check.
|
|
181
|
-
* @param {MongoCollectionService.ExistsOptions} [options] - The options for the query (optional).
|
|
134
|
+
* @param {MongoAdapter.AnyId} id - The id of the object to check.
|
|
135
|
+
* @param {MongoCollectionService.ExistsOptions<T>} [options] - The options for the query (optional).
|
|
182
136
|
* @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
|
|
183
137
|
*/
|
|
184
138
|
async exists(id, options) {
|
|
185
|
-
return !!(await this.findById(id, { ...options,
|
|
139
|
+
return !!(await this.findById(id, { ...options, projection: ['_id'] }));
|
|
186
140
|
}
|
|
187
141
|
/**
|
|
188
142
|
* Checks if an object with the given arguments exists.
|
|
@@ -191,13 +145,13 @@ export class MongoCollectionService extends MongoService {
|
|
|
191
145
|
* @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
|
|
192
146
|
*/
|
|
193
147
|
async existsOne(options) {
|
|
194
|
-
return !!(await this.findOne({ ...options,
|
|
148
|
+
return !!(await this.findOne({ ...options, projection: ['_id'] }));
|
|
195
149
|
}
|
|
196
150
|
/**
|
|
197
151
|
* Finds a document by its ID.
|
|
198
152
|
*
|
|
199
|
-
* @param {AnyId} id - The ID of the document.
|
|
200
|
-
* @param {MongoCollectionService.FindOneOptions} [options] - The options for the find query.
|
|
153
|
+
* @param {MongoAdapter.AnyId} id - The ID of the document.
|
|
154
|
+
* @param {MongoCollectionService.FindOneOptions<T>} [options] - The options for the find query.
|
|
201
155
|
* @return {Promise<PartialDTO<T | undefined>>} - A promise resolving to the found document, or undefined if not found.
|
|
202
156
|
*/
|
|
203
157
|
async findById(id, options) {
|
|
@@ -206,37 +160,18 @@ export class MongoCollectionService extends MongoService {
|
|
|
206
160
|
method: 'findById',
|
|
207
161
|
byId: true,
|
|
208
162
|
documentId: id,
|
|
209
|
-
options
|
|
163
|
+
options,
|
|
210
164
|
};
|
|
211
165
|
return this._intercept(async () => {
|
|
212
166
|
const documentFilter = await this._getDocumentFilter(info);
|
|
213
|
-
const filter = MongoAdapter.prepareFilter([
|
|
214
|
-
documentFilter,
|
|
215
|
-
options?.filter,
|
|
216
|
-
]);
|
|
167
|
+
const filter = MongoAdapter.prepareFilter([documentFilter, options?.filter]);
|
|
217
168
|
return this._findById(id, { ...options, filter });
|
|
218
169
|
}, info);
|
|
219
170
|
}
|
|
220
|
-
async _findById(id, options) {
|
|
221
|
-
const filter = MongoAdapter.prepareFilter([
|
|
222
|
-
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
223
|
-
options?.filter
|
|
224
|
-
]);
|
|
225
|
-
const mongoOptions = {
|
|
226
|
-
...options,
|
|
227
|
-
limit: undefined,
|
|
228
|
-
skip: undefined,
|
|
229
|
-
sort: undefined,
|
|
230
|
-
projection: MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
231
|
-
};
|
|
232
|
-
const decode = this.getDecoder();
|
|
233
|
-
const out = await this.__findOne(filter, mongoOptions);
|
|
234
|
-
return out ? decode(out, { coerce: true }) : undefined;
|
|
235
|
-
}
|
|
236
171
|
/**
|
|
237
172
|
* Finds a document in the collection that matches the specified options.
|
|
238
173
|
*
|
|
239
|
-
* @param {MongoCollectionService.FindOneOptions} options - The options for the query.
|
|
174
|
+
* @param {MongoCollectionService.FindOneOptions<T>} [options] - The options for the query.
|
|
240
175
|
* @return {Promise<PartialDTO<T> | undefined>} A promise that resolves with the found document or undefined if no document is found.
|
|
241
176
|
*/
|
|
242
177
|
async findOne(options) {
|
|
@@ -244,41 +179,17 @@ export class MongoCollectionService extends MongoService {
|
|
|
244
179
|
crud: 'read',
|
|
245
180
|
method: 'findOne',
|
|
246
181
|
byId: false,
|
|
247
|
-
options
|
|
182
|
+
options,
|
|
248
183
|
};
|
|
249
184
|
return this._intercept(async () => {
|
|
250
|
-
const filter = MongoAdapter.prepareFilter([
|
|
251
|
-
await this._getDocumentFilter(info),
|
|
252
|
-
options?.filter,
|
|
253
|
-
]);
|
|
185
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
254
186
|
return this._findOne({ ...options, filter });
|
|
255
187
|
}, info);
|
|
256
188
|
}
|
|
257
|
-
async _findOne(options) {
|
|
258
|
-
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
259
|
-
const mongoOptions = {
|
|
260
|
-
...options,
|
|
261
|
-
sort: options?.sort ? MongoAdapter.prepareSort(options.sort) : undefined,
|
|
262
|
-
projection: MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
263
|
-
limit: undefined
|
|
264
|
-
};
|
|
265
|
-
const decode = this.getDecoder();
|
|
266
|
-
const out = await this.__findOne(filter, mongoOptions);
|
|
267
|
-
return out ? decode(out, { coerce: true }) : undefined;
|
|
268
|
-
}
|
|
269
189
|
/**
|
|
270
190
|
* Finds multiple documents in the MongoDB collection.
|
|
271
191
|
*
|
|
272
|
-
* @param options - The options for the find operation.
|
|
273
|
-
* - pick: string[] - An array of fields to include in the returned documents.
|
|
274
|
-
* - include: string[] - An array of fields to include in the returned documents.
|
|
275
|
-
* - omit: string[] - An array of fields to exclude from the returned documents.
|
|
276
|
-
* - sort: Record<string, number> - The sorting criteria.
|
|
277
|
-
* - skip: number - The number of documents to skip.
|
|
278
|
-
* - limit: number - The maximum number of documents to return.
|
|
279
|
-
* - filter: FilterQuery<T> - The filter conditions to apply to the find operation.
|
|
280
|
-
* - count: boolean - If set to true, returns the total count of matching documents.
|
|
281
|
-
*
|
|
192
|
+
* @param {MongoCollectionService.FindManyOptions<T>} options - The options for the find operation.
|
|
282
193
|
* @return A Promise that resolves to an array of partial outputs of type T.
|
|
283
194
|
*/
|
|
284
195
|
async findMany(options) {
|
|
@@ -286,76 +197,37 @@ export class MongoCollectionService extends MongoService {
|
|
|
286
197
|
crud: 'read',
|
|
287
198
|
method: 'findMany',
|
|
288
199
|
byId: false,
|
|
289
|
-
options
|
|
200
|
+
options,
|
|
290
201
|
};
|
|
291
202
|
return this._intercept(async () => {
|
|
292
|
-
const filter = MongoAdapter.prepareFilter([
|
|
293
|
-
|
|
294
|
-
options?.filter,
|
|
295
|
-
]);
|
|
296
|
-
return this._findMany({ ...options, filter });
|
|
203
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
204
|
+
return this._findMany({ ...options, filter, limit: options?.limit || this.defaultLimit });
|
|
297
205
|
}, info);
|
|
298
206
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Finds multiple documents in the collection and returns both records (max limit)
|
|
209
|
+
* and total count that matched the given criteria
|
|
210
|
+
*
|
|
211
|
+
* @param {MongoCollectionService.FindManyOptions<T>} [options] - The options for the find operation.
|
|
212
|
+
* @return A Promise that resolves to an array of partial outputs of type T.
|
|
213
|
+
*/
|
|
214
|
+
async findManyWithCount(options) {
|
|
215
|
+
const info = {
|
|
216
|
+
crud: 'read',
|
|
217
|
+
method: 'findManyWithCount',
|
|
218
|
+
byId: false,
|
|
219
|
+
options,
|
|
302
220
|
};
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
filter = MongoAdapter.prepareFilter(options?.filter);
|
|
308
|
-
let dataStages = stages;
|
|
309
|
-
if (options?.count) {
|
|
310
|
-
dataStages = [];
|
|
311
|
-
const count = [];
|
|
312
|
-
if (filter)
|
|
313
|
-
count.push({ $match: filter });
|
|
314
|
-
count.push({ $count: 'totalMatches' });
|
|
315
|
-
stages.push({
|
|
316
|
-
$facet: {
|
|
317
|
-
data: dataStages,
|
|
318
|
-
count,
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
if (filter)
|
|
323
|
-
dataStages.push({ $match: filter });
|
|
324
|
-
if (options?.skip)
|
|
325
|
-
dataStages.push({ $skip: options.skip });
|
|
326
|
-
if (options?.sort) {
|
|
327
|
-
const sort = MongoAdapter.prepareSort(options.sort);
|
|
328
|
-
if (sort)
|
|
329
|
-
dataStages.push({ $sort: sort });
|
|
330
|
-
}
|
|
331
|
-
dataStages.push({ $limit: limit });
|
|
332
|
-
const dataType = this.getDataType();
|
|
333
|
-
const projection = MongoAdapter.prepareProjection(dataType, options);
|
|
334
|
-
if (projection)
|
|
335
|
-
dataStages.push({ $project: projection });
|
|
336
|
-
const decode = this.getDecoder();
|
|
337
|
-
const cursor = await this.__aggregate(stages, {
|
|
338
|
-
...mongoOptions
|
|
339
|
-
});
|
|
340
|
-
try {
|
|
341
|
-
if (options?.count) {
|
|
342
|
-
const facetResult = await cursor.toArray();
|
|
343
|
-
this.context.response.totalMatches = facetResult[0].count[0].totalMatches || 0;
|
|
344
|
-
return facetResult[0].data.map((r) => decode(r, { coerce: true }));
|
|
345
|
-
}
|
|
346
|
-
else
|
|
347
|
-
return await cursor.toArray();
|
|
348
|
-
}
|
|
349
|
-
finally {
|
|
350
|
-
if (!cursor.closed)
|
|
351
|
-
await cursor.close();
|
|
352
|
-
}
|
|
221
|
+
return this._intercept(async () => {
|
|
222
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
223
|
+
return this._findManyWithCount({ ...options, filter, limit: options?.limit || this.defaultLimit });
|
|
224
|
+
}, info);
|
|
353
225
|
}
|
|
354
226
|
/**
|
|
355
227
|
* Retrieves a document from the collection by its ID. Throws error if not found.
|
|
356
228
|
*
|
|
357
|
-
* @param {
|
|
358
|
-
* @param {MongoCollectionService.FindOneOptions} [options] - Optional options for the findOne operation.
|
|
229
|
+
* @param {MongoAdapter.AnyId} id - The ID of the document to retrieve.
|
|
230
|
+
* @param {MongoCollectionService.FindOneOptions<T>} [options] - Optional options for the findOne operation.
|
|
359
231
|
* @returns {Promise<PartialDTO<T>>} - A promise that resolves to the retrieved document,
|
|
360
232
|
* or rejects with a ResourceNotFoundError if the document does not exist.
|
|
361
233
|
* @throws {ResourceNotAvailableError} - If the document with the specified ID does not exist.
|
|
@@ -369,8 +241,8 @@ export class MongoCollectionService extends MongoService {
|
|
|
369
241
|
/**
|
|
370
242
|
* Updates a document with the given id in the collection.
|
|
371
243
|
*
|
|
372
|
-
* @param {
|
|
373
|
-
* @param {PatchDTO<T>} input - The partial input object containing the fields to update.
|
|
244
|
+
* @param {MongoAdapter.AnyId} id - The id of the document to update.
|
|
245
|
+
* @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input object containing the fields to update.
|
|
374
246
|
* @param {MongoCollectionService.UpdateOptions<T>} [options] - The options for the update operation.
|
|
375
247
|
* @returns {Promise<PartialDTO<T> | undefined>} A promise that resolves to the updated document or
|
|
376
248
|
* undefined if the document was not found.
|
|
@@ -385,49 +257,16 @@ export class MongoCollectionService extends MongoService {
|
|
|
385
257
|
options,
|
|
386
258
|
};
|
|
387
259
|
return this._intercept(async () => {
|
|
388
|
-
const filter = MongoAdapter.prepareFilter([
|
|
389
|
-
await this._getDocumentFilter(info),
|
|
390
|
-
options?.filter
|
|
391
|
-
]);
|
|
260
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
392
261
|
return this._update(id, input, { ...options, filter });
|
|
393
262
|
}, info);
|
|
394
263
|
}
|
|
395
|
-
async _update(id, input, options) {
|
|
396
|
-
const isUpdateFilter = Array.isArray(input) ||
|
|
397
|
-
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
398
|
-
const isDocument = !Array.isArray(input) &&
|
|
399
|
-
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
400
|
-
if (isUpdateFilter && isDocument)
|
|
401
|
-
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
402
|
-
let update;
|
|
403
|
-
if (isDocument) {
|
|
404
|
-
const encode = this.getEncoder('update');
|
|
405
|
-
const doc = encode(input, { coerce: true });
|
|
406
|
-
update = MongoAdapter.preparePatch(doc);
|
|
407
|
-
update.$set = update.$set || {};
|
|
408
|
-
}
|
|
409
|
-
else
|
|
410
|
-
update = input;
|
|
411
|
-
const filter = MongoAdapter.prepareFilter([
|
|
412
|
-
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
413
|
-
options?.filter
|
|
414
|
-
]);
|
|
415
|
-
const mongoOptions = {
|
|
416
|
-
...options,
|
|
417
|
-
includeResultMetadata: false,
|
|
418
|
-
upsert: undefined,
|
|
419
|
-
projection: MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
420
|
-
};
|
|
421
|
-
const decode = this.getDecoder();
|
|
422
|
-
const out = await this.__findOneAndUpdate(filter, update, mongoOptions);
|
|
423
|
-
return out ? decode(out, { coerce: true }) : undefined;
|
|
424
|
-
}
|
|
425
264
|
/**
|
|
426
265
|
* Updates a document in the collection with the specified ID.
|
|
427
266
|
*
|
|
428
|
-
* @param {
|
|
429
|
-
* @param {PatchDTO<T>} input - The partial input data to update the document with.
|
|
430
|
-
* @param {MongoCollectionService.UpdateOptions<T>} options - The options for updating the document.
|
|
267
|
+
* @param {MongoAdapter.AnyId} id - The ID of the document to update.
|
|
268
|
+
* @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input data to update the document with.
|
|
269
|
+
* @param {MongoCollectionService.UpdateOptions<T>} [options] - The options for updating the document.
|
|
431
270
|
* @returns {Promise<number>} - A promise that resolves to the number of documents modified.
|
|
432
271
|
*/
|
|
433
272
|
async updateOnly(id, input, options) {
|
|
@@ -440,47 +279,14 @@ export class MongoCollectionService extends MongoService {
|
|
|
440
279
|
options,
|
|
441
280
|
};
|
|
442
281
|
return this._intercept(async () => {
|
|
443
|
-
const filter = MongoAdapter.prepareFilter([
|
|
444
|
-
await this._getDocumentFilter(info),
|
|
445
|
-
options?.filter
|
|
446
|
-
]);
|
|
282
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
447
283
|
return this._updateOnly(id, input, { ...options, filter });
|
|
448
284
|
}, info);
|
|
449
285
|
}
|
|
450
|
-
async _updateOnly(id, input, options) {
|
|
451
|
-
const isUpdateFilter = Array.isArray(input) ||
|
|
452
|
-
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
453
|
-
const isDocument = !Array.isArray(input) &&
|
|
454
|
-
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
455
|
-
if (isUpdateFilter && isDocument)
|
|
456
|
-
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
457
|
-
let update;
|
|
458
|
-
if (isDocument) {
|
|
459
|
-
const encode = this.getEncoder('update');
|
|
460
|
-
const doc = encode(input, { coerce: true });
|
|
461
|
-
update = MongoAdapter.preparePatch(doc);
|
|
462
|
-
if (!Object.keys(doc).length)
|
|
463
|
-
return 0;
|
|
464
|
-
}
|
|
465
|
-
else
|
|
466
|
-
update = input;
|
|
467
|
-
const filter = MongoAdapter.prepareFilter([
|
|
468
|
-
MongoAdapter.prepareKeyValues(id, [this.collectionKey]),
|
|
469
|
-
options?.filter
|
|
470
|
-
]);
|
|
471
|
-
const mongoOptions = {
|
|
472
|
-
...options,
|
|
473
|
-
includeResultMetadata: false,
|
|
474
|
-
upsert: undefined,
|
|
475
|
-
projection: MongoAdapter.prepareProjection(this.getDataType(), options),
|
|
476
|
-
};
|
|
477
|
-
const out = await this.__updateOne(filter, update, mongoOptions);
|
|
478
|
-
return out.matchedCount;
|
|
479
|
-
}
|
|
480
286
|
/**
|
|
481
287
|
* Updates multiple documents in the collection based on the specified input and options.
|
|
482
288
|
*
|
|
483
|
-
* @param {PatchDTO<T>} input - The partial input to update the documents with.
|
|
289
|
+
* @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input to update the documents with.
|
|
484
290
|
* @param {MongoCollectionService.UpdateManyOptions<T>} options - The options for updating the documents.
|
|
485
291
|
* @return {Promise<number>} - A promise that resolves to the number of documents matched and modified.
|
|
486
292
|
*/
|
|
@@ -493,63 +299,17 @@ export class MongoCollectionService extends MongoService {
|
|
|
493
299
|
options,
|
|
494
300
|
};
|
|
495
301
|
return this._intercept(async () => {
|
|
496
|
-
const filter = MongoAdapter.prepareFilter([
|
|
497
|
-
await this._getDocumentFilter(info),
|
|
498
|
-
options?.filter
|
|
499
|
-
]);
|
|
302
|
+
const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
|
|
500
303
|
return this._updateMany(input, { ...options, filter });
|
|
501
304
|
}, info);
|
|
502
305
|
}
|
|
503
|
-
async _updateMany(input, options) {
|
|
504
|
-
const isUpdateFilter = Array.isArray(input) ||
|
|
505
|
-
!!Object.keys(input).find(x => x.startsWith('$'));
|
|
506
|
-
const isDocument = !Array.isArray(input) &&
|
|
507
|
-
!!Object.keys(input).find(x => !x.startsWith('$'));
|
|
508
|
-
if (isUpdateFilter && isDocument)
|
|
509
|
-
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
510
|
-
let update;
|
|
511
|
-
if (isDocument) {
|
|
512
|
-
const encode = this.getEncoder('update');
|
|
513
|
-
const doc = encode(input, { coerce: true });
|
|
514
|
-
update = MongoAdapter.preparePatch(doc);
|
|
515
|
-
if (!Object.keys(doc).length)
|
|
516
|
-
return 0;
|
|
517
|
-
}
|
|
518
|
-
else
|
|
519
|
-
update = input;
|
|
520
|
-
const mongoOptions = {
|
|
521
|
-
...omit(options, 'filter'),
|
|
522
|
-
upsert: undefined
|
|
523
|
-
};
|
|
524
|
-
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
525
|
-
const r = await this.__updateMany(filter, update, mongoOptions);
|
|
526
|
-
return r.matchedCount;
|
|
527
|
-
}
|
|
528
306
|
/**
|
|
529
307
|
* Generates an ID.
|
|
530
308
|
*
|
|
531
309
|
* @protected
|
|
532
|
-
* @returns {AnyId} The generated ID.
|
|
310
|
+
* @returns {MongoAdapter.AnyId} The generated ID.
|
|
533
311
|
*/
|
|
534
312
|
_generateId() {
|
|
535
|
-
return typeof this.$idGenerator === 'function' ?
|
|
536
|
-
this.$idGenerator(this) : new ObjectId();
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Retrieves the common filter used for querying documents.
|
|
540
|
-
* This method is mostly used for security issues like securing multi-tenant applications.
|
|
541
|
-
*
|
|
542
|
-
* @protected
|
|
543
|
-
* @returns {FilterInput | Promise<FilterInput> | undefined} The common filter or a Promise
|
|
544
|
-
* that resolves to the common filter, or undefined if not available.
|
|
545
|
-
*/
|
|
546
|
-
_getDocumentFilter(args) {
|
|
547
|
-
return typeof this.$documentFilter === 'function' ?
|
|
548
|
-
this.$documentFilter(args, this) : this.$documentFilter;
|
|
549
|
-
}
|
|
550
|
-
async _intercept(callback, args) {
|
|
551
|
-
if (this.$interceptor)
|
|
552
|
-
return this.$interceptor(callback, args, this);
|
|
553
|
-
return callback();
|
|
313
|
+
return typeof this.$idGenerator === 'function' ? this.$idGenerator(this) : new ObjectId();
|
|
554
314
|
}
|
|
555
315
|
}
|