@opra/mongodb 1.2.1 → 1.2.3

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,12 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = prepareKeyValues;
4
- const tslib_1 = require("tslib");
5
- const putil_isplainobject_1 = tslib_1.__importDefault(require("putil-isplainobject"));
4
+ const objects_1 = require("@jsopen/objects");
6
5
  const defaultPrimaryKey = ['_id'];
7
6
  function prepareKeyValues(keyValue, primaryKey) {
8
7
  primaryKey = primaryKey || defaultPrimaryKey;
9
- const b = (0, putil_isplainobject_1.default)(keyValue);
8
+ const b = (0, objects_1.isPlainObject)(keyValue);
10
9
  if (primaryKey.length > 1 && !b) {
11
10
  throw new TypeError(`Argument "keyValue" must be an object that contains all key values`);
12
11
  }
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = preparePatch;
4
- const common_1 = require("@opra/common");
5
- function preparePatch(doc, options) {
6
- const trg = {};
7
- _preparePatch(doc, trg, '', options);
8
- trg.$set = trg.$set || {};
9
- return trg;
4
+ const objects_1 = require("@jsopen/objects");
5
+ function preparePatch(doc, options, target) {
6
+ target = target || {};
7
+ _preparePatch(doc, target, '', options);
8
+ target.$set = target.$set || {};
9
+ return target;
10
10
  }
11
11
  function _preparePatch(src, trg, path, options) {
12
12
  let f;
@@ -23,7 +23,7 @@ function _preparePatch(src, trg, path, options) {
23
23
  trg.$unset[field] = '';
24
24
  continue;
25
25
  }
26
- if (v && typeof v === 'object' && !(0, common_1.isBuiltInObject)(v)) {
26
+ if (v && typeof v === 'object' && !(0, objects_1.isBuiltIn)(v)) {
27
27
  // If field name starts with "*", do "replace" operation except "merge"
28
28
  if (!k.startsWith('*')) {
29
29
  _preparePatch(v, trg, key);
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MongoCollectionService = void 0;
4
- const tslib_1 = require("tslib");
5
4
  const common_1 = require("@opra/common");
6
- const lodash_omit_1 = tslib_1.__importDefault(require("lodash.omit"));
7
5
  const mongo_adapter_js_1 = require("./mongo-adapter.js");
8
6
  const mongo_entity_service_js_1 = require("./mongo-entity-service.js");
9
7
  /**
@@ -53,7 +51,7 @@ class MongoCollectionService extends mongo_entity_service_js_1.MongoEntityServic
53
51
  crud: 'read',
54
52
  byId: true,
55
53
  documentId: r._id,
56
- options: (0, lodash_omit_1.default)(options, 'filter'),
54
+ options,
57
55
  };
58
56
  const out = await this._findById(findCommand);
59
57
  if (out)
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MongoEntityService = void 0;
4
- const tslib_1 = require("tslib");
4
+ const objects_1 = require("@jsopen/objects");
5
5
  const common_1 = require("@opra/common");
6
- const lodash_omit_1 = tslib_1.__importDefault(require("lodash.omit"));
7
6
  const valgen_1 = require("valgen");
8
7
  const mongo_adapter_js_1 = require("./mongo-adapter.js");
9
8
  const mongo_service_js_1 = require("./mongo-service.js");
@@ -196,7 +195,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
196
195
  const db = this.getDatabase();
197
196
  const collection = await this.getCollection(db);
198
197
  const cursor = collection.aggregate(stages, {
199
- ...(0, lodash_omit_1.default)(options, ['projection', 'sort', 'skip', 'limit', 'filter']),
198
+ ...(0, objects_1.omit)(options, ['projection', 'sort', 'skip', 'limit', 'filter']),
200
199
  session: options?.session ?? this.getSession(),
201
200
  });
202
201
  /** Execute db command */
@@ -224,9 +223,6 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
224
223
  filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
225
224
  const dataStages = [];
226
225
  const countStages = [];
227
- if (filter)
228
- countStages.push({ $match: filter });
229
- countStages.push({ $count: 'totalMatches' });
230
226
  const stages = [
231
227
  {
232
228
  $facet: {
@@ -235,15 +231,25 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
235
231
  },
236
232
  },
237
233
  ];
238
- if (filter)
234
+ /** Pre-Stages */
235
+ if (options?.preStages)
236
+ dataStages.push(...options.preStages);
237
+ /** Filter */
238
+ if (filter) {
239
+ countStages.push({ $match: filter });
239
240
  dataStages.push({ $match: filter });
240
- if (options?.skip)
241
- dataStages.push({ $skip: options.skip });
241
+ }
242
+ countStages.push({ $count: 'totalMatches' });
243
+ /** Sort */
242
244
  if (options?.sort) {
243
245
  const sort = mongo_adapter_js_1.MongoAdapter.prepareSort(options.sort);
244
246
  if (sort)
245
247
  dataStages.push({ $sort: sort });
246
248
  }
249
+ /** Skip */
250
+ if (options?.skip)
251
+ dataStages.push({ $skip: options.skip });
252
+ /** Limit */
247
253
  dataStages.push({ $limit: limit });
248
254
  const dataType = this.dataType;
249
255
  const projection = mongo_adapter_js_1.MongoAdapter.prepareProjection(dataType, options?.projection);
@@ -254,7 +260,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
254
260
  const db = this.getDatabase();
255
261
  const collection = await this.getCollection(db);
256
262
  const cursor = collection.aggregate(stages, {
257
- ...(0, lodash_omit_1.default)(options, ['projection', 'sort', 'skip', 'limit', 'filter']),
263
+ ...(0, objects_1.omit)(options, ['projection', 'sort', 'skip', 'limit', 'filter']),
258
264
  session: options?.session ?? this.getSession(),
259
265
  });
260
266
  /** Fetch the cursor and decode the result objects */
@@ -282,16 +288,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
282
288
  if (input && inputRaw) {
283
289
  throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
284
290
  }
285
- let update;
286
- if (input) {
287
- const inputCodec = this._getInputCodec('update');
288
- const doc = inputCodec(input);
289
- delete doc._id;
290
- update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
291
- update.$set = update.$set || {};
292
- }
293
- else
294
- update = inputRaw;
291
+ const update = this._prepareUpdate(command);
295
292
  const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
296
293
  mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
297
294
  options?.filter,
@@ -310,36 +307,6 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
310
307
  if (out)
311
308
  return outputCodec(out);
312
309
  }
313
- /**
314
- * Replaces a document with the given id in the collection
315
- *
316
- * @param {MongoEntityService.ReplaceCommand<T>} command
317
- */
318
- async _replace(command) {
319
- const input = command.input;
320
- (0, valgen_1.isNotNullish)(input, { label: 'input' });
321
- (0, valgen_1.isNotNullish)(input._id, { label: 'input._id' });
322
- const inputCodec = this._getInputCodec('replace');
323
- const document = inputCodec(input);
324
- const { options } = command;
325
- const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
326
- mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
327
- options?.filter,
328
- ]);
329
- const db = this.getDatabase();
330
- const collection = await this.getCollection(db);
331
- const out = await collection.findOneAndReplace(filter || {}, document, {
332
- upsert: undefined,
333
- ...options,
334
- returnDocument: 'after',
335
- includeResultMetadata: false,
336
- session: options?.session ?? this.getSession(),
337
- projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection),
338
- });
339
- const outputCodec = this._getOutputCodec('replace');
340
- if (out)
341
- return outputCodec(out);
342
- }
343
310
  /**
344
311
  * Updates a document in the collection with the specified ID.
345
312
  *
@@ -352,17 +319,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
352
319
  if (input && inputRaw) {
353
320
  throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
354
321
  }
355
- let update;
356
- if (input) {
357
- const inputCodec = this._getInputCodec('update');
358
- const doc = inputCodec(input);
359
- delete doc._id;
360
- update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
361
- if (!Object.keys(doc).length)
362
- return 0;
363
- }
364
- else
365
- update = inputRaw;
322
+ const update = this._prepareUpdate(command);
366
323
  const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
367
324
  mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
368
325
  options?.filter,
@@ -387,26 +344,61 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
387
344
  if (input && inputRaw) {
388
345
  throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
389
346
  }
390
- let update;
391
- if (input) {
392
- const inputCodec = this._getInputCodec('update');
393
- const doc = inputCodec(input);
394
- delete doc._id;
395
- update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
396
- if (!Object.keys(doc).length)
397
- return 0;
398
- }
399
- else
400
- update = inputRaw;
347
+ const update = this._prepareUpdate(command);
401
348
  const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
402
349
  const db = this.getDatabase();
403
350
  const collection = await this.getCollection(db);
404
351
  return (await collection.updateMany(filter || {}, update, {
405
- ...(0, lodash_omit_1.default)(options, 'filter'),
352
+ ...(0, objects_1.omit)(options, ['filter']),
406
353
  session: options?.session ?? this.getSession(),
407
354
  upsert: false,
408
355
  })).matchedCount;
409
356
  }
357
+ /**
358
+ * Replaces a document with the given id in the collection
359
+ *
360
+ * @param {MongoEntityService.ReplaceCommand<T>} command
361
+ */
362
+ async _replace(command) {
363
+ const input = command.input;
364
+ (0, valgen_1.isNotNullish)(input, { label: 'input' });
365
+ (0, valgen_1.isNotNullish)(input._id, { label: 'input._id' });
366
+ const inputCodec = this._getInputCodec('replace');
367
+ const document = inputCodec(input);
368
+ const { options } = command;
369
+ const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
370
+ mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
371
+ options?.filter,
372
+ ]);
373
+ const db = this.getDatabase();
374
+ const collection = await this.getCollection(db);
375
+ const out = await collection.findOneAndReplace(filter || {}, document, {
376
+ upsert: undefined,
377
+ ...options,
378
+ returnDocument: 'after',
379
+ includeResultMetadata: false,
380
+ session: options?.session ?? this.getSession(),
381
+ projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection),
382
+ });
383
+ const outputCodec = this._getOutputCodec('replace');
384
+ if (out)
385
+ return outputCodec(out);
386
+ }
387
+ _prepareUpdate(command) {
388
+ const { input, inputRaw } = command;
389
+ (0, valgen_1.isNotNullish)(input || inputRaw, { label: 'input' });
390
+ if (input && inputRaw) {
391
+ throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
392
+ }
393
+ let update = { ...inputRaw };
394
+ if (input) {
395
+ const inputCodec = this._getInputCodec('update');
396
+ const doc = inputCodec(input);
397
+ delete doc._id;
398
+ update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc, {}, update);
399
+ }
400
+ return update;
401
+ }
410
402
  async _executeCommand(command, commandFn) {
411
403
  try {
412
404
  const result = await super._executeCommand(command, async () => {
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MongoNestedService = void 0;
4
- const tslib_1 = require("tslib");
4
+ const objects_1 = require("@jsopen/objects");
5
5
  const common_1 = require("@opra/common");
6
- const lodash_omit_1 = tslib_1.__importDefault(require("lodash.omit"));
7
6
  const valgen_1 = require("valgen");
8
7
  const mongo_adapter_js_1 = require("./mongo-adapter.js");
9
8
  const mongo_service_js_1 = require("./mongo-service.js");
@@ -178,7 +177,7 @@ class MongoNestedService extends mongo_service_js_1.MongoService {
178
177
  const db = this.getDatabase();
179
178
  const collection = await this.getCollection(db);
180
179
  const cursor = collection.aggregate(stages, {
181
- ...(0, lodash_omit_1.default)(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
180
+ ...(0, objects_1.omit)(options, ['documentFilter', 'skip', 'limit', 'filter']),
182
181
  session: options?.session ?? this.getSession(),
183
182
  });
184
183
  try {
@@ -433,26 +432,36 @@ class MongoNestedService extends mongo_service_js_1.MongoService {
433
432
  { $unwind: { path: '$' + this.fieldName } },
434
433
  { $replaceRoot: { newRoot: '$' + this.fieldName } },
435
434
  ];
435
+ /** Pre-Stages */
436
+ if (options?.preStages)
437
+ stages.push(...options.preStages);
438
+ /** Filter */
436
439
  if (options?.filter || options?.nestedFilter) {
437
440
  const optionsFilter = mongo_adapter_js_1.MongoAdapter.prepareFilter([options?.filter, options.nestedFilter]);
438
441
  stages.push({ $match: optionsFilter });
439
442
  }
440
- if (options?.skip)
441
- stages.push({ $skip: options.skip });
443
+ /** Sort */
442
444
  if (options?.sort) {
443
445
  const sort = mongo_adapter_js_1.MongoAdapter.prepareSort(options.sort);
444
446
  if (sort)
445
447
  stages.push({ $sort: sort });
446
448
  }
449
+ /** Skip */
450
+ if (options?.skip)
451
+ stages.push({ $skip: options.skip });
452
+ /** Limit */
447
453
  stages.push({ $limit: limit });
448
454
  const dataType = this.dataType;
449
455
  const projection = mongo_adapter_js_1.MongoAdapter.prepareProjection(dataType, options?.projection);
450
456
  if (projection)
451
457
  stages.push({ $project: projection });
458
+ /** Post-Stages */
459
+ if (options?.postStages)
460
+ stages.push(...options.postStages);
452
461
  const db = this.getDatabase();
453
462
  const collection = await this.getCollection(db);
454
463
  const cursor = collection.aggregate(stages, {
455
- ...(0, lodash_omit_1.default)(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
464
+ ...(0, objects_1.omit)(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter']),
456
465
  session: options?.session ?? this.getSession(),
457
466
  });
458
467
  try {
@@ -504,18 +513,28 @@ class MongoNestedService extends mongo_service_js_1.MongoService {
504
513
  },
505
514
  },
506
515
  ];
516
+ /** Pre-Stages */
517
+ if (options?.preStages)
518
+ dataStages.push(...options.preStages);
519
+ /** Filter */
507
520
  if (options?.filter || options?.nestedFilter) {
508
521
  const optionsFilter = mongo_adapter_js_1.MongoAdapter.prepareFilter([options?.filter, options?.nestedFilter]);
509
522
  dataStages.push({ $match: optionsFilter });
510
523
  }
511
- if (options?.skip)
512
- dataStages.push({ $skip: options.skip });
524
+ /** Sort */
513
525
  if (options?.sort) {
514
526
  const sort = mongo_adapter_js_1.MongoAdapter.prepareSort(options.sort);
515
527
  if (sort)
516
528
  dataStages.push({ $sort: sort });
517
529
  }
530
+ /** Skip */
531
+ if (options?.skip)
532
+ dataStages.push({ $skip: options.skip });
533
+ /** Limit */
518
534
  dataStages.push({ $limit: limit });
535
+ /** Post-Stages */
536
+ if (options?.postStages)
537
+ dataStages.push(...options.postStages);
519
538
  const dataType = this.dataType;
520
539
  const projection = mongo_adapter_js_1.MongoAdapter.prepareProjection(dataType, options?.projection);
521
540
  if (projection)
@@ -523,7 +542,7 @@ class MongoNestedService extends mongo_service_js_1.MongoService {
523
542
  const db = this.getDatabase();
524
543
  const collection = await this.getCollection(db);
525
544
  const cursor = collection.aggregate(stages, {
526
- ...(0, lodash_omit_1.default)(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
545
+ ...(0, objects_1.omit)(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter']),
527
546
  session: options?.session ?? this.getSession(),
528
547
  });
529
548
  try {
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MongoSingletonService = void 0;
4
- const tslib_1 = require("tslib");
4
+ const objects_1 = require("@jsopen/objects");
5
5
  const common_1 = require("@opra/common");
6
- const lodash_omit_1 = tslib_1.__importDefault(require("lodash.omit"));
7
6
  const mongodb_1 = require("mongodb");
8
7
  const mongo_adapter_js_1 = require("./mongo-adapter.js");
9
8
  const mongo_entity_service_js_1 = require("./mongo-entity-service.js");
@@ -54,7 +53,7 @@ class MongoSingletonService extends mongo_entity_service_js_1.MongoEntityService
54
53
  crud: 'read',
55
54
  byId: true,
56
55
  documentId: r._id,
57
- options: (0, lodash_omit_1.default)(options, 'filter'),
56
+ options,
58
57
  };
59
58
  const out = await this._findById(findCommand);
60
59
  if (out)
@@ -64,7 +63,7 @@ class MongoSingletonService extends mongo_entity_service_js_1.MongoEntityService
64
63
  /**
65
64
  * Creates the document in the database.
66
65
  *
67
- * @param {DTO<T>} input - The partial input to create the document with.
66
+ * @param {PartialDTO<T>} input - The partial input to create the document with.
68
67
  * @param {MongoEntityService.CreateOptions} [options] - The options for creating the document.
69
68
  * @returns {Promise<T>} A promise that resolves create operation result
70
69
  * @throws {Error} Throws an error if an unknown error occurs while creating the document.
@@ -164,7 +163,7 @@ class MongoSingletonService extends mongo_entity_service_js_1.MongoEntityService
164
163
  crud: 'read',
165
164
  byId: true,
166
165
  documentId: this._id,
167
- options: (0, lodash_omit_1.default)(options, ['filter', 'sort']),
166
+ options: (0, objects_1.omit)(options, ['filter', 'sort']),
168
167
  };
169
168
  const out = await this._findById(findCommand);
170
169
  if (out)
@@ -1,4 +1,4 @@
1
- import isPlainObject from 'putil-isplainobject';
1
+ import { isPlainObject } from '@jsopen/objects';
2
2
  const defaultPrimaryKey = ['_id'];
3
3
  export default function prepareKeyValues(keyValue, primaryKey) {
4
4
  primaryKey = primaryKey || defaultPrimaryKey;
@@ -1,9 +1,9 @@
1
- import { isBuiltInObject } from '@opra/common';
2
- export default function preparePatch(doc, options) {
3
- const trg = {};
4
- _preparePatch(doc, trg, '', options);
5
- trg.$set = trg.$set || {};
6
- return trg;
1
+ import { isBuiltIn } from '@jsopen/objects';
2
+ export default function preparePatch(doc, options, target) {
3
+ target = target || {};
4
+ _preparePatch(doc, target, '', options);
5
+ target.$set = target.$set || {};
6
+ return target;
7
7
  }
8
8
  function _preparePatch(src, trg, path, options) {
9
9
  let f;
@@ -20,7 +20,7 @@ function _preparePatch(src, trg, path, options) {
20
20
  trg.$unset[field] = '';
21
21
  continue;
22
22
  }
23
- if (v && typeof v === 'object' && !isBuiltInObject(v)) {
23
+ if (v && typeof v === 'object' && !isBuiltIn(v)) {
24
24
  // If field name starts with "*", do "replace" operation except "merge"
25
25
  if (!k.startsWith('*')) {
26
26
  _preparePatch(v, trg, key);
@@ -1,5 +1,4 @@
1
1
  import { ResourceNotAvailableError } from '@opra/common';
2
- import omit from 'lodash.omit';
3
2
  import { MongoAdapter } from './mongo-adapter.js';
4
3
  import { MongoEntityService } from './mongo-entity-service.js';
5
4
  /**
@@ -49,7 +48,7 @@ export class MongoCollectionService extends MongoEntityService {
49
48
  crud: 'read',
50
49
  byId: true,
51
50
  documentId: r._id,
52
- options: omit(options, 'filter'),
51
+ options,
53
52
  };
54
53
  const out = await this._findById(findCommand);
55
54
  if (out)
@@ -1,5 +1,5 @@
1
+ import { omit } from '@jsopen/objects';
1
2
  import { InternalServerError } from '@opra/common';
2
- import omit from 'lodash.omit';
3
3
  import { isNotNullish } from 'valgen';
4
4
  import { MongoAdapter } from './mongo-adapter.js';
5
5
  import { MongoService } from './mongo-service.js';
@@ -220,9 +220,6 @@ export class MongoEntityService extends MongoService {
220
220
  filter = MongoAdapter.prepareFilter(options?.filter);
221
221
  const dataStages = [];
222
222
  const countStages = [];
223
- if (filter)
224
- countStages.push({ $match: filter });
225
- countStages.push({ $count: 'totalMatches' });
226
223
  const stages = [
227
224
  {
228
225
  $facet: {
@@ -231,15 +228,25 @@ export class MongoEntityService extends MongoService {
231
228
  },
232
229
  },
233
230
  ];
234
- if (filter)
231
+ /** Pre-Stages */
232
+ if (options?.preStages)
233
+ dataStages.push(...options.preStages);
234
+ /** Filter */
235
+ if (filter) {
236
+ countStages.push({ $match: filter });
235
237
  dataStages.push({ $match: filter });
236
- if (options?.skip)
237
- dataStages.push({ $skip: options.skip });
238
+ }
239
+ countStages.push({ $count: 'totalMatches' });
240
+ /** Sort */
238
241
  if (options?.sort) {
239
242
  const sort = MongoAdapter.prepareSort(options.sort);
240
243
  if (sort)
241
244
  dataStages.push({ $sort: sort });
242
245
  }
246
+ /** Skip */
247
+ if (options?.skip)
248
+ dataStages.push({ $skip: options.skip });
249
+ /** Limit */
243
250
  dataStages.push({ $limit: limit });
244
251
  const dataType = this.dataType;
245
252
  const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
@@ -278,16 +285,7 @@ export class MongoEntityService extends MongoService {
278
285
  if (input && inputRaw) {
279
286
  throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
280
287
  }
281
- let update;
282
- if (input) {
283
- const inputCodec = this._getInputCodec('update');
284
- const doc = inputCodec(input);
285
- delete doc._id;
286
- update = MongoAdapter.preparePatch(doc);
287
- update.$set = update.$set || {};
288
- }
289
- else
290
- update = inputRaw;
288
+ const update = this._prepareUpdate(command);
291
289
  const filter = MongoAdapter.prepareFilter([
292
290
  MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
293
291
  options?.filter,
@@ -306,36 +304,6 @@ export class MongoEntityService extends MongoService {
306
304
  if (out)
307
305
  return outputCodec(out);
308
306
  }
309
- /**
310
- * Replaces a document with the given id in the collection
311
- *
312
- * @param {MongoEntityService.ReplaceCommand<T>} command
313
- */
314
- async _replace(command) {
315
- const input = command.input;
316
- isNotNullish(input, { label: 'input' });
317
- isNotNullish(input._id, { label: 'input._id' });
318
- const inputCodec = this._getInputCodec('replace');
319
- const document = inputCodec(input);
320
- const { options } = command;
321
- const filter = MongoAdapter.prepareFilter([
322
- MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
323
- options?.filter,
324
- ]);
325
- const db = this.getDatabase();
326
- const collection = await this.getCollection(db);
327
- const out = await collection.findOneAndReplace(filter || {}, document, {
328
- upsert: undefined,
329
- ...options,
330
- returnDocument: 'after',
331
- includeResultMetadata: false,
332
- session: options?.session ?? this.getSession(),
333
- projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
334
- });
335
- const outputCodec = this._getOutputCodec('replace');
336
- if (out)
337
- return outputCodec(out);
338
- }
339
307
  /**
340
308
  * Updates a document in the collection with the specified ID.
341
309
  *
@@ -348,17 +316,7 @@ export class MongoEntityService extends MongoService {
348
316
  if (input && inputRaw) {
349
317
  throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
350
318
  }
351
- let update;
352
- if (input) {
353
- const inputCodec = this._getInputCodec('update');
354
- const doc = inputCodec(input);
355
- delete doc._id;
356
- update = MongoAdapter.preparePatch(doc);
357
- if (!Object.keys(doc).length)
358
- return 0;
359
- }
360
- else
361
- update = inputRaw;
319
+ const update = this._prepareUpdate(command);
362
320
  const filter = MongoAdapter.prepareFilter([
363
321
  MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
364
322
  options?.filter,
@@ -383,26 +341,61 @@ export class MongoEntityService extends MongoService {
383
341
  if (input && inputRaw) {
384
342
  throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
385
343
  }
386
- let update;
387
- if (input) {
388
- const inputCodec = this._getInputCodec('update');
389
- const doc = inputCodec(input);
390
- delete doc._id;
391
- update = MongoAdapter.preparePatch(doc);
392
- if (!Object.keys(doc).length)
393
- return 0;
394
- }
395
- else
396
- update = inputRaw;
344
+ const update = this._prepareUpdate(command);
397
345
  const filter = MongoAdapter.prepareFilter(options?.filter);
398
346
  const db = this.getDatabase();
399
347
  const collection = await this.getCollection(db);
400
348
  return (await collection.updateMany(filter || {}, update, {
401
- ...omit(options, 'filter'),
349
+ ...omit(options, ['filter']),
402
350
  session: options?.session ?? this.getSession(),
403
351
  upsert: false,
404
352
  })).matchedCount;
405
353
  }
354
+ /**
355
+ * Replaces a document with the given id in the collection
356
+ *
357
+ * @param {MongoEntityService.ReplaceCommand<T>} command
358
+ */
359
+ async _replace(command) {
360
+ const input = command.input;
361
+ isNotNullish(input, { label: 'input' });
362
+ isNotNullish(input._id, { label: 'input._id' });
363
+ const inputCodec = this._getInputCodec('replace');
364
+ const document = inputCodec(input);
365
+ const { options } = command;
366
+ const filter = MongoAdapter.prepareFilter([
367
+ MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
368
+ options?.filter,
369
+ ]);
370
+ const db = this.getDatabase();
371
+ const collection = await this.getCollection(db);
372
+ const out = await collection.findOneAndReplace(filter || {}, document, {
373
+ upsert: undefined,
374
+ ...options,
375
+ returnDocument: 'after',
376
+ includeResultMetadata: false,
377
+ session: options?.session ?? this.getSession(),
378
+ projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
379
+ });
380
+ const outputCodec = this._getOutputCodec('replace');
381
+ if (out)
382
+ return outputCodec(out);
383
+ }
384
+ _prepareUpdate(command) {
385
+ const { input, inputRaw } = command;
386
+ isNotNullish(input || inputRaw, { label: 'input' });
387
+ if (input && inputRaw) {
388
+ throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
389
+ }
390
+ let update = { ...inputRaw };
391
+ if (input) {
392
+ const inputCodec = this._getInputCodec('update');
393
+ const doc = inputCodec(input);
394
+ delete doc._id;
395
+ update = MongoAdapter.preparePatch(doc, {}, update);
396
+ }
397
+ return update;
398
+ }
406
399
  async _executeCommand(command, commandFn) {
407
400
  try {
408
401
  const result = await super._executeCommand(command, async () => {
@@ -1,5 +1,5 @@
1
+ import { omit } from '@jsopen/objects';
1
2
  import { ComplexType, NotAcceptableError, ResourceNotAvailableError } from '@opra/common';
2
- import omit from 'lodash.omit';
3
3
  import { isNotNullish } from 'valgen';
4
4
  import { MongoAdapter } from './mongo-adapter.js';
5
5
  import { MongoService } from './mongo-service.js';
@@ -174,7 +174,7 @@ export class MongoNestedService extends MongoService {
174
174
  const db = this.getDatabase();
175
175
  const collection = await this.getCollection(db);
176
176
  const cursor = collection.aggregate(stages, {
177
- ...omit(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
177
+ ...omit(options, ['documentFilter', 'skip', 'limit', 'filter']),
178
178
  session: options?.session ?? this.getSession(),
179
179
  });
180
180
  try {
@@ -429,26 +429,36 @@ export class MongoNestedService extends MongoService {
429
429
  { $unwind: { path: '$' + this.fieldName } },
430
430
  { $replaceRoot: { newRoot: '$' + this.fieldName } },
431
431
  ];
432
+ /** Pre-Stages */
433
+ if (options?.preStages)
434
+ stages.push(...options.preStages);
435
+ /** Filter */
432
436
  if (options?.filter || options?.nestedFilter) {
433
437
  const optionsFilter = MongoAdapter.prepareFilter([options?.filter, options.nestedFilter]);
434
438
  stages.push({ $match: optionsFilter });
435
439
  }
436
- if (options?.skip)
437
- stages.push({ $skip: options.skip });
440
+ /** Sort */
438
441
  if (options?.sort) {
439
442
  const sort = MongoAdapter.prepareSort(options.sort);
440
443
  if (sort)
441
444
  stages.push({ $sort: sort });
442
445
  }
446
+ /** Skip */
447
+ if (options?.skip)
448
+ stages.push({ $skip: options.skip });
449
+ /** Limit */
443
450
  stages.push({ $limit: limit });
444
451
  const dataType = this.dataType;
445
452
  const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
446
453
  if (projection)
447
454
  stages.push({ $project: projection });
455
+ /** Post-Stages */
456
+ if (options?.postStages)
457
+ stages.push(...options.postStages);
448
458
  const db = this.getDatabase();
449
459
  const collection = await this.getCollection(db);
450
460
  const cursor = collection.aggregate(stages, {
451
- ...omit(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
461
+ ...omit(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter']),
452
462
  session: options?.session ?? this.getSession(),
453
463
  });
454
464
  try {
@@ -500,18 +510,28 @@ export class MongoNestedService extends MongoService {
500
510
  },
501
511
  },
502
512
  ];
513
+ /** Pre-Stages */
514
+ if (options?.preStages)
515
+ dataStages.push(...options.preStages);
516
+ /** Filter */
503
517
  if (options?.filter || options?.nestedFilter) {
504
518
  const optionsFilter = MongoAdapter.prepareFilter([options?.filter, options?.nestedFilter]);
505
519
  dataStages.push({ $match: optionsFilter });
506
520
  }
507
- if (options?.skip)
508
- dataStages.push({ $skip: options.skip });
521
+ /** Sort */
509
522
  if (options?.sort) {
510
523
  const sort = MongoAdapter.prepareSort(options.sort);
511
524
  if (sort)
512
525
  dataStages.push({ $sort: sort });
513
526
  }
527
+ /** Skip */
528
+ if (options?.skip)
529
+ dataStages.push({ $skip: options.skip });
530
+ /** Limit */
514
531
  dataStages.push({ $limit: limit });
532
+ /** Post-Stages */
533
+ if (options?.postStages)
534
+ dataStages.push(...options.postStages);
515
535
  const dataType = this.dataType;
516
536
  const projection = MongoAdapter.prepareProjection(dataType, options?.projection);
517
537
  if (projection)
@@ -519,7 +539,7 @@ export class MongoNestedService extends MongoService {
519
539
  const db = this.getDatabase();
520
540
  const collection = await this.getCollection(db);
521
541
  const cursor = collection.aggregate(stages, {
522
- ...omit(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter', 'count']),
542
+ ...omit(options, ['documentFilter', 'nestedFilter', 'projection', 'sort', 'skip', 'limit', 'filter']),
523
543
  session: options?.session ?? this.getSession(),
524
544
  });
525
545
  try {
@@ -1,5 +1,5 @@
1
+ import { omit } from '@jsopen/objects';
1
2
  import { ResourceNotAvailableError } from '@opra/common';
2
- import omit from 'lodash.omit';
3
3
  import { ObjectId } from 'mongodb';
4
4
  import { MongoAdapter } from './mongo-adapter.js';
5
5
  import { MongoEntityService } from './mongo-entity-service.js';
@@ -50,7 +50,7 @@ export class MongoSingletonService extends MongoEntityService {
50
50
  crud: 'read',
51
51
  byId: true,
52
52
  documentId: r._id,
53
- options: omit(options, 'filter'),
53
+ options,
54
54
  };
55
55
  const out = await this._findById(findCommand);
56
56
  if (out)
@@ -60,7 +60,7 @@ export class MongoSingletonService extends MongoEntityService {
60
60
  /**
61
61
  * Creates the document in the database.
62
62
  *
63
- * @param {DTO<T>} input - The partial input to create the document with.
63
+ * @param {PartialDTO<T>} input - The partial input to create the document with.
64
64
  * @param {MongoEntityService.CreateOptions} [options] - The options for creating the document.
65
65
  * @returns {Promise<T>} A promise that resolves create operation result
66
66
  * @throws {Error} Throws an error if an unknown error occurs while creating the document.
package/package.json CHANGED
@@ -1,19 +1,18 @@
1
1
  {
2
2
  "name": "@opra/mongodb",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Opra MongoDB adapter package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
7
7
  "dependencies": {
8
- "lodash.omit": "^4.5.0",
9
- "putil-isplainobject": "^1.1.5",
8
+ "@jsopen/objects": "^1.5.0",
10
9
  "tslib": "^2.8.1",
11
10
  "valgen": "^5.12.0"
12
11
  },
13
12
  "peerDependencies": {
14
- "@opra/common": "^1.2.1",
15
- "@opra/core": "^1.2.1",
16
- "@opra/http": "^1.2.1",
13
+ "@opra/common": "^1.2.3",
14
+ "@opra/core": "^1.2.3",
15
+ "@opra/http": "^1.2.3",
17
16
  "mongodb": ">= 6.0.0"
18
17
  },
19
18
  "type": "module",
@@ -1,3 +1,3 @@
1
1
  export default function preparePatch(doc: any, options?: {
2
2
  fieldPrefix?: string;
3
- }): any;
3
+ }, target?: any): any;
@@ -1,4 +1,4 @@
1
- import mongodb from 'mongodb';
1
+ import mongodb, { type UpdateFilter } from 'mongodb';
2
2
  import type { PartialDTO, PatchDTO, StrictOmit, Type } from 'ts-gems';
3
3
  import { MongoService } from './mongo-service.js';
4
4
  /**
@@ -31,8 +31,6 @@ export declare namespace MongoEntityService {
31
31
  interface FindOneOptions<T> extends MongoService.FindOneOptions<T> {
32
32
  }
33
33
  interface FindManyOptions<T> extends MongoService.FindManyOptions<T> {
34
- preStages?: mongodb.Document[];
35
- postStages?: mongodb.Document[];
36
34
  }
37
35
  interface ReplaceOptions<T> extends MongoService.ReplaceOptions<T> {
38
36
  }
@@ -170,12 +168,6 @@ export declare class MongoEntityService<T extends mongodb.Document> extends Mong
170
168
  * @param {MongoEntityService.UpdateOneCommand<T>} command
171
169
  */
172
170
  protected _update(command: MongoEntityService.UpdateOneCommand<T>): Promise<PartialDTO<T> | undefined>;
173
- /**
174
- * Replaces a document with the given id in the collection
175
- *
176
- * @param {MongoEntityService.ReplaceCommand<T>} command
177
- */
178
- protected _replace(command: MongoEntityService.ReplaceCommand<T>): Promise<PartialDTO<T> | undefined>;
179
171
  /**
180
172
  * Updates a document in the collection with the specified ID.
181
173
  *
@@ -188,6 +180,13 @@ export declare class MongoEntityService<T extends mongodb.Document> extends Mong
188
180
  * @param {MongoEntityService.UpdateManyCommand<T>} command
189
181
  */
190
182
  protected _updateMany(command: MongoEntityService.UpdateManyCommand<T>): Promise<number>;
183
+ /**
184
+ * Replaces a document with the given id in the collection
185
+ *
186
+ * @param {MongoEntityService.ReplaceCommand<T>} command
187
+ */
188
+ protected _replace(command: MongoEntityService.ReplaceCommand<T>): Promise<PartialDTO<T> | undefined>;
189
+ protected _prepareUpdate(command: MongoEntityService.UpdateOneCommand<T> | MongoEntityService.UpdateManyCommand<T>): UpdateFilter<T>;
191
190
  protected _executeCommand(command: MongoEntityService.CommandInfo, commandFn: () => any): Promise<any>;
192
191
  protected _beforeCreate(command: MongoEntityService.CreateCommand<T>): Promise<void>;
193
192
  protected _beforeDelete(command: MongoEntityService.DeleteCommand<T>): Promise<void>;
@@ -103,6 +103,8 @@ export declare namespace MongoService {
103
103
  sort?: string[];
104
104
  limit?: number;
105
105
  skip?: number;
106
+ preStages?: mongodb.Document[];
107
+ postStages?: mongodb.Document[];
106
108
  }
107
109
  /**
108
110
  * Represents options for "replace" operation
@@ -58,7 +58,7 @@ export declare class MongoSingletonService<T extends mongodb.Document> extends M
58
58
  /**
59
59
  * Creates the document in the database.
60
60
  *
61
- * @param {DTO<T>} input - The partial input to create the document with.
61
+ * @param {PartialDTO<T>} input - The partial input to create the document with.
62
62
  * @param {MongoEntityService.CreateOptions} [options] - The options for creating the document.
63
63
  * @returns {Promise<T>} A promise that resolves create operation result
64
64
  * @throws {Error} Throws an error if an unknown error occurs while creating the document.