@opra/common 0.22.0 → 0.23.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/browser.js +957 -1566
- package/cjs/document/api-document.js +7 -3
- package/cjs/document/data-type/api-field.js +2 -2
- package/cjs/document/data-type/complex-type.js +17 -63
- package/cjs/document/data-type/data-type.js +0 -9
- package/cjs/document/data-type/enum-type.js +2 -8
- package/cjs/document/data-type/mapped-type.js +0 -36
- package/cjs/document/data-type/simple-type.js +2 -8
- package/cjs/document/data-type/union-type.js +1 -37
- package/cjs/document/index.js +2 -0
- package/cjs/document/resource/collection.js +75 -32
- package/cjs/document/resource/singleton.js +31 -20
- package/cjs/document/resource/storage.js +6 -20
- package/cjs/document/utils/generate-codec.js +39 -0
- package/cjs/exception/http-errors/bad-request.error.js +2 -3
- package/cjs/exception/http-errors/failed-dependency.error.js +2 -3
- package/cjs/exception/http-errors/forbidden.error.js +2 -3
- package/cjs/exception/http-errors/internal-server.error.js +2 -3
- package/cjs/exception/http-errors/method-not-allowed.error.js +2 -3
- package/cjs/exception/http-errors/not-acceptable.error.js +2 -3
- package/cjs/exception/http-errors/not-found.error.js +2 -3
- package/cjs/exception/http-errors/unauthorized.error.js +2 -3
- package/cjs/exception/http-errors/unprocessable-entity.error.js +2 -2
- package/cjs/exception/opra-exception.js +48 -33
- package/cjs/exception/resource-errors/resource-not-found.error.js +2 -3
- package/cjs/exception/wrap-exception.js +16 -16
- package/cjs/helpers/index.js +1 -1
- package/cjs/helpers/is-url-string.js +14 -0
- package/cjs/helpers/object-utils.js +2 -2
- package/cjs/helpers/responsive-map.js +4 -4
- package/cjs/helpers/type-guards.js +15 -3
- package/cjs/http/index.js +2 -9
- package/cjs/http/opra-url-path.js +251 -0
- package/cjs/{url → http}/opra-url.js +53 -109
- package/cjs/i18n/i18n.js +1 -1
- package/cjs/index.js +0 -2
- package/cjs/schema/opra-schema.ns.js +1 -1
- package/cjs/schema/resource/operation.interface.js +2 -0
- package/esm/document/api-document.js +9 -5
- package/esm/document/data-type/api-field.js +2 -2
- package/esm/document/data-type/complex-type.js +13 -59
- package/esm/document/data-type/data-type.js +0 -9
- package/esm/document/data-type/enum-type.js +2 -8
- package/esm/document/data-type/mapped-type.js +0 -36
- package/esm/document/data-type/simple-type.js +2 -8
- package/esm/document/data-type/union-type.js +1 -37
- package/esm/document/index.js +2 -0
- package/esm/document/resource/collection.js +75 -32
- package/esm/document/resource/singleton.js +31 -20
- package/esm/document/resource/storage.js +6 -20
- package/esm/document/utils/generate-codec.js +33 -0
- package/esm/exception/http-errors/bad-request.error.js +2 -3
- package/esm/exception/http-errors/failed-dependency.error.js +2 -3
- package/esm/exception/http-errors/forbidden.error.js +2 -3
- package/esm/exception/http-errors/internal-server.error.js +2 -3
- package/esm/exception/http-errors/method-not-allowed.error.js +2 -3
- package/esm/exception/http-errors/not-acceptable.error.js +2 -3
- package/esm/exception/http-errors/not-found.error.js +2 -3
- package/esm/exception/http-errors/unauthorized.error.js +2 -3
- package/esm/exception/http-errors/unprocessable-entity.error.js +2 -2
- package/esm/exception/opra-exception.js +47 -32
- package/esm/exception/resource-errors/resource-not-found.error.js +2 -3
- package/esm/exception/wrap-exception.js +16 -16
- package/esm/helpers/index.js +1 -1
- package/esm/helpers/is-url-string.js +9 -0
- package/esm/helpers/object-utils.js +2 -2
- package/esm/helpers/responsive-map.js +4 -4
- package/esm/helpers/type-guards.js +11 -2
- package/esm/http/index.js +2 -9
- package/esm/http/opra-url-path.js +246 -0
- package/esm/{url → http}/opra-url.js +53 -109
- package/esm/i18n/i18n.js +2 -2
- package/esm/index.js +0 -2
- package/esm/schema/opra-schema.ns.js +1 -1
- package/esm/schema/resource/operation.interface.js +1 -0
- package/package.json +5 -5
- package/types/document/api-document.d.ts +4 -1
- package/types/document/data-type/complex-type.d.ts +7 -12
- package/types/document/data-type/data-type.d.ts +0 -6
- package/types/document/data-type/enum-type.d.ts +2 -4
- package/types/document/data-type/mapped-type.d.ts +1 -5
- package/types/document/data-type/simple-type.d.ts +2 -4
- package/types/document/data-type/union-type.d.ts +1 -5
- package/types/document/index.d.ts +2 -0
- package/types/document/interfaces/collection-resource.interface.d.ts +10 -0
- package/types/document/interfaces/singleton-resource.interface.d.ts +7 -0
- package/types/document/interfaces/storage-resource.interface.d.ts +8 -0
- package/types/document/resource/collection.d.ts +41 -35
- package/types/document/resource/resource.d.ts +1 -0
- package/types/document/resource/singleton.d.ts +24 -21
- package/types/document/resource/storage.d.ts +14 -17
- package/types/document/utils/generate-codec.d.ts +10 -0
- package/types/exception/error-issue.d.ts +2 -1
- package/types/exception/http-errors/bad-request.error.d.ts +2 -1
- package/types/exception/http-errors/failed-dependency.error.d.ts +2 -1
- package/types/exception/http-errors/forbidden.error.d.ts +2 -1
- package/types/exception/http-errors/internal-server.error.d.ts +2 -1
- package/types/exception/http-errors/method-not-allowed.error.d.ts +2 -1
- package/types/exception/http-errors/not-acceptable.error.d.ts +2 -1
- package/types/exception/http-errors/not-found.error.d.ts +2 -1
- package/types/exception/http-errors/unauthorized.error.d.ts +2 -1
- package/types/exception/http-errors/unprocessable-entity.error.d.ts +2 -1
- package/types/exception/opra-exception.d.ts +13 -8
- package/types/exception/wrap-exception.d.ts +1 -1
- package/types/helpers/index.d.ts +1 -1
- package/types/helpers/is-url-string.d.ts +2 -0
- package/types/helpers/object-utils.d.ts +1 -1
- package/types/helpers/type-guards.d.ts +3 -0
- package/types/http/index.d.ts +2 -9
- package/types/http/opra-url-path.d.ts +54 -0
- package/types/{url → http}/opra-url.d.ts +9 -13
- package/types/index.d.ts +0 -2
- package/types/schema/data-type/complex-type.interface.d.ts +1 -1
- package/types/schema/opra-schema.ns.d.ts +1 -1
- package/types/schema/resource/collection.interface.d.ts +29 -8
- package/types/schema/resource/operation.interface.d.ts +3 -0
- package/types/schema/resource/singleton.interface.d.ts +5 -5
- package/types/schema/resource/storage.interface.d.ts +42 -5
- package/cjs/helpers/is-url.js +0 -8
- package/cjs/http/codecs/boolean-codec.js +0 -24
- package/cjs/http/codecs/date-codec.js +0 -41
- package/cjs/http/codecs/filter-codec.js +0 -17
- package/cjs/http/codecs/integer-codec.js +0 -19
- package/cjs/http/codecs/number-codec.js +0 -24
- package/cjs/http/codecs/string-codec.js +0 -23
- package/cjs/http/http-params.js +0 -353
- package/cjs/http/multipart/batch-multipart.js +0 -170
- package/cjs/http/multipart/http-request-content.js +0 -17
- package/cjs/http/multipart/http-response-content.js +0 -14
- package/cjs/http/multipart/index.js +0 -2
- package/cjs/url/index.js +0 -8
- package/cjs/url/opra-url-path-component.js +0 -30
- package/cjs/url/opra-url-path.js +0 -155
- package/cjs/url/utils/decode-path-component.js +0 -41
- package/cjs/url/utils/encode-path-component.js +0 -27
- package/cjs/utils/path-utils.js +0 -24
- package/esm/helpers/is-url.js +0 -4
- package/esm/http/codecs/boolean-codec.js +0 -20
- package/esm/http/codecs/date-codec.js +0 -37
- package/esm/http/codecs/filter-codec.js +0 -13
- package/esm/http/codecs/integer-codec.js +0 -15
- package/esm/http/codecs/number-codec.js +0 -20
- package/esm/http/codecs/string-codec.js +0 -19
- package/esm/http/http-params.js +0 -348
- package/esm/http/multipart/batch-multipart.js +0 -170
- package/esm/http/multipart/http-request-content.js +0 -17
- package/esm/http/multipart/http-response-content.js +0 -14
- package/esm/http/multipart/index.js +0 -2
- package/esm/url/index.js +0 -5
- package/esm/url/opra-url-path-component.js +0 -26
- package/esm/url/opra-url-path.js +0 -151
- package/esm/url/utils/decode-path-component.js +0 -37
- package/esm/url/utils/encode-path-component.js +0 -22
- package/esm/utils/path-utils.js +0 -19
- package/types/helpers/is-url.d.ts +0 -1
- package/types/http/codecs/boolean-codec.d.ts +0 -5
- package/types/http/codecs/date-codec.d.ts +0 -16
- package/types/http/codecs/filter-codec.d.ts +0 -6
- package/types/http/codecs/integer-codec.d.ts +0 -11
- package/types/http/codecs/number-codec.d.ts +0 -14
- package/types/http/codecs/string-codec.d.ts +0 -16
- package/types/http/http-params.d.ts +0 -114
- package/types/http/interfaces/client-http-headers.interface.d.ts +0 -65
- package/types/http/interfaces/server-http-headers.interface.d.ts +0 -1
- package/types/http/multipart/batch-multipart.d.ts +0 -0
- package/types/http/multipart/http-request-content.d.ts +0 -0
- package/types/http/multipart/http-response-content.d.ts +0 -0
- package/types/http/multipart/index.d.ts +0 -0
- package/types/schema/resource/endpoint.interface.d.ts +0 -29
- package/types/url/index.d.ts +0 -5
- package/types/url/opra-url-path-component.d.ts +0 -15
- package/types/url/opra-url-path.d.ts +0 -36
- package/types/url/utils/decode-path-component.d.ts +0 -5
- package/types/url/utils/encode-path-component.d.ts +0 -1
- package/types/utils/path-utils.d.ts +0 -2
- /package/cjs/{http/interfaces/client-http-headers.interface.js → document/interfaces/collection-resource.interface.js} +0 -0
- /package/cjs/{http/interfaces/server-http-headers.interface.js → document/interfaces/singleton-resource.interface.js} +0 -0
- /package/cjs/{schema/resource/endpoint.interface.js → document/interfaces/storage-resource.interface.js} +0 -0
- /package/esm/{http/interfaces/client-http-headers.interface.js → document/interfaces/collection-resource.interface.js} +0 -0
- /package/esm/{http/interfaces/server-http-headers.interface.js → document/interfaces/singleton-resource.interface.js} +0 -0
- /package/esm/{schema/resource/endpoint.interface.js → document/interfaces/storage-resource.interface.js} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import omit from 'lodash.omit';
|
|
3
3
|
import merge from 'putil-merge';
|
|
4
|
-
import * as vg from 'valgen';
|
|
5
4
|
import { omitUndefined, ResponsiveMap } from '../../helpers/index.js';
|
|
5
|
+
import { translate } from '../../i18n/index.js';
|
|
6
6
|
import { OpraSchema } from '../../schema/index.js';
|
|
7
7
|
import { METADATA_KEY, TYPENAME_PATTERN } from '../constants.js';
|
|
8
8
|
import { ApiField } from './api-field.js';
|
|
@@ -15,7 +15,7 @@ class ComplexTypeClass extends DataType {
|
|
|
15
15
|
super(document, init);
|
|
16
16
|
this.kind = OpraSchema.ComplexType.Kind;
|
|
17
17
|
const own = this.own = {};
|
|
18
|
-
own.ctor = init?.ctor;
|
|
18
|
+
own.ctor = init?.ctor || init?.base?.ctor;
|
|
19
19
|
own.abstract = init?.abstract;
|
|
20
20
|
own.additionalFields = init?.additionalFields;
|
|
21
21
|
own.fields = new ResponsiveMap();
|
|
@@ -28,8 +28,6 @@ class ComplexTypeClass extends DataType {
|
|
|
28
28
|
if (this.base) {
|
|
29
29
|
if (this.additionalFields == null)
|
|
30
30
|
this.additionalFields = this.base.additionalFields;
|
|
31
|
-
if (own.ctor == null && this.base instanceof ComplexType)
|
|
32
|
-
this.ctor = this.base.ctor;
|
|
33
31
|
if (this.base.fields)
|
|
34
32
|
for (const [k, el] of this.base.fields.entries()) {
|
|
35
33
|
const newEl = new ApiField(this, el);
|
|
@@ -65,7 +63,7 @@ class ComplexTypeClass extends DataType {
|
|
|
65
63
|
else
|
|
66
64
|
field = this.fields.get(nameOrPath);
|
|
67
65
|
if (!field)
|
|
68
|
-
throw new Error(
|
|
66
|
+
throw new Error(translate('error:UNKNOWN_FIELD', { field: nameOrPath }));
|
|
69
67
|
return field;
|
|
70
68
|
}
|
|
71
69
|
iteratePath(path, silent) {
|
|
@@ -99,7 +97,7 @@ class ComplexTypeClass extends DataType {
|
|
|
99
97
|
if (dataType && !dataType.additionalFields) {
|
|
100
98
|
if (silent)
|
|
101
99
|
return { done: true, value: [] };
|
|
102
|
-
throw new Error(
|
|
100
|
+
throw new Error(translate('error:UNKNOWN_FIELD', { field: curPath }));
|
|
103
101
|
}
|
|
104
102
|
}
|
|
105
103
|
}
|
|
@@ -111,13 +109,15 @@ class ComplexTypeClass extends DataType {
|
|
|
111
109
|
};
|
|
112
110
|
}
|
|
113
111
|
normalizeFieldPath(fieldPaths) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
112
|
+
const array = (Array.isArray(fieldPaths) ? fieldPaths : [fieldPaths])
|
|
113
|
+
.map(s => {
|
|
114
|
+
let curPath = '';
|
|
115
|
+
for (const [, , p] of this.iteratePath(s)) {
|
|
116
|
+
curPath = p;
|
|
117
|
+
}
|
|
118
|
+
return curPath;
|
|
119
|
+
}).flat();
|
|
120
|
+
return array.length ? array : undefined;
|
|
121
121
|
}
|
|
122
122
|
exportSchema() {
|
|
123
123
|
const out = super.exportSchema();
|
|
@@ -147,52 +147,6 @@ class ComplexTypeClass extends DataType {
|
|
|
147
147
|
}
|
|
148
148
|
return false;
|
|
149
149
|
}
|
|
150
|
-
decode(v) {
|
|
151
|
-
return this._getDecoder()(v, { coerce: true });
|
|
152
|
-
}
|
|
153
|
-
encode(v) {
|
|
154
|
-
return this._getEncoder()(v, { coerce: true });
|
|
155
|
-
}
|
|
156
|
-
validate(v) {
|
|
157
|
-
return this._getEncoder()(v);
|
|
158
|
-
}
|
|
159
|
-
_getDecoder() {
|
|
160
|
-
if (this._decoder)
|
|
161
|
-
return this._decoder;
|
|
162
|
-
const schema = {};
|
|
163
|
-
for (const f of this.fields.values()) {
|
|
164
|
-
let t = f.type._getDecoder();
|
|
165
|
-
if (f.isArray)
|
|
166
|
-
t = vg.isArray(t);
|
|
167
|
-
schema[f.name] = f.required ? vg.required(t) : vg.optional(t);
|
|
168
|
-
}
|
|
169
|
-
this._decoder = vg.isObject(schema, {
|
|
170
|
-
ctor: this.ctor,
|
|
171
|
-
additionalFields: this.additionalFields ?? 'ignore',
|
|
172
|
-
name: this.name,
|
|
173
|
-
caseInSensitive: true,
|
|
174
|
-
});
|
|
175
|
-
return this._decoder;
|
|
176
|
-
}
|
|
177
|
-
_getEncoder() {
|
|
178
|
-
if (this._encoder)
|
|
179
|
-
return this._encoder;
|
|
180
|
-
const schema = {};
|
|
181
|
-
for (const f of this.fields.values()) {
|
|
182
|
-
let t = f.type._getEncoder();
|
|
183
|
-
if (f.isArray)
|
|
184
|
-
t = vg.isArray(t);
|
|
185
|
-
schema[f.name] = t;
|
|
186
|
-
}
|
|
187
|
-
this._encoder = vg.isObject(schema, {
|
|
188
|
-
ctor: this.ctor,
|
|
189
|
-
additionalFields: this.additionalFields,
|
|
190
|
-
name: this.name,
|
|
191
|
-
caseInSensitive: true,
|
|
192
|
-
detectCircular: true
|
|
193
|
-
});
|
|
194
|
-
return this._encoder;
|
|
195
|
-
}
|
|
196
150
|
}
|
|
197
151
|
/**
|
|
198
152
|
* @class ComplexType
|
|
@@ -8,15 +8,6 @@ export class DataType {
|
|
|
8
8
|
this.description = init?.description;
|
|
9
9
|
this.isAnonymous = !this.name;
|
|
10
10
|
}
|
|
11
|
-
decode(v) {
|
|
12
|
-
return this._getDecoder()(v, { coerce: true });
|
|
13
|
-
}
|
|
14
|
-
encode(v) {
|
|
15
|
-
return this._getEncoder()(v, { coerce: true });
|
|
16
|
-
}
|
|
17
|
-
validate(v) {
|
|
18
|
-
return this._getEncoder()(v);
|
|
19
|
-
}
|
|
20
11
|
exportSchema() {
|
|
21
12
|
return omitUndefined({
|
|
22
13
|
kind: this.kind,
|
|
@@ -15,6 +15,8 @@ class EnumTypeClass extends DataType {
|
|
|
15
15
|
this.ownMeanings = init.meanings || {};
|
|
16
16
|
this.values = { ...this.base?.values, ...this.ownValues };
|
|
17
17
|
this.meanings = { ...this.base?.meanings, ...this.ownMeanings };
|
|
18
|
+
this.decode = vg.isEnum(Object.values(this.values));
|
|
19
|
+
this.encode = vg.isEnum(Object.values(this.values));
|
|
18
20
|
}
|
|
19
21
|
exportSchema() {
|
|
20
22
|
const out = DataType.prototype.exportSchema.call(this);
|
|
@@ -26,14 +28,6 @@ class EnumTypeClass extends DataType {
|
|
|
26
28
|
}));
|
|
27
29
|
return out;
|
|
28
30
|
}
|
|
29
|
-
_getDecoder() {
|
|
30
|
-
if (!this._decoder)
|
|
31
|
-
this._decoder = vg.isEnum(Object.values(this.values), { enumName: this.name });
|
|
32
|
-
return this._decoder;
|
|
33
|
-
}
|
|
34
|
-
_getEncoder() {
|
|
35
|
-
return this._getDecoder();
|
|
36
|
-
}
|
|
37
31
|
}
|
|
38
32
|
/**
|
|
39
33
|
* @class EnumType
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import merge from 'putil-merge';
|
|
3
|
-
import * as vg from 'valgen';
|
|
4
3
|
import { inheritPropertyInitializers, mergePrototype, omitUndefined, ResponsiveMap } from '../../helpers/index.js';
|
|
5
4
|
import { OpraSchema } from '../../schema/index.js';
|
|
6
5
|
import { METADATA_KEY } from '../constants.js';
|
|
@@ -33,41 +32,6 @@ class MappedTypeClass extends DataType {
|
|
|
33
32
|
}));
|
|
34
33
|
return out;
|
|
35
34
|
}
|
|
36
|
-
_getDecoder() {
|
|
37
|
-
if (this._decoder)
|
|
38
|
-
return this._decoder;
|
|
39
|
-
const schema = {};
|
|
40
|
-
for (const f of this.fields.values()) {
|
|
41
|
-
let t = f.type.getDecoder();
|
|
42
|
-
if (f.isArray)
|
|
43
|
-
t = vg.isArray(t);
|
|
44
|
-
schema[f.name] = t;
|
|
45
|
-
}
|
|
46
|
-
this._decoder = vg.isObject(schema, {
|
|
47
|
-
additionalFields: this.additionalFields,
|
|
48
|
-
name: this.name,
|
|
49
|
-
caseInSensitive: true
|
|
50
|
-
});
|
|
51
|
-
return this._decoder;
|
|
52
|
-
}
|
|
53
|
-
_getEncoder() {
|
|
54
|
-
if (this._encoder)
|
|
55
|
-
return this._encoder;
|
|
56
|
-
const schema = {};
|
|
57
|
-
for (const f of this.fields.values()) {
|
|
58
|
-
let t = f.type.getEncoder();
|
|
59
|
-
if (f.isArray)
|
|
60
|
-
t = vg.isArray(t);
|
|
61
|
-
schema[f.name] = t;
|
|
62
|
-
}
|
|
63
|
-
this._encoder = vg.isObject(schema, {
|
|
64
|
-
additionalFields: this.additionalFields,
|
|
65
|
-
name: this.name,
|
|
66
|
-
caseInSensitive: true,
|
|
67
|
-
detectCircular: true
|
|
68
|
-
});
|
|
69
|
-
return this._encoder;
|
|
70
|
-
}
|
|
71
35
|
}
|
|
72
36
|
/**
|
|
73
37
|
* @class MappedType
|
|
@@ -13,14 +13,8 @@ class SimpleTypeClass extends DataType {
|
|
|
13
13
|
super(document, init);
|
|
14
14
|
this.kind = OpraSchema.SimpleType.Kind;
|
|
15
15
|
this.base = init.base;
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
}
|
|
19
|
-
_getDecoder() {
|
|
20
|
-
return this._decoder;
|
|
21
|
-
}
|
|
22
|
-
_getEncoder() {
|
|
23
|
-
return this._encoder;
|
|
16
|
+
this.decode = init.decoder || init.base?.decode || vg.isAny();
|
|
17
|
+
this.encode = init.encoder || init.base?.encode || vg.isAny();
|
|
24
18
|
}
|
|
25
19
|
exportSchema() {
|
|
26
20
|
// noinspection UnnecessaryLocalVariableJS
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import merge from 'putil-merge';
|
|
3
|
-
import * as vg from 'valgen';
|
|
4
3
|
import { inheritPropertyInitializers, mergePrototype, omitUndefined, ResponsiveMap } from '../../helpers/index.js';
|
|
5
4
|
import { OpraSchema } from '../../schema/index.js';
|
|
6
5
|
import { METADATA_KEY } from '../constants.js';
|
|
@@ -20,7 +19,7 @@ class UnionTypeClass extends DataType {
|
|
|
20
19
|
`${OpraSchema.UnionType.Kind} of ${OpraSchema.MappedType.Kind} types.`);
|
|
21
20
|
own.types.push(base);
|
|
22
21
|
if (base.additionalFields)
|
|
23
|
-
this.additionalFields =
|
|
22
|
+
this.additionalFields = base.additionalFields;
|
|
24
23
|
this.fields.setAll(base.fields);
|
|
25
24
|
}
|
|
26
25
|
this.types = [...own.types];
|
|
@@ -32,41 +31,6 @@ class UnionTypeClass extends DataType {
|
|
|
32
31
|
}));
|
|
33
32
|
return out;
|
|
34
33
|
}
|
|
35
|
-
_getDecoder() {
|
|
36
|
-
if (this._decoder)
|
|
37
|
-
return this._decoder;
|
|
38
|
-
const schema = {};
|
|
39
|
-
for (const f of this.fields.values()) {
|
|
40
|
-
let t = f.type.getDecoder();
|
|
41
|
-
if (f.isArray)
|
|
42
|
-
t = vg.isArray(t);
|
|
43
|
-
schema[f.name] = t;
|
|
44
|
-
}
|
|
45
|
-
this._decoder = vg.isObject(schema, {
|
|
46
|
-
additionalFields: this.additionalFields,
|
|
47
|
-
name: this.name,
|
|
48
|
-
caseInSensitive: true
|
|
49
|
-
});
|
|
50
|
-
return this._decoder;
|
|
51
|
-
}
|
|
52
|
-
_getEncoder() {
|
|
53
|
-
if (this._encoder)
|
|
54
|
-
return this._encoder;
|
|
55
|
-
const schema = {};
|
|
56
|
-
for (const f of this.fields.values()) {
|
|
57
|
-
let t = f.type.getEncoder();
|
|
58
|
-
if (f.isArray)
|
|
59
|
-
t = vg.isArray(t);
|
|
60
|
-
schema[f.name] = t;
|
|
61
|
-
}
|
|
62
|
-
this._encoder = vg.isObject(schema, {
|
|
63
|
-
additionalFields: this.additionalFields,
|
|
64
|
-
name: this.name,
|
|
65
|
-
caseInSensitive: true,
|
|
66
|
-
detectCircular: true
|
|
67
|
-
});
|
|
68
|
-
return this._encoder;
|
|
69
|
-
}
|
|
70
34
|
}
|
|
71
35
|
/**
|
|
72
36
|
* @class UnionType
|
package/esm/document/index.js
CHANGED
|
@@ -13,3 +13,5 @@ export * from './resource/resource.js';
|
|
|
13
13
|
export * from './resource/collection.js';
|
|
14
14
|
export * from './resource/singleton.js';
|
|
15
15
|
export * from './resource/storage.js';
|
|
16
|
+
export * from './interfaces/collection-resource.interface.js';
|
|
17
|
+
export * from './interfaces/singleton-resource.interface.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import omit from 'lodash.omit';
|
|
2
2
|
import merge from 'putil-merge';
|
|
3
|
+
import * as vg from 'valgen';
|
|
3
4
|
import { BadRequestError } from '../../exception/index.js';
|
|
4
5
|
import { OpraFilter } from '../../filter/index.js';
|
|
5
6
|
import { omitUndefined } from '../../helpers/index.js';
|
|
@@ -7,15 +8,18 @@ import { translate } from '../../i18n/index.js';
|
|
|
7
8
|
import { OpraSchema } from '../../schema/index.js';
|
|
8
9
|
import { METADATA_KEY } from '../constants.js';
|
|
9
10
|
import { SimpleType } from '../data-type/simple-type.js';
|
|
11
|
+
import { generateCodec } from '../utils/generate-codec.js';
|
|
10
12
|
import { Resource } from './resource.js';
|
|
11
|
-
const NESTJS_INJECTABLE_WATERMARK = '__injectable__';
|
|
13
|
+
const NESTJS_INJECTABLE_WATERMARK = '__injectable__'; // todo, put this in nextjs package wia augmentation
|
|
12
14
|
const NAME_PATTERN = /^(.*)(Resource|Collection)$/;
|
|
13
15
|
class CollectionClass extends Resource {
|
|
14
16
|
constructor(document, init) {
|
|
15
17
|
super(document, init);
|
|
18
|
+
this._decoders = {};
|
|
19
|
+
this._encoders = {};
|
|
16
20
|
this.kind = OpraSchema.Collection.Kind;
|
|
17
21
|
this.controller = init.controller;
|
|
18
|
-
|
|
22
|
+
this.operations = { ...init.operations };
|
|
19
23
|
const dataType = this.type = init.type;
|
|
20
24
|
// Validate key fields
|
|
21
25
|
this.primaryKey = init.primaryKey
|
|
@@ -28,19 +32,6 @@ class CollectionClass extends Resource {
|
|
|
28
32
|
if (!(field?.type instanceof SimpleType))
|
|
29
33
|
throw new TypeError(`Only Simple type allowed for primary keys but "${f}" is a ${field.type.kind}`);
|
|
30
34
|
});
|
|
31
|
-
if (this.controller) {
|
|
32
|
-
const instance = typeof this.controller == 'function'
|
|
33
|
-
? new this.controller()
|
|
34
|
-
: this.controller;
|
|
35
|
-
for (const operation of Object.values(operations)) {
|
|
36
|
-
if (!operation.handler && operation.handlerName) {
|
|
37
|
-
const fn = instance[operation.handlerName];
|
|
38
|
-
if (!fn)
|
|
39
|
-
throw new TypeError(`No such operation handler (${operation.handlerName}) found`);
|
|
40
|
-
operation.handler = fn.bind(instance);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
35
|
}
|
|
45
36
|
exportSchema() {
|
|
46
37
|
const out = Resource.prototype.exportSchema.call(this);
|
|
@@ -66,7 +57,8 @@ class CollectionClass extends Resource {
|
|
|
66
57
|
// decode values
|
|
67
58
|
for (const [k, v] of Object.entries(obj)) {
|
|
68
59
|
const el = dataType.getField(k);
|
|
69
|
-
|
|
60
|
+
if (el.type instanceof SimpleType)
|
|
61
|
+
obj[k] = el.type.decode(v);
|
|
70
62
|
if (obj[k] == null)
|
|
71
63
|
throw new TypeError(`You must provide value of primary field(s) (${k})`);
|
|
72
64
|
}
|
|
@@ -76,7 +68,9 @@ class CollectionClass extends Resource {
|
|
|
76
68
|
if (typeof value === 'object')
|
|
77
69
|
value = value[primaryKey];
|
|
78
70
|
const el = dataType.getField(primaryKey);
|
|
79
|
-
|
|
71
|
+
let result;
|
|
72
|
+
if (el.type instanceof SimpleType)
|
|
73
|
+
result = el.type.decode(value);
|
|
80
74
|
if (result == null)
|
|
81
75
|
throw new TypeError(`You must provide value of primary field(s) (${primaryKey})`);
|
|
82
76
|
return result;
|
|
@@ -87,12 +81,14 @@ class CollectionClass extends Resource {
|
|
|
87
81
|
}
|
|
88
82
|
normalizeSortFields(fields) {
|
|
89
83
|
const normalized = this.type.normalizeFieldPath(fields);
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
if (!normalized)
|
|
85
|
+
return;
|
|
86
|
+
const findManyOp = this.operations.findMany;
|
|
87
|
+
const sortFields = findManyOp && findManyOp.sortFields;
|
|
92
88
|
(Array.isArray(normalized) ? normalized : [normalized]).forEach(field => {
|
|
93
89
|
if (!sortFields?.find(x => x === field))
|
|
94
90
|
throw new BadRequestError({
|
|
95
|
-
message: translate('error:UNACCEPTED_SORT_FIELD', { field }
|
|
91
|
+
message: translate('error:UNACCEPTED_SORT_FIELD', { field }),
|
|
96
92
|
});
|
|
97
93
|
});
|
|
98
94
|
return normalized;
|
|
@@ -105,27 +101,75 @@ class CollectionClass extends Resource {
|
|
|
105
101
|
this.normalizeFilter(ast.left);
|
|
106
102
|
if (!(ast.left instanceof OpraFilter.QualifiedIdentifier && ast.left.field))
|
|
107
103
|
throw new TypeError(`Invalid filter query. Left side should be a data field.`);
|
|
104
|
+
// Check if filtering accepted for given field
|
|
105
|
+
const findManyOp = this.operations.findMany;
|
|
106
|
+
const fieldLower = ast.left.value.toLowerCase();
|
|
107
|
+
const filterDef = (findManyOp && findManyOp.filters || [])
|
|
108
|
+
.find(f => f.field.toLowerCase() === fieldLower);
|
|
109
|
+
if (!filterDef) {
|
|
110
|
+
throw new BadRequestError({
|
|
111
|
+
message: translate('error:UNACCEPTED_FILTER_FIELD', { field: ast.left.value }),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// Check if filtering operation accepted for given field
|
|
115
|
+
if (!filterDef.operators?.includes(ast.op))
|
|
116
|
+
throw new BadRequestError({
|
|
117
|
+
message: translate('error:UNACCEPTED_FILTER_OPERATION', { field: ast.left.value }),
|
|
118
|
+
});
|
|
108
119
|
this.normalizeFilter(ast.right);
|
|
120
|
+
return ast;
|
|
109
121
|
}
|
|
110
|
-
|
|
122
|
+
if (ast instanceof OpraFilter.LogicalExpression) {
|
|
111
123
|
ast.items.forEach(item => this.normalizeFilter(item));
|
|
124
|
+
return ast;
|
|
112
125
|
}
|
|
113
|
-
|
|
126
|
+
if (ast instanceof OpraFilter.ArithmeticExpression) {
|
|
114
127
|
ast.items.forEach(item => this.normalizeFilter(item.expression));
|
|
128
|
+
return ast;
|
|
115
129
|
}
|
|
116
|
-
|
|
130
|
+
if (ast instanceof OpraFilter.ArrayExpression) {
|
|
117
131
|
ast.items.forEach(item => this.normalizeFilter(item));
|
|
132
|
+
return ast;
|
|
118
133
|
}
|
|
119
|
-
|
|
134
|
+
if (ast instanceof OpraFilter.ParenthesizedExpression) {
|
|
120
135
|
this.normalizeFilter(ast.expression);
|
|
136
|
+
return ast;
|
|
121
137
|
}
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
if (ast instanceof OpraFilter.QualifiedIdentifier) {
|
|
139
|
+
const normalizedFieldPath = this.type.normalizeFieldPath(ast.value)?.join('.');
|
|
140
|
+
ast.field = this.type.getField(normalizedFieldPath);
|
|
124
141
|
ast.dataType = ast.field?.type || this.document.getDataType('any');
|
|
125
|
-
ast.value =
|
|
142
|
+
ast.value = normalizedFieldPath;
|
|
143
|
+
return ast;
|
|
126
144
|
}
|
|
127
145
|
return ast;
|
|
128
146
|
}
|
|
147
|
+
getDecoder(operation) {
|
|
148
|
+
let decoder = this._decoders[operation];
|
|
149
|
+
if (decoder)
|
|
150
|
+
return decoder;
|
|
151
|
+
const options = {
|
|
152
|
+
partial: operation !== 'create'
|
|
153
|
+
};
|
|
154
|
+
if (operation !== 'create')
|
|
155
|
+
options.omit = [...this.primaryKey];
|
|
156
|
+
decoder = generateCodec(this.type, 'decode', options);
|
|
157
|
+
this._decoders[operation] = decoder;
|
|
158
|
+
return decoder;
|
|
159
|
+
}
|
|
160
|
+
getEncoder(operation) {
|
|
161
|
+
let encoder = this._encoders[operation];
|
|
162
|
+
if (encoder)
|
|
163
|
+
return encoder;
|
|
164
|
+
const options = {
|
|
165
|
+
partial: true
|
|
166
|
+
};
|
|
167
|
+
encoder = generateCodec(this.type, 'encode', options);
|
|
168
|
+
if (operation === 'findMany')
|
|
169
|
+
return vg.isArray(encoder);
|
|
170
|
+
this._encoders[operation] = encoder;
|
|
171
|
+
return encoder;
|
|
172
|
+
}
|
|
129
173
|
}
|
|
130
174
|
/**
|
|
131
175
|
*
|
|
@@ -163,13 +207,12 @@ export const Collection = function (...args) {
|
|
|
163
207
|
Collection.prototype = CollectionClass.prototype;
|
|
164
208
|
function createOperationDecorator(operation) {
|
|
165
209
|
return (options) => ((target, propertyKey) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
};
|
|
210
|
+
if (propertyKey !== operation)
|
|
211
|
+
throw new TypeError(`Name of the handler name should be '${operation}'`);
|
|
212
|
+
const operationMeta = { ...options };
|
|
170
213
|
const resourceMetadata = (Reflect.getOwnMetadata(METADATA_KEY, target.constructor) || {});
|
|
171
214
|
resourceMetadata.operations = resourceMetadata.operations || {};
|
|
172
|
-
resourceMetadata.operations[operation] =
|
|
215
|
+
resourceMetadata.operations[operation] = operationMeta;
|
|
173
216
|
Reflect.defineMetadata(METADATA_KEY, resourceMetadata, target.constructor);
|
|
174
217
|
});
|
|
175
218
|
}
|
|
@@ -3,29 +3,19 @@ import merge from 'putil-merge';
|
|
|
3
3
|
import { omitUndefined } from '../../helpers/index.js';
|
|
4
4
|
import { OpraSchema } from '../../schema/index.js';
|
|
5
5
|
import { METADATA_KEY } from '../constants.js';
|
|
6
|
+
import { generateCodec } from '../utils/generate-codec.js';
|
|
6
7
|
import { Resource } from './resource.js';
|
|
7
|
-
const NESTJS_INJECTABLE_WATERMARK = '__injectable__';
|
|
8
|
+
const NESTJS_INJECTABLE_WATERMARK = '__injectable__'; // todo, put this in nextjs package wia augmentation
|
|
8
9
|
const NAME_PATTERN = /^(.*)(Resource|Singleton)$/;
|
|
9
10
|
class SingletonClass extends Resource {
|
|
10
11
|
constructor(document, init) {
|
|
11
12
|
super(document, init);
|
|
13
|
+
this._decoders = {};
|
|
14
|
+
this._encoders = {};
|
|
12
15
|
this.kind = OpraSchema.Singleton.Kind;
|
|
13
16
|
this.controller = init.controller;
|
|
14
|
-
|
|
17
|
+
this.operations = { ...init.operations };
|
|
15
18
|
this.type = init.type;
|
|
16
|
-
if (this.controller) {
|
|
17
|
-
const instance = typeof this.controller == 'function'
|
|
18
|
-
? new this.controller()
|
|
19
|
-
: this.controller;
|
|
20
|
-
for (const operation of Object.values(operations)) {
|
|
21
|
-
if (!operation.handler && operation.handlerName) {
|
|
22
|
-
const fn = instance[operation.handlerName];
|
|
23
|
-
if (!fn)
|
|
24
|
-
throw new TypeError(`No such operation handler (${operation.handlerName}) found`);
|
|
25
|
-
operation.handler = fn.bind(instance);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
19
|
}
|
|
30
20
|
exportSchema() {
|
|
31
21
|
const out = Resource.prototype.exportSchema.call(this);
|
|
@@ -38,6 +28,28 @@ class SingletonClass extends Resource {
|
|
|
38
28
|
normalizeFieldPath(path) {
|
|
39
29
|
return this.type.normalizeFieldPath(path);
|
|
40
30
|
}
|
|
31
|
+
getDecoder(operation) {
|
|
32
|
+
let decoder = this._decoders[operation];
|
|
33
|
+
if (decoder)
|
|
34
|
+
return decoder;
|
|
35
|
+
const options = {
|
|
36
|
+
partial: operation !== 'create'
|
|
37
|
+
};
|
|
38
|
+
decoder = generateCodec(this.type, 'decode', options);
|
|
39
|
+
this._decoders[operation] = decoder;
|
|
40
|
+
return decoder;
|
|
41
|
+
}
|
|
42
|
+
getEncoder(operation) {
|
|
43
|
+
let encoder = this._encoders[operation];
|
|
44
|
+
if (encoder)
|
|
45
|
+
return encoder;
|
|
46
|
+
const options = {
|
|
47
|
+
partial: true
|
|
48
|
+
};
|
|
49
|
+
encoder = generateCodec(this.type, 'encode', options);
|
|
50
|
+
this._encoders[operation] = encoder;
|
|
51
|
+
return encoder;
|
|
52
|
+
}
|
|
41
53
|
}
|
|
42
54
|
export const Singleton = function (...args) {
|
|
43
55
|
// ClassDecorator
|
|
@@ -68,13 +80,12 @@ export const Singleton = function (...args) {
|
|
|
68
80
|
Singleton.prototype = SingletonClass.prototype;
|
|
69
81
|
function createOperationDecorator(operation) {
|
|
70
82
|
return (options) => ((target, propertyKey) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
83
|
+
if (propertyKey !== operation)
|
|
84
|
+
throw new TypeError(`Name of the handler name should be '${operation}'`);
|
|
85
|
+
const operationMeta = { ...options };
|
|
75
86
|
const resourceMetadata = (Reflect.getOwnMetadata(METADATA_KEY, target.constructor) || {});
|
|
76
87
|
resourceMetadata.operations = resourceMetadata.operations || {};
|
|
77
|
-
resourceMetadata.operations[operation] =
|
|
88
|
+
resourceMetadata.operations[operation] = operationMeta;
|
|
78
89
|
Reflect.defineMetadata(METADATA_KEY, resourceMetadata, target.constructor);
|
|
79
90
|
});
|
|
80
91
|
}
|
|
@@ -11,20 +11,7 @@ class StorageClass extends Resource {
|
|
|
11
11
|
super(document, init);
|
|
12
12
|
this.kind = OpraSchema.Storage.Kind;
|
|
13
13
|
this.controller = init.controller;
|
|
14
|
-
|
|
15
|
-
if (this.controller) {
|
|
16
|
-
const instance = typeof this.controller == 'function'
|
|
17
|
-
? new this.controller()
|
|
18
|
-
: this.controller;
|
|
19
|
-
for (const operation of Object.values(operations)) {
|
|
20
|
-
if (!operation.handler && operation.handlerName) {
|
|
21
|
-
const fn = instance[operation.handlerName];
|
|
22
|
-
if (!fn)
|
|
23
|
-
throw new TypeError(`No such operation handler (${operation.handlerName}) found`);
|
|
24
|
-
operation.handler = fn.bind(instance);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
14
|
+
this.operations = { ...init.operations };
|
|
28
15
|
}
|
|
29
16
|
exportSchema() {
|
|
30
17
|
const out = Resource.prototype.exportSchema.call(this);
|
|
@@ -62,16 +49,15 @@ export const Storage = function (...args) {
|
|
|
62
49
|
Storage.prototype = StorageClass.prototype;
|
|
63
50
|
function createOperationDecorator(operation) {
|
|
64
51
|
return (options) => ((target, propertyKey) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
};
|
|
52
|
+
if (propertyKey !== operation)
|
|
53
|
+
throw new TypeError(`Name of the handler name should be '${operation}'`);
|
|
54
|
+
const operationMeta = { ...options };
|
|
69
55
|
const resourceMetadata = (Reflect.getOwnMetadata(METADATA_KEY, target.constructor) || {});
|
|
70
56
|
resourceMetadata.operations = resourceMetadata.operations || {};
|
|
71
|
-
resourceMetadata.operations[operation] =
|
|
57
|
+
resourceMetadata.operations[operation] = operationMeta;
|
|
72
58
|
Reflect.defineMetadata(METADATA_KEY, resourceMetadata, target.constructor);
|
|
73
59
|
});
|
|
74
60
|
}
|
|
75
61
|
Storage.Delete = createOperationDecorator('delete');
|
|
76
62
|
Storage.Get = createOperationDecorator('get');
|
|
77
|
-
Storage.
|
|
63
|
+
Storage.Post = createOperationDecorator('post');
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as vg from 'valgen';
|
|
2
|
+
import { ComplexType } from '../data-type/complex-type.js';
|
|
3
|
+
import { EnumType } from '../data-type/enum-type.js';
|
|
4
|
+
import { MappedType } from '../data-type/mapped-type.js';
|
|
5
|
+
import { SimpleType } from '../data-type/simple-type.js';
|
|
6
|
+
import { UnionType } from '../data-type/union-type.js';
|
|
7
|
+
export function generateCodec(type, codec, options) {
|
|
8
|
+
return _generateDecoder(type, codec, options);
|
|
9
|
+
}
|
|
10
|
+
export function _generateDecoder(type, codec, options) {
|
|
11
|
+
const schema = {};
|
|
12
|
+
for (const f of type.fields.values()) {
|
|
13
|
+
let fn;
|
|
14
|
+
if (f.type instanceof SimpleType || f.type instanceof EnumType) {
|
|
15
|
+
fn = f.type[codec];
|
|
16
|
+
}
|
|
17
|
+
else if (f.type instanceof ComplexType || f.type instanceof MappedType || f.type instanceof UnionType) {
|
|
18
|
+
fn = _generateDecoder(f.type, codec, options);
|
|
19
|
+
}
|
|
20
|
+
/* istanbul ignore next */
|
|
21
|
+
if (!fn)
|
|
22
|
+
throw new TypeError(`Can't generate codec for (${f.type})`);
|
|
23
|
+
if (f.isArray)
|
|
24
|
+
fn = vg.isArray(fn);
|
|
25
|
+
schema[f.name] = !options.partial && f.required ? vg.required(fn) : vg.optional(fn);
|
|
26
|
+
}
|
|
27
|
+
return vg.isObject(schema, {
|
|
28
|
+
ctor: type.ctor,
|
|
29
|
+
additionalFields: type.additionalFields ?? false,
|
|
30
|
+
name: type.name,
|
|
31
|
+
caseInSensitive: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -10,10 +10,9 @@ export class BadRequestError extends OpraException {
|
|
|
10
10
|
super(...arguments);
|
|
11
11
|
this.status = 400;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
super.
|
|
13
|
+
init(issue) {
|
|
14
|
+
super.init({
|
|
15
15
|
message: translate('error:BAD_REQUEST', 'Bad request'),
|
|
16
|
-
severity: 'error',
|
|
17
16
|
code: 'BAD_REQUEST',
|
|
18
17
|
...issue
|
|
19
18
|
});
|
|
@@ -9,10 +9,9 @@ export class FailedDependencyError extends OpraException {
|
|
|
9
9
|
super(...arguments);
|
|
10
10
|
this.status = 424;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
super.
|
|
12
|
+
init(issue) {
|
|
13
|
+
super.init({
|
|
14
14
|
message: translate('error:FAILED_DEPENDENCY', 'The request failed due to failure of a previous request'),
|
|
15
|
-
severity: 'error',
|
|
16
15
|
code: 'FAILED_DEPENDENCY',
|
|
17
16
|
...issue
|
|
18
17
|
});
|