@opra/mongodb 1.2.2 → 1.3.0
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/{mongo-adapter.js → adapter/mongo-adapter.js} +4 -6
- package/cjs/adapter/mongo-patch-generator.js +124 -0
- package/cjs/index.js +7 -6
- package/cjs/{mongo-collection-service.js → services/mongo-collection-service.js} +1 -1
- package/cjs/{mongo-entity-service.js → services/mongo-entity-service.js} +58 -63
- package/cjs/{mongo-nested-service.js → services/mongo-nested-service.js} +10 -3
- package/cjs/{mongo-service.js → services/mongo-service.js} +4 -2
- package/cjs/{mongo-singleton-service.js → services/mongo-singleton-service.js} +1 -1
- package/esm/{mongo-adapter.js → adapter/mongo-adapter.js} +4 -6
- package/esm/adapter/mongo-patch-generator.js +120 -0
- package/esm/index.js +7 -6
- package/esm/{mongo-collection-service.js → services/mongo-collection-service.js} +1 -1
- package/esm/{mongo-entity-service.js → services/mongo-entity-service.js} +58 -63
- package/esm/{mongo-nested-service.js → services/mongo-nested-service.js} +10 -3
- package/esm/{mongo-service.js → services/mongo-service.js} +4 -2
- package/esm/{mongo-singleton-service.js → services/mongo-singleton-service.js} +1 -1
- package/package.json +5 -5
- package/types/{mongo-adapter.d.ts → adapter/mongo-adapter.d.ts} +4 -6
- package/types/adapter/mongo-patch-generator.d.ts +23 -0
- package/types/{adapter-utils → adapter}/prepare-filter.d.ts +1 -1
- package/types/index.d.cts +7 -6
- package/types/index.d.ts +7 -6
- package/types/{mongo-collection-service.d.ts → services/mongo-collection-service.d.ts} +1 -1
- package/types/{mongo-entity-service.d.ts → services/mongo-entity-service.d.ts} +9 -7
- package/types/{mongo-nested-service.d.ts → services/mongo-nested-service.d.ts} +2 -2
- package/types/{mongo-service.d.ts → services/mongo-service.d.ts} +1 -1
- package/types/{mongo-singleton-service.d.ts → services/mongo-singleton-service.d.ts} +1 -1
- package/cjs/adapter-utils/prepare-patch.js +0 -37
- package/esm/adapter-utils/prepare-patch.js +0 -34
- package/types/adapter-utils/prepare-patch.d.ts +0 -3
- /package/cjs/{adapter-utils → adapter}/prepare-filter.js +0 -0
- /package/cjs/{adapter-utils → adapter}/prepare-key-values.js +0 -0
- /package/cjs/{adapter-utils → adapter}/prepare-projection.js +0 -0
- /package/cjs/{adapter-utils → adapter}/prepare-sort.js +0 -0
- /package/esm/{adapter-utils → adapter}/prepare-filter.js +0 -0
- /package/esm/{adapter-utils → adapter}/prepare-key-values.js +0 -0
- /package/esm/{adapter-utils → adapter}/prepare-projection.js +0 -0
- /package/esm/{adapter-utils → adapter}/prepare-sort.js +0 -0
- /package/types/{adapter-utils → adapter}/prepare-key-values.d.ts +0 -0
- /package/types/{adapter-utils → adapter}/prepare-projection.d.ts +0 -0
- /package/types/{adapter-utils → adapter}/prepare-sort.d.ts +0 -0
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MongoAdapter = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const prepare_filter_js_1 = tslib_1.__importDefault(require("./
|
|
6
|
-
const prepare_key_values_js_1 = tslib_1.__importDefault(require("./
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const prepare_sort_js_1 = tslib_1.__importDefault(require("./adapter-utils/prepare-sort.js"));
|
|
5
|
+
const prepare_filter_js_1 = tslib_1.__importDefault(require("./prepare-filter.js"));
|
|
6
|
+
const prepare_key_values_js_1 = tslib_1.__importDefault(require("./prepare-key-values.js"));
|
|
7
|
+
const prepare_projection_js_1 = tslib_1.__importDefault(require("./prepare-projection.js"));
|
|
8
|
+
const prepare_sort_js_1 = tslib_1.__importDefault(require("./prepare-sort.js"));
|
|
10
9
|
var MongoAdapter;
|
|
11
10
|
(function (MongoAdapter) {
|
|
12
11
|
MongoAdapter.prepareFilter = prepare_filter_js_1.default;
|
|
13
12
|
MongoAdapter.prepareKeyValues = prepare_key_values_js_1.default;
|
|
14
|
-
MongoAdapter.preparePatch = prepare_patch_js_1.default;
|
|
15
13
|
MongoAdapter.prepareProjection = prepare_projection_js_1.default;
|
|
16
14
|
MongoAdapter.prepareSort = prepare_sort_js_1.default;
|
|
17
15
|
async function parseRequest(context) {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongoPatchGenerator = void 0;
|
|
4
|
+
const common_1 = require("@opra/common");
|
|
5
|
+
const FIELD_NAME_PATTERN = /^([-><*:])?(.+)$/;
|
|
6
|
+
class MongoPatchGenerator {
|
|
7
|
+
generatePatch(dataType, doc, options) {
|
|
8
|
+
const ctx = {};
|
|
9
|
+
this._processComplexType(ctx, dataType, options?.currentPath || '', doc);
|
|
10
|
+
const update = {};
|
|
11
|
+
if (ctx.$pull)
|
|
12
|
+
update.$pull = ctx.$pull;
|
|
13
|
+
if (ctx.$unset)
|
|
14
|
+
update.$unset = ctx.$unset;
|
|
15
|
+
if (ctx.$set)
|
|
16
|
+
update.$set = ctx.$set;
|
|
17
|
+
return {
|
|
18
|
+
update,
|
|
19
|
+
arrayFilters: ctx.arrayFilters,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
_processComplexType(ctx, dataType, path, input) {
|
|
23
|
+
if (input.$remove) {
|
|
24
|
+
this._processRemove(ctx, dataType, path, input.$remove);
|
|
25
|
+
}
|
|
26
|
+
const keys = Object.keys(input);
|
|
27
|
+
const pathDot = path + (path ? '.' : '');
|
|
28
|
+
let field;
|
|
29
|
+
let key;
|
|
30
|
+
let value;
|
|
31
|
+
let keyField;
|
|
32
|
+
let keyValue;
|
|
33
|
+
let arrayIndex = 0;
|
|
34
|
+
let arrayFilterName = '';
|
|
35
|
+
for (key of keys) {
|
|
36
|
+
const m = FIELD_NAME_PATTERN.exec(key);
|
|
37
|
+
if (!m)
|
|
38
|
+
continue;
|
|
39
|
+
key = m[2];
|
|
40
|
+
value = input[key];
|
|
41
|
+
field = dataType.fields.get(key);
|
|
42
|
+
if (!field) {
|
|
43
|
+
if (dataType.additionalFields === true) {
|
|
44
|
+
if (value === null) {
|
|
45
|
+
ctx.$unset = ctx.$unset || {};
|
|
46
|
+
ctx.$unset[pathDot + key] = 1;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
ctx.$set = ctx.$set || {};
|
|
50
|
+
ctx.$set[pathDot + key] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (field.readonly)
|
|
56
|
+
continue;
|
|
57
|
+
if (value === null) {
|
|
58
|
+
ctx.$unset = ctx.$unset || {};
|
|
59
|
+
ctx.$unset[pathDot + field.name] = 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (field.type instanceof common_1.ComplexType) {
|
|
63
|
+
if (!value)
|
|
64
|
+
continue;
|
|
65
|
+
if (field.isArray) {
|
|
66
|
+
if (!value.length)
|
|
67
|
+
continue;
|
|
68
|
+
keyField = field.keyField || field.type.keyField;
|
|
69
|
+
if (keyField) {
|
|
70
|
+
for (let v of value) {
|
|
71
|
+
/** Increase arrayIndex and determine a new name for array filter */
|
|
72
|
+
arrayFilterName = 'f' + String(++arrayIndex);
|
|
73
|
+
/** Extract key value from object */
|
|
74
|
+
keyValue = v[keyField];
|
|
75
|
+
if (keyValue == null)
|
|
76
|
+
continue;
|
|
77
|
+
v = { ...v };
|
|
78
|
+
/** Remove key field from object */
|
|
79
|
+
delete v[keyField];
|
|
80
|
+
/** Add array filter */
|
|
81
|
+
ctx.arrayFilters = ctx.arrayFilters || {};
|
|
82
|
+
ctx.arrayFilters[`${arrayFilterName}.${keyField}`] = keyValue;
|
|
83
|
+
/** Process each object in array */
|
|
84
|
+
this._processComplexType(ctx, field.type, pathDot + field.name + `.$[${arrayFilterName}]`, v);
|
|
85
|
+
}
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!(typeof value === 'object'))
|
|
90
|
+
continue;
|
|
91
|
+
/** Process nested object */
|
|
92
|
+
this._processComplexType(ctx, field.type, pathDot + field.name, value);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
ctx.$set = ctx.$set || {};
|
|
96
|
+
ctx.$set[pathDot + field.name] = value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
_processRemove(ctx, dataType, path, input) {
|
|
100
|
+
let field;
|
|
101
|
+
let key;
|
|
102
|
+
let value;
|
|
103
|
+
const pathDot = path + (path ? '.' : '');
|
|
104
|
+
const keys = Object.keys(input);
|
|
105
|
+
let keyField;
|
|
106
|
+
for (key of keys) {
|
|
107
|
+
value = input[key];
|
|
108
|
+
field = dataType.fields.get(key);
|
|
109
|
+
if (!(field && field.isArray))
|
|
110
|
+
continue;
|
|
111
|
+
ctx.$pull = ctx.$pull || {};
|
|
112
|
+
if (field.type instanceof common_1.ComplexType) {
|
|
113
|
+
keyField = field.keyField || field.type.keyField;
|
|
114
|
+
if (!keyField)
|
|
115
|
+
continue;
|
|
116
|
+
ctx.$pull[pathDot + key] = { $elemMatch: { [keyField]: Array.isArray(value) ? { $in: value } : value } };
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
ctx.$pull[pathDot + key] = Array.isArray(value) ? { $in: value } : value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.MongoPatchGenerator = MongoPatchGenerator;
|
package/cjs/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
tslib_1.__exportStar(require("./mongo-adapter.js"), exports);
|
|
5
|
-
tslib_1.__exportStar(require("./mongo-
|
|
6
|
-
tslib_1.__exportStar(require("./mongo-
|
|
7
|
-
tslib_1.__exportStar(require("./mongo-
|
|
8
|
-
tslib_1.__exportStar(require("./mongo-service.js"), exports);
|
|
9
|
-
tslib_1.__exportStar(require("./mongo-
|
|
4
|
+
tslib_1.__exportStar(require("./adapter/mongo-adapter.js"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./adapter/mongo-patch-generator.js"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./services/mongo-collection-service.js"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./services/mongo-entity-service.js"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./services/mongo-nested-service.js"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./services/mongo-service.js"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./services/mongo-singleton-service.js"), exports);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MongoCollectionService = void 0;
|
|
4
4
|
const common_1 = require("@opra/common");
|
|
5
|
-
const mongo_adapter_js_1 = require("
|
|
5
|
+
const mongo_adapter_js_1 = require("../adapter/mongo-adapter.js");
|
|
6
6
|
const mongo_entity_service_js_1 = require("./mongo-entity-service.js");
|
|
7
7
|
/**
|
|
8
8
|
* @class MongoCollectionService
|
|
@@ -4,7 +4,8 @@ exports.MongoEntityService = void 0;
|
|
|
4
4
|
const objects_1 = require("@jsopen/objects");
|
|
5
5
|
const common_1 = require("@opra/common");
|
|
6
6
|
const valgen_1 = require("valgen");
|
|
7
|
-
const mongo_adapter_js_1 = require("
|
|
7
|
+
const mongo_adapter_js_1 = require("../adapter/mongo-adapter.js");
|
|
8
|
+
const mongo_patch_generator_js_1 = require("../adapter/mongo-patch-generator.js");
|
|
8
9
|
const mongo_service_js_1 = require("./mongo-service.js");
|
|
9
10
|
/**
|
|
10
11
|
* @class MongoEntityService
|
|
@@ -288,16 +289,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
|
|
|
288
289
|
if (input && inputRaw) {
|
|
289
290
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
290
291
|
}
|
|
291
|
-
|
|
292
|
-
if (input) {
|
|
293
|
-
const inputCodec = this._getInputCodec('update');
|
|
294
|
-
const doc = inputCodec(input);
|
|
295
|
-
delete doc._id;
|
|
296
|
-
update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
297
|
-
update.$set = update.$set || {};
|
|
298
|
-
}
|
|
299
|
-
else
|
|
300
|
-
update = inputRaw;
|
|
292
|
+
const update = this._prepareUpdate(command);
|
|
301
293
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
302
294
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
303
295
|
options?.filter,
|
|
@@ -316,36 +308,6 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
|
|
|
316
308
|
if (out)
|
|
317
309
|
return outputCodec(out);
|
|
318
310
|
}
|
|
319
|
-
/**
|
|
320
|
-
* Replaces a document with the given id in the collection
|
|
321
|
-
*
|
|
322
|
-
* @param {MongoEntityService.ReplaceCommand<T>} command
|
|
323
|
-
*/
|
|
324
|
-
async _replace(command) {
|
|
325
|
-
const input = command.input;
|
|
326
|
-
(0, valgen_1.isNotNullish)(input, { label: 'input' });
|
|
327
|
-
(0, valgen_1.isNotNullish)(input._id, { label: 'input._id' });
|
|
328
|
-
const inputCodec = this._getInputCodec('replace');
|
|
329
|
-
const document = inputCodec(input);
|
|
330
|
-
const { options } = command;
|
|
331
|
-
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
332
|
-
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
333
|
-
options?.filter,
|
|
334
|
-
]);
|
|
335
|
-
const db = this.getDatabase();
|
|
336
|
-
const collection = await this.getCollection(db);
|
|
337
|
-
const out = await collection.findOneAndReplace(filter || {}, document, {
|
|
338
|
-
upsert: undefined,
|
|
339
|
-
...options,
|
|
340
|
-
returnDocument: 'after',
|
|
341
|
-
includeResultMetadata: false,
|
|
342
|
-
session: options?.session ?? this.getSession(),
|
|
343
|
-
projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
344
|
-
});
|
|
345
|
-
const outputCodec = this._getOutputCodec('replace');
|
|
346
|
-
if (out)
|
|
347
|
-
return outputCodec(out);
|
|
348
|
-
}
|
|
349
311
|
/**
|
|
350
312
|
* Updates a document in the collection with the specified ID.
|
|
351
313
|
*
|
|
@@ -358,17 +320,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
|
|
|
358
320
|
if (input && inputRaw) {
|
|
359
321
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
360
322
|
}
|
|
361
|
-
|
|
362
|
-
if (input) {
|
|
363
|
-
const inputCodec = this._getInputCodec('update');
|
|
364
|
-
const doc = inputCodec(input);
|
|
365
|
-
delete doc._id;
|
|
366
|
-
update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
367
|
-
if (!Object.keys(doc).length)
|
|
368
|
-
return 0;
|
|
369
|
-
}
|
|
370
|
-
else
|
|
371
|
-
update = inputRaw;
|
|
323
|
+
const update = this._prepareUpdate(command);
|
|
372
324
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
373
325
|
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
374
326
|
options?.filter,
|
|
@@ -393,17 +345,7 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
|
|
|
393
345
|
if (input && inputRaw) {
|
|
394
346
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
395
347
|
}
|
|
396
|
-
|
|
397
|
-
if (input) {
|
|
398
|
-
const inputCodec = this._getInputCodec('update');
|
|
399
|
-
const doc = inputCodec(input);
|
|
400
|
-
delete doc._id;
|
|
401
|
-
update = mongo_adapter_js_1.MongoAdapter.preparePatch(doc);
|
|
402
|
-
if (!Object.keys(doc).length)
|
|
403
|
-
return 0;
|
|
404
|
-
}
|
|
405
|
-
else
|
|
406
|
-
update = inputRaw;
|
|
348
|
+
const update = this._prepareUpdate(command);
|
|
407
349
|
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter(options?.filter);
|
|
408
350
|
const db = this.getDatabase();
|
|
409
351
|
const collection = await this.getCollection(db);
|
|
@@ -413,6 +355,59 @@ class MongoEntityService extends mongo_service_js_1.MongoService {
|
|
|
413
355
|
upsert: false,
|
|
414
356
|
})).matchedCount;
|
|
415
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* Replaces a document with the given id in the collection
|
|
360
|
+
*
|
|
361
|
+
* @param {MongoEntityService.ReplaceCommand<T>} command
|
|
362
|
+
*/
|
|
363
|
+
async _replace(command) {
|
|
364
|
+
const input = command.input;
|
|
365
|
+
(0, valgen_1.isNotNullish)(input, { label: 'input' });
|
|
366
|
+
(0, valgen_1.isNotNullish)(input._id, { label: 'input._id' });
|
|
367
|
+
const inputCodec = this._getInputCodec('replace');
|
|
368
|
+
const document = inputCodec(input);
|
|
369
|
+
const { options } = command;
|
|
370
|
+
const filter = mongo_adapter_js_1.MongoAdapter.prepareFilter([
|
|
371
|
+
mongo_adapter_js_1.MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
372
|
+
options?.filter,
|
|
373
|
+
]);
|
|
374
|
+
const db = this.getDatabase();
|
|
375
|
+
const collection = await this.getCollection(db);
|
|
376
|
+
const out = await collection.findOneAndReplace(filter || {}, document, {
|
|
377
|
+
upsert: undefined,
|
|
378
|
+
...options,
|
|
379
|
+
returnDocument: 'after',
|
|
380
|
+
includeResultMetadata: false,
|
|
381
|
+
session: options?.session ?? this.getSession(),
|
|
382
|
+
projection: mongo_adapter_js_1.MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
383
|
+
});
|
|
384
|
+
const outputCodec = this._getOutputCodec('replace');
|
|
385
|
+
if (out)
|
|
386
|
+
return outputCodec(out);
|
|
387
|
+
}
|
|
388
|
+
_prepareUpdate(command) {
|
|
389
|
+
const { input, inputRaw } = command;
|
|
390
|
+
(0, valgen_1.isNotNullish)(input || inputRaw, { label: 'input' });
|
|
391
|
+
if (input && inputRaw) {
|
|
392
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
393
|
+
}
|
|
394
|
+
if (inputRaw)
|
|
395
|
+
return inputRaw;
|
|
396
|
+
const inputCodec = this._getInputCodec('update');
|
|
397
|
+
const doc = inputCodec(input);
|
|
398
|
+
delete doc._id;
|
|
399
|
+
return this._generatePatch(command, doc);
|
|
400
|
+
}
|
|
401
|
+
_generatePatch(command, doc) {
|
|
402
|
+
const patchGenerator = new mongo_patch_generator_js_1.MongoPatchGenerator();
|
|
403
|
+
const { update, arrayFilters } = patchGenerator.generatePatch(this.dataType, doc);
|
|
404
|
+
command.options = command.options || {};
|
|
405
|
+
if (arrayFilters) {
|
|
406
|
+
command.options.arrayFilters = command.options.arrayFilters || [];
|
|
407
|
+
command.options.arrayFilters.push(arrayFilters);
|
|
408
|
+
}
|
|
409
|
+
return update;
|
|
410
|
+
}
|
|
416
411
|
async _executeCommand(command, commandFn) {
|
|
417
412
|
try {
|
|
418
413
|
const result = await super._executeCommand(command, async () => {
|
|
@@ -4,7 +4,8 @@ exports.MongoNestedService = void 0;
|
|
|
4
4
|
const objects_1 = require("@jsopen/objects");
|
|
5
5
|
const common_1 = require("@opra/common");
|
|
6
6
|
const valgen_1 = require("valgen");
|
|
7
|
-
const mongo_adapter_js_1 = require("
|
|
7
|
+
const mongo_adapter_js_1 = require("../adapter/mongo-adapter.js");
|
|
8
|
+
const mongo_patch_generator_js_1 = require("../adapter/mongo-patch-generator.js");
|
|
8
9
|
const mongo_service_js_1 = require("./mongo-service.js");
|
|
9
10
|
/**
|
|
10
11
|
* A class that provides methods to perform operations on an array field in a MongoDB collection.
|
|
@@ -687,9 +688,15 @@ class MongoNestedService extends mongo_service_js_1.MongoService {
|
|
|
687
688
|
const elemMatch = mongo_adapter_js_1.MongoAdapter.prepareFilter([options?.filter], { fieldPrefix: 'elem.' });
|
|
688
689
|
options.arrayFilters = [elemMatch];
|
|
689
690
|
}
|
|
690
|
-
const
|
|
691
|
-
|
|
691
|
+
const patchGenerator = new mongo_patch_generator_js_1.MongoPatchGenerator();
|
|
692
|
+
const { update, arrayFilters } = patchGenerator.generatePatch(this.dataType, doc, {
|
|
693
|
+
currentPath: this.fieldName + (options?.filter ? '.$[elem]' : '.$[]'),
|
|
692
694
|
});
|
|
695
|
+
command.options = command.options || {};
|
|
696
|
+
if (arrayFilters) {
|
|
697
|
+
command.options.arrayFilters = command.options.arrayFilters || [];
|
|
698
|
+
command.options.arrayFilters.push(arrayFilters);
|
|
699
|
+
}
|
|
693
700
|
// Count matching items, we will use this as result
|
|
694
701
|
const count = await this._count({
|
|
695
702
|
crud: 'read',
|
|
@@ -4,7 +4,7 @@ exports.MongoService = void 0;
|
|
|
4
4
|
const common_1 = require("@opra/common");
|
|
5
5
|
const core_1 = require("@opra/core");
|
|
6
6
|
const mongodb_1 = require("mongodb");
|
|
7
|
-
const mongo_adapter_js_1 = require("
|
|
7
|
+
const mongo_adapter_js_1 = require("../adapter/mongo-adapter.js");
|
|
8
8
|
const transactionKey = Symbol.for('transaction');
|
|
9
9
|
/**
|
|
10
10
|
* Class representing a MongoDB service for interacting with a collection.
|
|
@@ -232,8 +232,10 @@ class MongoService extends core_1.ServiceBase {
|
|
|
232
232
|
if (validator)
|
|
233
233
|
return validator;
|
|
234
234
|
const options = { projection: '*' };
|
|
235
|
-
if (operation === 'update')
|
|
235
|
+
if (operation === 'update') {
|
|
236
236
|
options.partial = 'deep';
|
|
237
|
+
options.allowPatchOperators = true;
|
|
238
|
+
}
|
|
237
239
|
const dataType = this.dataType;
|
|
238
240
|
validator = dataType.generateCodec('decode', options);
|
|
239
241
|
this._inputCodecs[operation] = validator;
|
|
@@ -4,7 +4,7 @@ exports.MongoSingletonService = void 0;
|
|
|
4
4
|
const objects_1 = require("@jsopen/objects");
|
|
5
5
|
const common_1 = require("@opra/common");
|
|
6
6
|
const mongodb_1 = require("mongodb");
|
|
7
|
-
const mongo_adapter_js_1 = require("
|
|
7
|
+
const mongo_adapter_js_1 = require("../adapter/mongo-adapter.js");
|
|
8
8
|
const mongo_entity_service_js_1 = require("./mongo-entity-service.js");
|
|
9
9
|
/**
|
|
10
10
|
* A class that provides access to a MongoDB collection, with support for singleton document operations.
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import _prepareFilter from './
|
|
2
|
-
import _prepareKeyValues from './
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import _prepareSort from './adapter-utils/prepare-sort.js';
|
|
1
|
+
import _prepareFilter from './prepare-filter.js';
|
|
2
|
+
import _prepareKeyValues from './prepare-key-values.js';
|
|
3
|
+
import _prepareProjection from './prepare-projection.js';
|
|
4
|
+
import _prepareSort from './prepare-sort.js';
|
|
6
5
|
export var MongoAdapter;
|
|
7
6
|
(function (MongoAdapter) {
|
|
8
7
|
MongoAdapter.prepareFilter = _prepareFilter;
|
|
9
8
|
MongoAdapter.prepareKeyValues = _prepareKeyValues;
|
|
10
|
-
MongoAdapter.preparePatch = _preparePatch;
|
|
11
9
|
MongoAdapter.prepareProjection = _prepareProjection;
|
|
12
10
|
MongoAdapter.prepareSort = _prepareSort;
|
|
13
11
|
async function parseRequest(context) {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ComplexType } from '@opra/common';
|
|
2
|
+
const FIELD_NAME_PATTERN = /^([-><*:])?(.+)$/;
|
|
3
|
+
export class MongoPatchGenerator {
|
|
4
|
+
generatePatch(dataType, doc, options) {
|
|
5
|
+
const ctx = {};
|
|
6
|
+
this._processComplexType(ctx, dataType, options?.currentPath || '', doc);
|
|
7
|
+
const update = {};
|
|
8
|
+
if (ctx.$pull)
|
|
9
|
+
update.$pull = ctx.$pull;
|
|
10
|
+
if (ctx.$unset)
|
|
11
|
+
update.$unset = ctx.$unset;
|
|
12
|
+
if (ctx.$set)
|
|
13
|
+
update.$set = ctx.$set;
|
|
14
|
+
return {
|
|
15
|
+
update,
|
|
16
|
+
arrayFilters: ctx.arrayFilters,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
_processComplexType(ctx, dataType, path, input) {
|
|
20
|
+
if (input.$remove) {
|
|
21
|
+
this._processRemove(ctx, dataType, path, input.$remove);
|
|
22
|
+
}
|
|
23
|
+
const keys = Object.keys(input);
|
|
24
|
+
const pathDot = path + (path ? '.' : '');
|
|
25
|
+
let field;
|
|
26
|
+
let key;
|
|
27
|
+
let value;
|
|
28
|
+
let keyField;
|
|
29
|
+
let keyValue;
|
|
30
|
+
let arrayIndex = 0;
|
|
31
|
+
let arrayFilterName = '';
|
|
32
|
+
for (key of keys) {
|
|
33
|
+
const m = FIELD_NAME_PATTERN.exec(key);
|
|
34
|
+
if (!m)
|
|
35
|
+
continue;
|
|
36
|
+
key = m[2];
|
|
37
|
+
value = input[key];
|
|
38
|
+
field = dataType.fields.get(key);
|
|
39
|
+
if (!field) {
|
|
40
|
+
if (dataType.additionalFields === true) {
|
|
41
|
+
if (value === null) {
|
|
42
|
+
ctx.$unset = ctx.$unset || {};
|
|
43
|
+
ctx.$unset[pathDot + key] = 1;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
ctx.$set = ctx.$set || {};
|
|
47
|
+
ctx.$set[pathDot + key] = value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (field.readonly)
|
|
53
|
+
continue;
|
|
54
|
+
if (value === null) {
|
|
55
|
+
ctx.$unset = ctx.$unset || {};
|
|
56
|
+
ctx.$unset[pathDot + field.name] = 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (field.type instanceof ComplexType) {
|
|
60
|
+
if (!value)
|
|
61
|
+
continue;
|
|
62
|
+
if (field.isArray) {
|
|
63
|
+
if (!value.length)
|
|
64
|
+
continue;
|
|
65
|
+
keyField = field.keyField || field.type.keyField;
|
|
66
|
+
if (keyField) {
|
|
67
|
+
for (let v of value) {
|
|
68
|
+
/** Increase arrayIndex and determine a new name for array filter */
|
|
69
|
+
arrayFilterName = 'f' + String(++arrayIndex);
|
|
70
|
+
/** Extract key value from object */
|
|
71
|
+
keyValue = v[keyField];
|
|
72
|
+
if (keyValue == null)
|
|
73
|
+
continue;
|
|
74
|
+
v = { ...v };
|
|
75
|
+
/** Remove key field from object */
|
|
76
|
+
delete v[keyField];
|
|
77
|
+
/** Add array filter */
|
|
78
|
+
ctx.arrayFilters = ctx.arrayFilters || {};
|
|
79
|
+
ctx.arrayFilters[`${arrayFilterName}.${keyField}`] = keyValue;
|
|
80
|
+
/** Process each object in array */
|
|
81
|
+
this._processComplexType(ctx, field.type, pathDot + field.name + `.$[${arrayFilterName}]`, v);
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!(typeof value === 'object'))
|
|
87
|
+
continue;
|
|
88
|
+
/** Process nested object */
|
|
89
|
+
this._processComplexType(ctx, field.type, pathDot + field.name, value);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
ctx.$set = ctx.$set || {};
|
|
93
|
+
ctx.$set[pathDot + field.name] = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
_processRemove(ctx, dataType, path, input) {
|
|
97
|
+
let field;
|
|
98
|
+
let key;
|
|
99
|
+
let value;
|
|
100
|
+
const pathDot = path + (path ? '.' : '');
|
|
101
|
+
const keys = Object.keys(input);
|
|
102
|
+
let keyField;
|
|
103
|
+
for (key of keys) {
|
|
104
|
+
value = input[key];
|
|
105
|
+
field = dataType.fields.get(key);
|
|
106
|
+
if (!(field && field.isArray))
|
|
107
|
+
continue;
|
|
108
|
+
ctx.$pull = ctx.$pull || {};
|
|
109
|
+
if (field.type instanceof ComplexType) {
|
|
110
|
+
keyField = field.keyField || field.type.keyField;
|
|
111
|
+
if (!keyField)
|
|
112
|
+
continue;
|
|
113
|
+
ctx.$pull[pathDot + key] = { $elemMatch: { [keyField]: Array.isArray(value) ? { $in: value } : value } };
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
ctx.$pull[pathDot + key] = Array.isArray(value) ? { $in: value } : value;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
package/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from './mongo-adapter.js';
|
|
2
|
-
export * from './mongo-
|
|
3
|
-
export * from './mongo-
|
|
4
|
-
export * from './mongo-
|
|
5
|
-
export * from './mongo-service.js';
|
|
6
|
-
export * from './mongo-
|
|
1
|
+
export * from './adapter/mongo-adapter.js';
|
|
2
|
+
export * from './adapter/mongo-patch-generator.js';
|
|
3
|
+
export * from './services/mongo-collection-service.js';
|
|
4
|
+
export * from './services/mongo-entity-service.js';
|
|
5
|
+
export * from './services/mongo-nested-service.js';
|
|
6
|
+
export * from './services/mongo-service.js';
|
|
7
|
+
export * from './services/mongo-singleton-service.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ResourceNotAvailableError } from '@opra/common';
|
|
2
|
-
import { MongoAdapter } from '
|
|
2
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
3
3
|
import { MongoEntityService } from './mongo-entity-service.js';
|
|
4
4
|
/**
|
|
5
5
|
* @class MongoCollectionService
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { omit } from '@jsopen/objects';
|
|
2
2
|
import { InternalServerError } from '@opra/common';
|
|
3
3
|
import { isNotNullish } from 'valgen';
|
|
4
|
-
import { MongoAdapter } from '
|
|
4
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
5
|
+
import { MongoPatchGenerator } from '../adapter/mongo-patch-generator.js';
|
|
5
6
|
import { MongoService } from './mongo-service.js';
|
|
6
7
|
/**
|
|
7
8
|
* @class MongoEntityService
|
|
@@ -285,16 +286,7 @@ export class MongoEntityService extends MongoService {
|
|
|
285
286
|
if (input && inputRaw) {
|
|
286
287
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
287
288
|
}
|
|
288
|
-
|
|
289
|
-
if (input) {
|
|
290
|
-
const inputCodec = this._getInputCodec('update');
|
|
291
|
-
const doc = inputCodec(input);
|
|
292
|
-
delete doc._id;
|
|
293
|
-
update = MongoAdapter.preparePatch(doc);
|
|
294
|
-
update.$set = update.$set || {};
|
|
295
|
-
}
|
|
296
|
-
else
|
|
297
|
-
update = inputRaw;
|
|
289
|
+
const update = this._prepareUpdate(command);
|
|
298
290
|
const filter = MongoAdapter.prepareFilter([
|
|
299
291
|
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
300
292
|
options?.filter,
|
|
@@ -313,36 +305,6 @@ export class MongoEntityService extends MongoService {
|
|
|
313
305
|
if (out)
|
|
314
306
|
return outputCodec(out);
|
|
315
307
|
}
|
|
316
|
-
/**
|
|
317
|
-
* Replaces a document with the given id in the collection
|
|
318
|
-
*
|
|
319
|
-
* @param {MongoEntityService.ReplaceCommand<T>} command
|
|
320
|
-
*/
|
|
321
|
-
async _replace(command) {
|
|
322
|
-
const input = command.input;
|
|
323
|
-
isNotNullish(input, { label: 'input' });
|
|
324
|
-
isNotNullish(input._id, { label: 'input._id' });
|
|
325
|
-
const inputCodec = this._getInputCodec('replace');
|
|
326
|
-
const document = inputCodec(input);
|
|
327
|
-
const { options } = command;
|
|
328
|
-
const filter = MongoAdapter.prepareFilter([
|
|
329
|
-
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
330
|
-
options?.filter,
|
|
331
|
-
]);
|
|
332
|
-
const db = this.getDatabase();
|
|
333
|
-
const collection = await this.getCollection(db);
|
|
334
|
-
const out = await collection.findOneAndReplace(filter || {}, document, {
|
|
335
|
-
upsert: undefined,
|
|
336
|
-
...options,
|
|
337
|
-
returnDocument: 'after',
|
|
338
|
-
includeResultMetadata: false,
|
|
339
|
-
session: options?.session ?? this.getSession(),
|
|
340
|
-
projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
341
|
-
});
|
|
342
|
-
const outputCodec = this._getOutputCodec('replace');
|
|
343
|
-
if (out)
|
|
344
|
-
return outputCodec(out);
|
|
345
|
-
}
|
|
346
308
|
/**
|
|
347
309
|
* Updates a document in the collection with the specified ID.
|
|
348
310
|
*
|
|
@@ -355,17 +317,7 @@ export class MongoEntityService extends MongoService {
|
|
|
355
317
|
if (input && inputRaw) {
|
|
356
318
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
357
319
|
}
|
|
358
|
-
|
|
359
|
-
if (input) {
|
|
360
|
-
const inputCodec = this._getInputCodec('update');
|
|
361
|
-
const doc = inputCodec(input);
|
|
362
|
-
delete doc._id;
|
|
363
|
-
update = MongoAdapter.preparePatch(doc);
|
|
364
|
-
if (!Object.keys(doc).length)
|
|
365
|
-
return 0;
|
|
366
|
-
}
|
|
367
|
-
else
|
|
368
|
-
update = inputRaw;
|
|
320
|
+
const update = this._prepareUpdate(command);
|
|
369
321
|
const filter = MongoAdapter.prepareFilter([
|
|
370
322
|
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
371
323
|
options?.filter,
|
|
@@ -390,17 +342,7 @@ export class MongoEntityService extends MongoService {
|
|
|
390
342
|
if (input && inputRaw) {
|
|
391
343
|
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
392
344
|
}
|
|
393
|
-
|
|
394
|
-
if (input) {
|
|
395
|
-
const inputCodec = this._getInputCodec('update');
|
|
396
|
-
const doc = inputCodec(input);
|
|
397
|
-
delete doc._id;
|
|
398
|
-
update = MongoAdapter.preparePatch(doc);
|
|
399
|
-
if (!Object.keys(doc).length)
|
|
400
|
-
return 0;
|
|
401
|
-
}
|
|
402
|
-
else
|
|
403
|
-
update = inputRaw;
|
|
345
|
+
const update = this._prepareUpdate(command);
|
|
404
346
|
const filter = MongoAdapter.prepareFilter(options?.filter);
|
|
405
347
|
const db = this.getDatabase();
|
|
406
348
|
const collection = await this.getCollection(db);
|
|
@@ -410,6 +352,59 @@ export class MongoEntityService extends MongoService {
|
|
|
410
352
|
upsert: false,
|
|
411
353
|
})).matchedCount;
|
|
412
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Replaces a document with the given id in the collection
|
|
357
|
+
*
|
|
358
|
+
* @param {MongoEntityService.ReplaceCommand<T>} command
|
|
359
|
+
*/
|
|
360
|
+
async _replace(command) {
|
|
361
|
+
const input = command.input;
|
|
362
|
+
isNotNullish(input, { label: 'input' });
|
|
363
|
+
isNotNullish(input._id, { label: 'input._id' });
|
|
364
|
+
const inputCodec = this._getInputCodec('replace');
|
|
365
|
+
const document = inputCodec(input);
|
|
366
|
+
const { options } = command;
|
|
367
|
+
const filter = MongoAdapter.prepareFilter([
|
|
368
|
+
MongoAdapter.prepareKeyValues(command.documentId, ['_id']),
|
|
369
|
+
options?.filter,
|
|
370
|
+
]);
|
|
371
|
+
const db = this.getDatabase();
|
|
372
|
+
const collection = await this.getCollection(db);
|
|
373
|
+
const out = await collection.findOneAndReplace(filter || {}, document, {
|
|
374
|
+
upsert: undefined,
|
|
375
|
+
...options,
|
|
376
|
+
returnDocument: 'after',
|
|
377
|
+
includeResultMetadata: false,
|
|
378
|
+
session: options?.session ?? this.getSession(),
|
|
379
|
+
projection: MongoAdapter.prepareProjection(this.dataType, options?.projection),
|
|
380
|
+
});
|
|
381
|
+
const outputCodec = this._getOutputCodec('replace');
|
|
382
|
+
if (out)
|
|
383
|
+
return outputCodec(out);
|
|
384
|
+
}
|
|
385
|
+
_prepareUpdate(command) {
|
|
386
|
+
const { input, inputRaw } = command;
|
|
387
|
+
isNotNullish(input || inputRaw, { label: 'input' });
|
|
388
|
+
if (input && inputRaw) {
|
|
389
|
+
throw new TypeError('You must pass one of MongoDB UpdateFilter or a partial document, not both');
|
|
390
|
+
}
|
|
391
|
+
if (inputRaw)
|
|
392
|
+
return inputRaw;
|
|
393
|
+
const inputCodec = this._getInputCodec('update');
|
|
394
|
+
const doc = inputCodec(input);
|
|
395
|
+
delete doc._id;
|
|
396
|
+
return this._generatePatch(command, doc);
|
|
397
|
+
}
|
|
398
|
+
_generatePatch(command, doc) {
|
|
399
|
+
const patchGenerator = new MongoPatchGenerator();
|
|
400
|
+
const { update, arrayFilters } = patchGenerator.generatePatch(this.dataType, doc);
|
|
401
|
+
command.options = command.options || {};
|
|
402
|
+
if (arrayFilters) {
|
|
403
|
+
command.options.arrayFilters = command.options.arrayFilters || [];
|
|
404
|
+
command.options.arrayFilters.push(arrayFilters);
|
|
405
|
+
}
|
|
406
|
+
return update;
|
|
407
|
+
}
|
|
413
408
|
async _executeCommand(command, commandFn) {
|
|
414
409
|
try {
|
|
415
410
|
const result = await super._executeCommand(command, async () => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { omit } from '@jsopen/objects';
|
|
2
2
|
import { ComplexType, NotAcceptableError, ResourceNotAvailableError } from '@opra/common';
|
|
3
3
|
import { isNotNullish } from 'valgen';
|
|
4
|
-
import { MongoAdapter } from '
|
|
4
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
5
|
+
import { MongoPatchGenerator } from '../adapter/mongo-patch-generator.js';
|
|
5
6
|
import { MongoService } from './mongo-service.js';
|
|
6
7
|
/**
|
|
7
8
|
* A class that provides methods to perform operations on an array field in a MongoDB collection.
|
|
@@ -684,9 +685,15 @@ export class MongoNestedService extends MongoService {
|
|
|
684
685
|
const elemMatch = MongoAdapter.prepareFilter([options?.filter], { fieldPrefix: 'elem.' });
|
|
685
686
|
options.arrayFilters = [elemMatch];
|
|
686
687
|
}
|
|
687
|
-
const
|
|
688
|
-
|
|
688
|
+
const patchGenerator = new MongoPatchGenerator();
|
|
689
|
+
const { update, arrayFilters } = patchGenerator.generatePatch(this.dataType, doc, {
|
|
690
|
+
currentPath: this.fieldName + (options?.filter ? '.$[elem]' : '.$[]'),
|
|
689
691
|
});
|
|
692
|
+
command.options = command.options || {};
|
|
693
|
+
if (arrayFilters) {
|
|
694
|
+
command.options.arrayFilters = command.options.arrayFilters || [];
|
|
695
|
+
command.options.arrayFilters.push(arrayFilters);
|
|
696
|
+
}
|
|
690
697
|
// Count matching items, we will use this as result
|
|
691
698
|
const count = await this._count({
|
|
692
699
|
crud: 'read',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DATATYPE_METADATA } from '@opra/common';
|
|
2
2
|
import { ServiceBase } from '@opra/core';
|
|
3
3
|
import { ObjectId } from 'mongodb';
|
|
4
|
-
import { MongoAdapter } from '
|
|
4
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
5
5
|
const transactionKey = Symbol.for('transaction');
|
|
6
6
|
/**
|
|
7
7
|
* Class representing a MongoDB service for interacting with a collection.
|
|
@@ -229,8 +229,10 @@ export class MongoService extends ServiceBase {
|
|
|
229
229
|
if (validator)
|
|
230
230
|
return validator;
|
|
231
231
|
const options = { projection: '*' };
|
|
232
|
-
if (operation === 'update')
|
|
232
|
+
if (operation === 'update') {
|
|
233
233
|
options.partial = 'deep';
|
|
234
|
+
options.allowPatchOperators = true;
|
|
235
|
+
}
|
|
234
236
|
const dataType = this.dataType;
|
|
235
237
|
validator = dataType.generateCodec('decode', options);
|
|
236
238
|
this._inputCodecs[operation] = validator;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { omit } from '@jsopen/objects';
|
|
2
2
|
import { ResourceNotAvailableError } from '@opra/common';
|
|
3
3
|
import { ObjectId } from 'mongodb';
|
|
4
|
-
import { MongoAdapter } from '
|
|
4
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
5
5
|
import { MongoEntityService } from './mongo-entity-service.js';
|
|
6
6
|
/**
|
|
7
7
|
* A class that provides access to a MongoDB collection, with support for singleton document operations.
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/mongodb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Opra MongoDB adapter package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@jsopen/objects": "^1.
|
|
8
|
+
"@jsopen/objects": "^1.5.0",
|
|
9
9
|
"tslib": "^2.8.1",
|
|
10
10
|
"valgen": "^5.12.0"
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
|
-
"@opra/common": "^1.
|
|
14
|
-
"@opra/core": "^1.
|
|
15
|
-
"@opra/http": "^1.
|
|
13
|
+
"@opra/common": "^1.3.0",
|
|
14
|
+
"@opra/core": "^1.3.0",
|
|
15
|
+
"@opra/http": "^1.3.0",
|
|
16
16
|
"mongodb": ">= 6.0.0"
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { OpraFilter } from '@opra/common';
|
|
2
2
|
import type { ExecutionContext } from '@opra/core';
|
|
3
3
|
import mongodb, { ObjectId } from 'mongodb';
|
|
4
|
-
import _prepareFilter from './
|
|
5
|
-
import _prepareKeyValues from './
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import _prepareSort from './adapter-utils/prepare-sort.js';
|
|
4
|
+
import _prepareFilter from './prepare-filter.js';
|
|
5
|
+
import _prepareKeyValues from './prepare-key-values.js';
|
|
6
|
+
import _prepareProjection from './prepare-projection.js';
|
|
7
|
+
import _prepareSort from './prepare-sort.js';
|
|
9
8
|
export declare namespace MongoAdapter {
|
|
10
9
|
type AnyId = string | number | ObjectId;
|
|
11
10
|
type FilterInput<T = any> = OpraFilter.Expression | mongodb.Filter<T> | string | undefined;
|
|
12
11
|
const prepareFilter: typeof _prepareFilter;
|
|
13
12
|
const prepareKeyValues: typeof _prepareKeyValues;
|
|
14
|
-
const preparePatch: typeof _preparePatch;
|
|
15
13
|
const prepareProjection: typeof _prepareProjection;
|
|
16
14
|
const prepareSort: typeof _prepareSort;
|
|
17
15
|
interface TransformedRequest {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComplexType } from '@opra/common';
|
|
2
|
+
import type { UpdateFilter } from 'mongodb';
|
|
3
|
+
import type { PatchDTO } from 'ts-gems';
|
|
4
|
+
interface Context {
|
|
5
|
+
$set?: Record<string, any>;
|
|
6
|
+
$unset?: Record<string, any>;
|
|
7
|
+
$pull?: Record<string, any>;
|
|
8
|
+
arrayFilters?: Record<string, any>;
|
|
9
|
+
}
|
|
10
|
+
export declare class MongoPatchGenerator {
|
|
11
|
+
generatePatch<T extends object>(dataType: ComplexType, doc: PatchDTO<T>, options?: MongoPatchGenerator.Options): {
|
|
12
|
+
update: UpdateFilter<T>;
|
|
13
|
+
arrayFilters?: Record<string, any>;
|
|
14
|
+
};
|
|
15
|
+
protected _processComplexType(ctx: Context, dataType: ComplexType, path: string, input: any): void;
|
|
16
|
+
protected _processRemove(ctx: Context, dataType: ComplexType, path: string, input: any): void;
|
|
17
|
+
}
|
|
18
|
+
export declare namespace MongoPatchGenerator {
|
|
19
|
+
interface Options {
|
|
20
|
+
currentPath?: string;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {};
|
package/types/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from './mongo-adapter.js';
|
|
2
|
-
export * from './mongo-
|
|
3
|
-
export * from './mongo-
|
|
4
|
-
export * from './mongo-
|
|
5
|
-
export * from './mongo-service.js';
|
|
6
|
-
export * from './mongo-
|
|
1
|
+
export * from './adapter/mongo-adapter.js';
|
|
2
|
+
export * from './adapter/mongo-patch-generator.js';
|
|
3
|
+
export * from './services/mongo-collection-service.js';
|
|
4
|
+
export * from './services/mongo-entity-service.js';
|
|
5
|
+
export * from './services/mongo-nested-service.js';
|
|
6
|
+
export * from './services/mongo-service.js';
|
|
7
|
+
export * from './services/mongo-singleton-service.js';
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from './mongo-adapter.js';
|
|
2
|
-
export * from './mongo-
|
|
3
|
-
export * from './mongo-
|
|
4
|
-
export * from './mongo-
|
|
5
|
-
export * from './mongo-service.js';
|
|
6
|
-
export * from './mongo-
|
|
1
|
+
export * from './adapter/mongo-adapter.js';
|
|
2
|
+
export * from './adapter/mongo-patch-generator.js';
|
|
3
|
+
export * from './services/mongo-collection-service.js';
|
|
4
|
+
export * from './services/mongo-entity-service.js';
|
|
5
|
+
export * from './services/mongo-nested-service.js';
|
|
6
|
+
export * from './services/mongo-service.js';
|
|
7
|
+
export * from './services/mongo-singleton-service.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import mongodb, { type UpdateFilter } from 'mongodb';
|
|
2
2
|
import type { PartialDTO, PatchDTO, RequiredSome, Type } from 'ts-gems';
|
|
3
|
-
import { MongoAdapter } from '
|
|
3
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
4
4
|
import { MongoEntityService } from './mongo-entity-service.js';
|
|
5
5
|
/**
|
|
6
6
|
*
|
|
@@ -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
|
/**
|
|
@@ -168,12 +168,6 @@ export declare class MongoEntityService<T extends mongodb.Document> extends Mong
|
|
|
168
168
|
* @param {MongoEntityService.UpdateOneCommand<T>} command
|
|
169
169
|
*/
|
|
170
170
|
protected _update(command: MongoEntityService.UpdateOneCommand<T>): Promise<PartialDTO<T> | undefined>;
|
|
171
|
-
/**
|
|
172
|
-
* Replaces a document with the given id in the collection
|
|
173
|
-
*
|
|
174
|
-
* @param {MongoEntityService.ReplaceCommand<T>} command
|
|
175
|
-
*/
|
|
176
|
-
protected _replace(command: MongoEntityService.ReplaceCommand<T>): Promise<PartialDTO<T> | undefined>;
|
|
177
171
|
/**
|
|
178
172
|
* Updates a document in the collection with the specified ID.
|
|
179
173
|
*
|
|
@@ -186,6 +180,14 @@ export declare class MongoEntityService<T extends mongodb.Document> extends Mong
|
|
|
186
180
|
* @param {MongoEntityService.UpdateManyCommand<T>} command
|
|
187
181
|
*/
|
|
188
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>;
|
|
190
|
+
protected _generatePatch(command: MongoEntityService.UpdateOneCommand<T> | MongoEntityService.UpdateManyCommand<T>, doc: any): mongodb.UpdateFilter<T>;
|
|
189
191
|
protected _executeCommand(command: MongoEntityService.CommandInfo, commandFn: () => any): Promise<any>;
|
|
190
192
|
protected _beforeCreate(command: MongoEntityService.CreateCommand<T>): Promise<void>;
|
|
191
193
|
protected _beforeDelete(command: MongoEntityService.DeleteCommand<T>): Promise<void>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ComplexType } from '@opra/common';
|
|
2
2
|
import mongodb from 'mongodb';
|
|
3
3
|
import type { DTO, PartialDTO, PatchDTO, RequiredSome, StrictOmit, Type } from 'ts-gems';
|
|
4
|
-
import { MongoAdapter } from '
|
|
5
|
-
import type { MongoEntityService } from './mongo-entity-service';
|
|
4
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
5
|
+
import type { MongoEntityService } from './mongo-entity-service.js';
|
|
6
6
|
import { MongoService } from './mongo-service.js';
|
|
7
7
|
/**
|
|
8
8
|
*
|
|
@@ -3,7 +3,7 @@ import { ExecutionContext, ServiceBase } from '@opra/core';
|
|
|
3
3
|
import mongodb, { ClientSession, type Document, type TransactionOptions } from 'mongodb';
|
|
4
4
|
import type { Nullish, StrictOmit, Type } from 'ts-gems';
|
|
5
5
|
import type { IsObject } from 'valgen';
|
|
6
|
-
import { MongoAdapter } from '
|
|
6
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
7
7
|
/**
|
|
8
8
|
* The namespace for the MongoService.
|
|
9
9
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import mongodb, { type UpdateFilter } from 'mongodb';
|
|
2
2
|
import type { PartialDTO, PatchDTO, RequiredSome, Type } from 'ts-gems';
|
|
3
|
-
import { MongoAdapter } from '
|
|
3
|
+
import { MongoAdapter } from '../adapter/mongo-adapter.js';
|
|
4
4
|
import { MongoEntityService } from './mongo-entity-service.js';
|
|
5
5
|
/**
|
|
6
6
|
*
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = preparePatch;
|
|
4
|
-
const objects_1 = require("@jsopen/objects");
|
|
5
|
-
function preparePatch(doc, options) {
|
|
6
|
-
const trg = {};
|
|
7
|
-
_preparePatch(doc, trg, '', options);
|
|
8
|
-
trg.$set = trg.$set || {};
|
|
9
|
-
return trg;
|
|
10
|
-
}
|
|
11
|
-
function _preparePatch(src, trg, path, options) {
|
|
12
|
-
let f;
|
|
13
|
-
let key;
|
|
14
|
-
let field;
|
|
15
|
-
trg = trg || {};
|
|
16
|
-
const fieldPrefix = options?.fieldPrefix;
|
|
17
|
-
for (const [k, v] of Object.entries(src)) {
|
|
18
|
-
f = k.startsWith('*') ? k.substring(1) : k;
|
|
19
|
-
key = path ? path + '.' + f : f;
|
|
20
|
-
field = (fieldPrefix ? fieldPrefix : '') + key;
|
|
21
|
-
if (v == null) {
|
|
22
|
-
trg.$unset = trg.$unset || {};
|
|
23
|
-
trg.$unset[field] = '';
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (v && typeof v === 'object' && !(0, objects_1.isBuiltIn)(v)) {
|
|
27
|
-
// If field name starts with "*", do "replace" operation except "merge"
|
|
28
|
-
if (!k.startsWith('*')) {
|
|
29
|
-
_preparePatch(v, trg, key);
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
trg.$set = trg.$set || {};
|
|
34
|
-
trg.$set[field] = v;
|
|
35
|
-
}
|
|
36
|
-
return trg;
|
|
37
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { isBuiltIn } from '@jsopen/objects';
|
|
2
|
-
export default function preparePatch(doc, options) {
|
|
3
|
-
const trg = {};
|
|
4
|
-
_preparePatch(doc, trg, '', options);
|
|
5
|
-
trg.$set = trg.$set || {};
|
|
6
|
-
return trg;
|
|
7
|
-
}
|
|
8
|
-
function _preparePatch(src, trg, path, options) {
|
|
9
|
-
let f;
|
|
10
|
-
let key;
|
|
11
|
-
let field;
|
|
12
|
-
trg = trg || {};
|
|
13
|
-
const fieldPrefix = options?.fieldPrefix;
|
|
14
|
-
for (const [k, v] of Object.entries(src)) {
|
|
15
|
-
f = k.startsWith('*') ? k.substring(1) : k;
|
|
16
|
-
key = path ? path + '.' + f : f;
|
|
17
|
-
field = (fieldPrefix ? fieldPrefix : '') + key;
|
|
18
|
-
if (v == null) {
|
|
19
|
-
trg.$unset = trg.$unset || {};
|
|
20
|
-
trg.$unset[field] = '';
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
if (v && typeof v === 'object' && !isBuiltIn(v)) {
|
|
24
|
-
// If field name starts with "*", do "replace" operation except "merge"
|
|
25
|
-
if (!k.startsWith('*')) {
|
|
26
|
-
_preparePatch(v, trg, key);
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
trg.$set = trg.$set || {};
|
|
31
|
-
trg.$set[field] = v;
|
|
32
|
-
}
|
|
33
|
-
return trg;
|
|
34
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|