@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.
@@ -1,4 +1,3 @@
1
- import { ObjectId } from 'mongodb';
2
1
  import { ResourceNotAvailableError } from '@opra/common';
3
2
  import { MongoAdapter } from './mongo-adapter.js';
4
3
  import { MongoEntityService } from './mongo-entity-service.js';
@@ -23,7 +22,7 @@ export class MongoCollectionService extends MongoEntityService {
23
22
  * Throws a ResourceNotFoundError if the resource does not exist.
24
23
  *
25
24
  * @param {MongoAdapter.AnyId} id - The ID of the resource to assert.
26
- * @param {MongoCollectionService.ExistsOptions<T>} [options] - Optional options for checking the existence.
25
+ * @param {MongoEntityService.ExistsOptions<T>} [options] - Optional options for checking the existence.
27
26
  * @returns {Promise<void>} - A Promise that resolves when the resource exists.
28
27
  * @throws {ResourceNotAvailableError} - If the resource does not exist.
29
28
  */
@@ -36,112 +35,126 @@ export class MongoCollectionService extends MongoEntityService {
36
35
  * Interceptors will be called before performing db operation
37
36
  *
38
37
  * @param {PartialDTO<T>} input - The input data for creating the document.
39
- * @param {MongoCollectionService.CreateOptions} [options] - The options for creating the document.
38
+ * @param {MongoEntityService.CreateOptions} [options] - The options for creating the document.
40
39
  * @returns {Promise<PartialDTO<T>>} A promise that resolves to the created document.
41
40
  * @throws {Error} if an unknown error occurs while creating the document.
42
41
  */
43
42
  async create(input, options) {
44
- const id = input._id || this._generateId();
45
- if (id != null)
46
- input._id = id;
47
- const info = {
43
+ const command = {
48
44
  crud: 'create',
49
45
  method: 'create',
50
46
  byId: false,
51
- documentId: id,
52
47
  input,
53
48
  options,
54
49
  };
55
- return this._intercept(() => this._create(input, options), info);
50
+ return this._executeCommand(command, () => this._create(command));
56
51
  }
57
52
  /**
58
53
  * Returns the count of documents in the collection based on the provided options.
59
54
  *
60
- * @param {MongoCollectionService.CountOptions<T>} options - The options for the count operation.
55
+ * @param {MongoEntityService.CountOptions<T>} options - The options for the count operation.
61
56
  * @return {Promise<number>} - A promise that resolves to the count of documents in the collection.
62
57
  */
63
58
  async count(options) {
64
- const info = {
59
+ const command = {
65
60
  crud: 'read',
66
61
  method: 'count',
67
62
  byId: false,
68
63
  options,
69
64
  };
70
- return this._intercept(async () => {
71
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
72
- return this._count({ ...options, filter });
73
- }, info);
65
+ return this._executeCommand(command, async () => {
66
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
67
+ command.options = { ...command.options, filter };
68
+ return this._count(command);
69
+ });
74
70
  }
75
71
  /**
76
72
  * Deletes a document from the collection.
77
73
  *
78
74
  * @param {MongoAdapter.AnyId} id - The ID of the document to delete.
79
- * @param {MongoCollectionService.DeleteOptions<T>} [options] - Optional delete options.
75
+ * @param {MongoEntityService.DeleteOptions<T>} [options] - Optional delete options.
80
76
  * @return {Promise<number>} - A Promise that resolves to the number of documents deleted.
81
77
  */
82
78
  async delete(id, options) {
83
- const info = {
79
+ const command = {
84
80
  crud: 'delete',
85
81
  method: 'delete',
86
82
  byId: true,
87
83
  documentId: id,
88
84
  options,
89
85
  };
90
- return this._intercept(async () => {
91
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
92
- return this._delete(id, { ...options, filter });
93
- }, info);
86
+ return this._executeCommand(command, async () => {
87
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
88
+ command.options = { ...command.options, filter };
89
+ return this._delete(command);
90
+ });
94
91
  }
95
92
  /**
96
93
  * Deletes multiple documents from the collection that meet the specified filter criteria.
97
94
  *
98
- * @param {MongoCollectionService.DeleteManyOptions<T>} options - The options for the delete operation.
95
+ * @param {MongoEntityService.DeleteManyOptions<T>} options - The options for the delete operation.
99
96
  * @return {Promise<number>} - A promise that resolves to the number of documents deleted.
100
97
  */
101
98
  async deleteMany(options) {
102
- const info = {
99
+ const command = {
103
100
  crud: 'delete',
104
101
  method: 'deleteMany',
105
102
  byId: false,
106
103
  options,
107
104
  };
108
- return this._intercept(async () => {
109
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
110
- return this._deleteMany({ ...options, filter });
111
- }, info);
105
+ return this._executeCommand(command, async () => {
106
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
107
+ command.options = { ...command.options, filter };
108
+ return this._deleteMany(command);
109
+ });
112
110
  }
113
111
  /**
114
112
  * The distinct command returns a list of distinct values for the given key across a collection.
115
113
  * @param {string} field
116
- * @param {MongoCollectionService.DistinctOptions<T>} [options]
114
+ * @param {MongoEntityService.DistinctOptions<T>} [options]
117
115
  * @protected
118
116
  */
119
117
  async distinct(field, options) {
120
- const info = {
118
+ const command = {
121
119
  crud: 'read',
122
120
  method: 'distinct',
123
- byId: true,
121
+ byId: false,
122
+ field,
124
123
  options,
125
124
  };
126
- return this._intercept(async () => {
127
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
128
- return this._distinct(field, { ...options, filter });
129
- }, info);
125
+ return this._executeCommand(command, async () => {
126
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
127
+ command.options = { ...command.options, filter };
128
+ return this._distinct(command);
129
+ });
130
130
  }
131
131
  /**
132
132
  * Checks if an object with the given id exists.
133
133
  *
134
134
  * @param {MongoAdapter.AnyId} id - The id of the object to check.
135
- * @param {MongoCollectionService.ExistsOptions<T>} [options] - The options for the query (optional).
135
+ * @param {MongoEntityService.ExistsOptions<T>} [options] - The options for the query (optional).
136
136
  * @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
137
137
  */
138
138
  async exists(id, options) {
139
- return !!(await this.findById(id, { ...options, projection: ['_id'] }));
139
+ const command = {
140
+ crud: 'read',
141
+ method: 'exists',
142
+ byId: true,
143
+ documentId: id,
144
+ options,
145
+ };
146
+ return this._executeCommand(command, async () => {
147
+ const documentFilter = await this._getDocumentFilter(command);
148
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
149
+ const findCommand = command;
150
+ findCommand.options = { ...command.options, filter, projection: ['_id'] };
151
+ return !!(await this._findById(findCommand));
152
+ });
140
153
  }
141
154
  /**
142
155
  * Checks if an object with the given arguments exists.
143
156
  *
144
- * @param {MongoCollectionService.ExistsOneOptions} [options] - The options for the query (optional).
157
+ * @param {MongoEntityService.ExistsOneOptions} [options] - The options for the query (optional).
145
158
  * @return {Promise<boolean>} - A Promise that resolves to a boolean indicating whether the object exists or not.
146
159
  */
147
160
  async existsOne(options) {
@@ -151,83 +164,87 @@ export class MongoCollectionService extends MongoEntityService {
151
164
  * Finds a document by its ID.
152
165
  *
153
166
  * @param {MongoAdapter.AnyId} id - The ID of the document.
154
- * @param {MongoCollectionService.FindOneOptions<T>} [options] - The options for the find query.
167
+ * @param {MongoEntityService.FindOneOptions<T>} [options] - The options for the find query.
155
168
  * @return {Promise<PartialDTO<T | undefined>>} - A promise resolving to the found document, or undefined if not found.
156
169
  */
157
170
  async findById(id, options) {
158
- const info = {
171
+ const command = {
159
172
  crud: 'read',
160
173
  method: 'findById',
161
174
  byId: true,
162
175
  documentId: id,
163
176
  options,
164
177
  };
165
- return this._intercept(async () => {
166
- const documentFilter = await this._getDocumentFilter(info);
167
- const filter = MongoAdapter.prepareFilter([documentFilter, options?.filter]);
168
- return this._findById(id, { ...options, filter });
169
- }, info);
178
+ return this._executeCommand(command, async () => {
179
+ const documentFilter = await this._getDocumentFilter(command);
180
+ const filter = MongoAdapter.prepareFilter([documentFilter, command.options?.filter]);
181
+ command.options = { ...command.options, filter };
182
+ return this._findById(command);
183
+ });
170
184
  }
171
185
  /**
172
186
  * Finds a document in the collection that matches the specified options.
173
187
  *
174
- * @param {MongoCollectionService.FindOneOptions<T>} [options] - The options for the query.
188
+ * @param {MongoEntityService.FindOneOptions<T>} [options] - The options for the query.
175
189
  * @return {Promise<PartialDTO<T> | undefined>} A promise that resolves with the found document or undefined if no document is found.
176
190
  */
177
191
  async findOne(options) {
178
- const info = {
192
+ const command = {
179
193
  crud: 'read',
180
194
  method: 'findOne',
181
195
  byId: false,
182
196
  options,
183
197
  };
184
- return this._intercept(async () => {
185
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
186
- return this._findOne({ ...options, filter });
187
- }, info);
198
+ return this._executeCommand(command, async () => {
199
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
200
+ command.options = { ...command.options, filter };
201
+ return this._findOne(command);
202
+ });
188
203
  }
189
204
  /**
190
205
  * Finds multiple documents in the MongoDB collection.
191
206
  *
192
- * @param {MongoCollectionService.FindManyOptions<T>} options - The options for the find operation.
207
+ * @param {MongoEntityService.FindManyOptions<T>} options - The options for the find operation.
193
208
  * @return A Promise that resolves to an array of partial outputs of type T.
194
209
  */
195
210
  async findMany(options) {
196
- const info = {
211
+ const command = {
197
212
  crud: 'read',
198
213
  method: 'findMany',
199
214
  byId: false,
200
215
  options,
201
216
  };
202
- return this._intercept(async () => {
203
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
204
- return this._findMany({ ...options, filter, limit: options?.limit || this.defaultLimit });
205
- }, info);
217
+ return this._executeCommand(command, async () => {
218
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
219
+ command.options = { ...command.options, filter, limit: command.options?.limit || this.defaultLimit };
220
+ return this._findMany(command);
221
+ });
206
222
  }
207
223
  /**
208
224
  * Finds multiple documents in the collection and returns both records (max limit)
209
225
  * and total count that matched the given criteria
210
226
  *
211
- * @param {MongoCollectionService.FindManyOptions<T>} [options] - The options for the find operation.
227
+ * @param {MongoEntityService.FindManyOptions<T>} [options] - The options for the find operation.
212
228
  * @return A Promise that resolves to an array of partial outputs of type T.
213
229
  */
214
230
  async findManyWithCount(options) {
215
- const info = {
231
+ const command = {
216
232
  crud: 'read',
217
233
  method: 'findManyWithCount',
218
234
  byId: false,
219
235
  options,
220
236
  };
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);
237
+ return this._executeCommand(command, async () => {
238
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
239
+ command.options = { ...command.options, filter, limit: command.options?.limit || this.defaultLimit };
240
+ return this._findManyWithCount(command);
241
+ });
225
242
  }
226
243
  /**
227
244
  * Retrieves a document from the collection by its ID. Throws error if not found.
228
245
  *
229
246
  * @param {MongoAdapter.AnyId} id - The ID of the document to retrieve.
230
- * @param {MongoCollectionService.FindOneOptions<T>} [options] - Optional options for the findOne operation.
247
+ * @param {MongoEntityService.FindOneOptions<T>} [options] - Optional options for the findOne operation.
231
248
  * @returns {Promise<PartialDTO<T>>} - A promise that resolves to the retrieved document,
232
249
  * or rejects with a ResourceNotFoundError if the document does not exist.
233
250
  * @throws {ResourceNotAvailableError} - If the document with the specified ID does not exist.
@@ -243,73 +260,73 @@ export class MongoCollectionService extends MongoEntityService {
243
260
  *
244
261
  * @param {MongoAdapter.AnyId} id - The id of the document to update.
245
262
  * @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input object containing the fields to update.
246
- * @param {MongoCollectionService.UpdateOptions<T>} [options] - The options for the update operation.
263
+ * @param {MongoEntityService.UpdateOneOptions<T>} [options] - The options for the update operation.
247
264
  * @returns {Promise<PartialDTO<T> | undefined>} A promise that resolves to the updated document or
248
265
  * undefined if the document was not found.
249
266
  */
250
267
  async update(id, input, options) {
251
- const info = {
268
+ const isUpdateFilter = Array.isArray(input) || !!Object.keys(input).find(x => x.startsWith('$'));
269
+ const command = {
252
270
  crud: 'update',
253
271
  method: 'update',
254
272
  documentId: id,
255
273
  byId: true,
256
- input,
274
+ input: isUpdateFilter ? undefined : input,
275
+ inputRaw: isUpdateFilter ? input : undefined,
257
276
  options,
258
277
  };
259
- return this._intercept(async () => {
260
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
261
- return this._update(id, input, { ...options, filter });
262
- }, info);
278
+ return this._executeCommand(command, async () => {
279
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
280
+ command.options = { ...command.options, filter };
281
+ return this._update(command);
282
+ });
263
283
  }
264
284
  /**
265
285
  * Updates a document in the collection with the specified ID.
266
286
  *
267
287
  * @param {MongoAdapter.AnyId} id - The ID of the document to update.
268
288
  * @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.
289
+ * @param {MongoEntityService.UpdateOneOptions<T>} [options] - The options for updating the document.
270
290
  * @returns {Promise<number>} - A promise that resolves to the number of documents modified.
271
291
  */
272
292
  async updateOnly(id, input, options) {
273
- const info = {
293
+ const isUpdateFilter = Array.isArray(input) || !!Object.keys(input).find(x => x.startsWith('$'));
294
+ const command = {
274
295
  crud: 'update',
275
- method: 'update',
296
+ method: 'updateOnly',
276
297
  documentId: id,
277
298
  byId: true,
278
- input,
299
+ input: isUpdateFilter ? undefined : input,
300
+ inputRaw: isUpdateFilter ? input : undefined,
279
301
  options,
280
302
  };
281
- return this._intercept(async () => {
282
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
283
- return this._updateOnly(id, input, { ...options, filter });
284
- }, info);
303
+ return this._executeCommand(command, async () => {
304
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
305
+ command.options = { ...command.options, filter };
306
+ return this._updateOnly(command);
307
+ });
285
308
  }
286
309
  /**
287
310
  * Updates multiple documents in the collection based on the specified input and options.
288
311
  *
289
312
  * @param {PatchDTO<T>|UpdateFilter<T>} input - The partial input to update the documents with.
290
- * @param {MongoCollectionService.UpdateManyOptions<T>} options - The options for updating the documents.
313
+ * @param {MongoEntityService.UpdateManyOptions<T>} options - The options for updating the documents.
291
314
  * @return {Promise<number>} - A promise that resolves to the number of documents matched and modified.
292
315
  */
293
316
  async updateMany(input, options) {
294
- const info = {
317
+ const isUpdateFilter = Array.isArray(input) || !!Object.keys(input).find(x => x.startsWith('$'));
318
+ const command = {
295
319
  crud: 'update',
296
320
  method: 'updateMany',
297
321
  byId: false,
298
- input,
322
+ input: isUpdateFilter ? undefined : input,
323
+ inputRaw: isUpdateFilter ? input : undefined,
299
324
  options,
300
325
  };
301
- return this._intercept(async () => {
302
- const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
303
- return this._updateMany(input, { ...options, filter });
304
- }, info);
305
- }
306
- /**
307
- * Generates an ID.
308
- *
309
- * @protected
310
- * @returns {MongoAdapter.AnyId} The generated ID.
311
- */
312
- _generateId() {
313
- return typeof this.$idGenerator === 'function' ? this.$idGenerator(this) : new ObjectId();
326
+ return this._executeCommand(command, async () => {
327
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(command), command.options?.filter]);
328
+ command.options = { ...command.options, filter };
329
+ return this._updateMany(command);
330
+ });
314
331
  }
315
332
  }