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