@opra/mongodb 1.30.0 → 1.31.1
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/README.md
CHANGED
|
@@ -74,5 +74,5 @@ Available under [MIT](LICENSE) license.
|
|
|
74
74
|
[downloads-url]: https://npmjs.org/package/@opra/mongodb
|
|
75
75
|
[ci-test-image]: https://github.com/panates/opra/actions/workflows/test.yml/badge.svg
|
|
76
76
|
[ci-test-url]: https://github.com/panates/opra/actions/workflows/test.yml
|
|
77
|
-
[coveralls-image]: https://coveralls.io/repos/github/panates/opra/badge.svg?branch=
|
|
77
|
+
[coveralls-image]: https://coveralls.io/repos/github/panates/opra/badge.svg?branch=dev
|
|
78
78
|
[coveralls-url]: https://coveralls.io/github/panates/opra?branch=main
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { ApiField, ComplexType } from '@opra/common';
|
|
1
|
+
import { ApiField, ArrayType, ComplexType } from '@opra/common';
|
|
2
2
|
const FIELD_NAME_PATTERN = /^([-><*:])?(.+)$/;
|
|
3
|
+
/** An array field (`isArray: true`) is declared as `ArrayType(Note)`, not
|
|
4
|
+
* `Note` directly — its own `.type` is the array wrapper. Every "is this
|
|
5
|
+
* an array-of-nested-entity field" check below needs the item type, not
|
|
6
|
+
* the wrapper, however many `[]` layers deep it goes. */
|
|
7
|
+
function unwrapArrayType(type) {
|
|
8
|
+
while (type instanceof ArrayType)
|
|
9
|
+
type = type.type;
|
|
10
|
+
return type;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* MongoPatchGenerator is responsible for generating MongoDB update patches from DTO objects.
|
|
5
14
|
* It handles nested objects, array operations ($push, $pull), and field unsetting.
|
|
@@ -92,7 +101,8 @@ export class MongoPatchGenerator {
|
|
|
92
101
|
result = true;
|
|
93
102
|
continue;
|
|
94
103
|
}
|
|
95
|
-
|
|
104
|
+
const itemType = unwrapArrayType(field.type);
|
|
105
|
+
if (itemType instanceof ComplexType) {
|
|
96
106
|
if (!value)
|
|
97
107
|
continue;
|
|
98
108
|
if (field.isArray) {
|
|
@@ -101,7 +111,7 @@ export class MongoPatchGenerator {
|
|
|
101
111
|
ctx.initArrayFields.push(pathDot + field.name);
|
|
102
112
|
if (!value.length)
|
|
103
113
|
continue;
|
|
104
|
-
keyField = field.keyField ||
|
|
114
|
+
keyField = field.keyField || itemType.keyField;
|
|
105
115
|
if (keyField) {
|
|
106
116
|
for (let v of value) {
|
|
107
117
|
/* Increase arrayIndex and determine a new name for array filter */
|
|
@@ -114,7 +124,7 @@ export class MongoPatchGenerator {
|
|
|
114
124
|
/* Remove key field from object */
|
|
115
125
|
delete v[keyField];
|
|
116
126
|
/* Process each object in array */
|
|
117
|
-
if (this._processComplexType(ctx,
|
|
127
|
+
if (this._processComplexType(ctx, itemType, pathDot + field.name + `.$[${arrayFilterName}]`, v, scope)) {
|
|
118
128
|
result = true;
|
|
119
129
|
/* Add array filter */
|
|
120
130
|
ctx.arrayFilters = ctx.arrayFilters || [];
|
|
@@ -131,7 +141,7 @@ export class MongoPatchGenerator {
|
|
|
131
141
|
if (!(typeof value === 'object'))
|
|
132
142
|
continue;
|
|
133
143
|
/* Process nested object */
|
|
134
|
-
if (this._processComplexType(ctx,
|
|
144
|
+
if (this._processComplexType(ctx, itemType, pathDot + field.name, value, scope)) {
|
|
135
145
|
result = true;
|
|
136
146
|
}
|
|
137
147
|
continue;
|
|
@@ -157,13 +167,14 @@ export class MongoPatchGenerator {
|
|
|
157
167
|
if (!(field && field.isArray))
|
|
158
168
|
continue;
|
|
159
169
|
ctx.$push = ctx.$push || {};
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
const itemType = unwrapArrayType(field.type);
|
|
171
|
+
if (itemType instanceof ComplexType) {
|
|
172
|
+
keyField = field.keyField || itemType.keyField;
|
|
162
173
|
if (keyField) {
|
|
163
174
|
if (Array.isArray(value)) {
|
|
164
175
|
value.forEach(v => {
|
|
165
176
|
if (!v[keyField]) {
|
|
166
|
-
throw new TypeError(`You must provide a key value of ${
|
|
177
|
+
throw new TypeError(`You must provide a key value of ${itemType.name} for $push operation.`);
|
|
167
178
|
}
|
|
168
179
|
});
|
|
169
180
|
ctx.$push[pathDot + key] = { $each: value };
|
|
@@ -171,7 +182,7 @@ export class MongoPatchGenerator {
|
|
|
171
182
|
}
|
|
172
183
|
else {
|
|
173
184
|
if (!value[keyField]) {
|
|
174
|
-
throw new TypeError(`You must provide a key value of ${
|
|
185
|
+
throw new TypeError(`You must provide a key value of ${itemType.name} for $push operation.`);
|
|
175
186
|
}
|
|
176
187
|
ctx.$push[pathDot + key] = value;
|
|
177
188
|
result = true;
|
|
@@ -200,8 +211,9 @@ export class MongoPatchGenerator {
|
|
|
200
211
|
if (!(field && field.isArray))
|
|
201
212
|
continue;
|
|
202
213
|
ctx.$pull = ctx.$pull || {};
|
|
203
|
-
|
|
204
|
-
|
|
214
|
+
const itemType = unwrapArrayType(field.type);
|
|
215
|
+
if (itemType instanceof ComplexType) {
|
|
216
|
+
keyField = field.keyField || itemType.keyField;
|
|
205
217
|
if (!keyField)
|
|
206
218
|
continue;
|
|
207
219
|
ctx.$pull[pathDot + key] = {
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { ApiField, ComplexType, FieldsProjection, parseFieldsProjection, } from '@opra/common';
|
|
1
|
+
import { ApiField, ArrayType, ComplexType, FieldsProjection, parseFieldsProjection, } from '@opra/common';
|
|
2
2
|
import mongodb, {} from 'mongodb';
|
|
3
|
+
/** An array field (`isArray: true`) is declared as `ArrayType(Note)`, not
|
|
4
|
+
* `Note` directly — its own `.type` is the array wrapper, not the item
|
|
5
|
+
* type a nested projection needs to recurse into. */
|
|
6
|
+
function unwrapArrayType(type) {
|
|
7
|
+
while (type instanceof ArrayType)
|
|
8
|
+
type = type.type;
|
|
9
|
+
return type;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* Prepares the MongoDB projection object based on the data type and requested projection.
|
|
5
13
|
*
|
|
@@ -44,10 +52,10 @@ export function prepare(dataType, target, projection, scope) {
|
|
|
44
52
|
(defaultFields && field.exclusive && !p)) {
|
|
45
53
|
continue;
|
|
46
54
|
}
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
const itemType = unwrapArrayType(field.type);
|
|
56
|
+
if (itemType instanceof ComplexType && typeof p?.projection === 'object') {
|
|
49
57
|
target[fieldName] = {};
|
|
50
|
-
prepare(
|
|
58
|
+
prepare(itemType, target[fieldName], p.projection);
|
|
51
59
|
continue;
|
|
52
60
|
}
|
|
53
61
|
target[fieldName] = 1;
|
package/package.json
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/mongodb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.1",
|
|
4
4
|
"description": "Opra MongoDB adapter package",
|
|
5
5
|
"author": "Panates",
|
|
6
|
+
"contributors": [
|
|
7
|
+
"Eray Hanoglu <e.hanoglu@panates.com>",
|
|
8
|
+
"Ilker Gurelli <i.gurelli@panates.com>",
|
|
9
|
+
"Onur Tokel <o.tokel@panates.com>",
|
|
10
|
+
"Bircan Yuruk <b.yuruk@panates.com>"
|
|
11
|
+
],
|
|
6
12
|
"license": "MIT",
|
|
7
13
|
"homepage": "https://www.oprajs.com",
|
|
8
14
|
"dependencies": {
|
|
9
|
-
"@jsopen/objects": "^2.3.
|
|
15
|
+
"@jsopen/objects": "^2.3.4",
|
|
10
16
|
"tslib": "^2.8.1",
|
|
11
|
-
"valgen": "^7.0.
|
|
17
|
+
"valgen": "^7.0.3"
|
|
12
18
|
},
|
|
13
19
|
"peerDependencies": {
|
|
14
|
-
"@opra/common": "^1.
|
|
15
|
-
"@opra/core": "^1.
|
|
16
|
-
"@opra/http": "^1.
|
|
20
|
+
"@opra/common": "^1.31.1",
|
|
21
|
+
"@opra/core": "^1.31.1",
|
|
22
|
+
"@opra/http": "^1.31.1",
|
|
17
23
|
"mongodb": "^7.0.0"
|
|
18
24
|
},
|
|
19
25
|
"exports": {
|
|
@@ -42,4 +48,4 @@
|
|
|
42
48
|
"publishConfig": {
|
|
43
49
|
"access": "public"
|
|
44
50
|
}
|
|
45
|
-
}
|
|
51
|
+
}
|
|
@@ -156,7 +156,11 @@ export declare class MongoNestedService<T extends mongodb.Document> extends Mong
|
|
|
156
156
|
/**
|
|
157
157
|
* Constructs a new instance
|
|
158
158
|
*
|
|
159
|
-
* @param dataType - The data type of the array
|
|
159
|
+
* @param dataType - The data type of the *document* that owns the array
|
|
160
|
+
* field — not the element type. This service reads `fieldName` off it to
|
|
161
|
+
* determine the element type itself (see the `dataType` getter), so
|
|
162
|
+
* passing the element type here leaves it looking for the field on the
|
|
163
|
+
* wrong type and failing with "Field (...) does not exist".
|
|
160
164
|
* @param fieldName - The name of the field in the document representing the array.
|
|
161
165
|
* @param [options] - The options for the array service.
|
|
162
166
|
* @constructor
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { omit } from '@jsopen/objects';
|
|
2
|
-
import { ComplexType, NotAcceptableError, ResourceNotAvailableError, } from '@opra/common';
|
|
2
|
+
import { ArrayType, ComplexType, NotAcceptableError, ResourceNotAvailableError, } from '@opra/common';
|
|
3
3
|
import { ExecutionContext, ServiceBase } from '@opra/core';
|
|
4
4
|
import mongodb from 'mongodb';
|
|
5
5
|
import { isNotNullish } from 'valgen';
|
|
@@ -31,7 +31,11 @@ export class MongoNestedService extends MongoService {
|
|
|
31
31
|
/**
|
|
32
32
|
* Constructs a new instance
|
|
33
33
|
*
|
|
34
|
-
* @param dataType - The data type of the array
|
|
34
|
+
* @param dataType - The data type of the *document* that owns the array
|
|
35
|
+
* field — not the element type. This service reads `fieldName` off it to
|
|
36
|
+
* determine the element type itself (see the `dataType` getter), so
|
|
37
|
+
* passing the element type here leaves it looking for the field on the
|
|
38
|
+
* wrong type and failing with "Field (...) does not exist".
|
|
35
39
|
* @param fieldName - The name of the field in the document representing the array.
|
|
36
40
|
* @param [options] - The options for the array service.
|
|
37
41
|
* @constructor
|
|
@@ -50,7 +54,13 @@ export class MongoNestedService extends MongoService {
|
|
|
50
54
|
* @throws {@link NotAcceptableError} If the data type is not a ComplexType.
|
|
51
55
|
*/
|
|
52
56
|
get dataType() {
|
|
53
|
-
|
|
57
|
+
// The field is declared as `ArrayType(Note)` (e.g. `notes: Note[]`) —
|
|
58
|
+
// its own `.type` is the array wrapper, not the item type directly;
|
|
59
|
+
// unwrap it (however many `[]` layers deep) before checking, same as
|
|
60
|
+
// the client-side schema viewer already does for display.
|
|
61
|
+
let t = super.dataType.getField(this.fieldName, this.scope).type;
|
|
62
|
+
while (t instanceof ArrayType)
|
|
63
|
+
t = t.type;
|
|
54
64
|
if (!(t instanceof ComplexType))
|
|
55
65
|
throw new NotAcceptableError(`Data type "${t.name}" is not a ComplexType`);
|
|
56
66
|
return t;
|