@opra/common 0.25.5 → 0.26.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 +1826 -1338
- package/cjs/document/api-document.js +16 -220
- package/cjs/document/data-type/complex-type-class.js +41 -19
- package/cjs/document/data-type/complex-type.js +1 -1
- package/cjs/document/data-type/data-type.js +2 -1
- package/cjs/document/data-type/enum-type-class.js +15 -12
- package/cjs/document/data-type/enum-type.js +28 -14
- package/cjs/document/data-type/field-class.js +21 -3
- package/cjs/document/data-type/field-decorator.js +0 -19
- package/cjs/document/data-type/mapped-type-class.js +8 -10
- package/cjs/document/data-type/mapped-type.js +1 -1
- package/cjs/document/data-type/simple-type-class.js +17 -8
- package/cjs/document/data-type/simple-type.js +1 -1
- package/cjs/document/data-type/union-type-class.js +15 -13
- package/cjs/document/document-base.js +24 -0
- package/cjs/document/factory/api-document-factory.js +231 -0
- package/cjs/document/factory/type-document-factory.js +324 -0
- package/cjs/document/index.js +7 -1
- package/cjs/document/resource/action-decorator.js +27 -0
- package/cjs/document/resource/collection-class.js +95 -44
- package/cjs/document/resource/collection-decorator.js +182 -0
- package/cjs/document/resource/collection.js +4 -4
- package/cjs/document/resource/container-class.js +82 -0
- package/cjs/document/resource/container-decorator.js +24 -0
- package/cjs/document/resource/container.js +29 -0
- package/cjs/document/resource/crud-resource.js +31 -0
- package/cjs/document/resource/endpoint.js +24 -22
- package/cjs/document/resource/operation-decorator.js +27 -0
- package/cjs/document/resource/parameter.js +51 -0
- package/cjs/document/{decorators/resource.decorator.js → resource/resource-decorator.js} +9 -14
- package/cjs/document/resource/resource.js +20 -5
- package/cjs/document/resource/singleton-class.js +60 -40
- package/cjs/document/resource/singleton-decorator.js +57 -0
- package/cjs/document/resource/singleton.js +4 -4
- package/cjs/document/resource/storage-class.js +11 -17
- package/cjs/document/resource/storage-decorator.js +66 -0
- package/cjs/document/resource/storage.js +3 -3
- package/cjs/document/type-document.js +195 -0
- package/cjs/exception/http-errors/internal-server.error.js +1 -0
- package/cjs/exception/wrap-exception.js +2 -1
- package/cjs/helpers/responsive-map.js +3 -3
- package/cjs/http/opra-url-path.js +2 -1
- package/cjs/schema/document/document-base.interface.js +2 -0
- package/cjs/schema/document/type-document.interface.js +2 -0
- package/cjs/schema/opra-schema.ns.js +3 -1
- package/cjs/schema/type-guards.js +3 -3
- package/esm/document/api-document.js +16 -220
- package/esm/document/data-type/complex-type-class.js +40 -19
- package/esm/document/data-type/complex-type.js +1 -1
- package/esm/document/data-type/data-type.js +2 -1
- package/esm/document/data-type/enum-type-class.js +15 -12
- package/esm/document/data-type/enum-type.js +26 -12
- package/esm/document/data-type/field-class.js +20 -3
- package/esm/document/data-type/field-decorator.js +0 -19
- package/esm/document/data-type/mapped-type-class.js +9 -11
- package/esm/document/data-type/mapped-type.js +1 -1
- package/esm/document/data-type/simple-type-class.js +15 -6
- package/esm/document/data-type/simple-type.js +1 -1
- package/esm/document/data-type/union-type-class.js +11 -9
- package/esm/document/document-base.js +20 -0
- package/esm/document/factory/api-document-factory.js +227 -0
- package/esm/document/factory/type-document-factory.js +320 -0
- package/esm/document/index.js +7 -1
- package/esm/document/resource/action-decorator.js +23 -0
- package/esm/document/resource/collection-class.js +95 -44
- package/esm/document/resource/collection-decorator.js +178 -0
- package/esm/document/resource/collection.js +4 -4
- package/esm/document/resource/container-class.js +78 -0
- package/esm/document/resource/container-decorator.js +20 -0
- package/esm/document/resource/container.js +25 -0
- package/esm/document/resource/crud-resource.js +27 -0
- package/esm/document/resource/endpoint.js +22 -20
- package/esm/document/resource/operation-decorator.js +23 -0
- package/esm/document/resource/parameter.js +46 -0
- package/esm/document/resource/resource-decorator.js +28 -0
- package/esm/document/resource/resource.js +20 -5
- package/esm/document/resource/singleton-class.js +58 -38
- package/esm/document/resource/singleton-decorator.js +53 -0
- package/esm/document/resource/singleton.js +4 -4
- package/esm/document/resource/storage-class.js +9 -15
- package/esm/document/resource/storage-decorator.js +62 -0
- package/esm/document/resource/storage.js +3 -3
- package/esm/document/type-document.js +191 -0
- package/esm/exception/http-errors/internal-server.error.js +1 -0
- package/esm/exception/wrap-exception.js +2 -1
- package/esm/helpers/responsive-map.js +3 -3
- package/esm/http/opra-url-path.js +1 -1
- package/esm/schema/document/document-base.interface.js +1 -0
- package/esm/schema/document/type-document.interface.js +1 -0
- package/esm/schema/opra-schema.ns.js +3 -1
- package/esm/schema/type-guards.js +1 -1
- package/package.json +4 -4
- package/types/document/api-document.d.ts +32 -73
- package/types/document/data-type/complex-type-class.d.ts +5 -5
- package/types/document/data-type/complex-type.d.ts +8 -3
- package/types/document/{decorators → data-type}/complex-type.decorator.d.ts +1 -1
- package/types/document/data-type/data-type.d.ts +11 -1
- package/types/document/data-type/enum-type-class.d.ts +6 -6
- package/types/document/data-type/enum-type.d.ts +12 -6
- package/types/document/data-type/field-class.d.ts +9 -1
- package/types/document/data-type/field-decorator.d.ts +1 -1
- package/types/document/data-type/field.d.ts +4 -3
- package/types/document/data-type/mapped-type-class.d.ts +5 -9
- package/types/document/data-type/mapped-type.d.ts +6 -7
- package/types/document/data-type/simple-type-class.d.ts +6 -3
- package/types/document/{decorators → data-type}/simple-type.decorator.d.ts +1 -1
- package/types/document/data-type/union-type-class.d.ts +2 -8
- package/types/document/data-type/union-type.d.ts +7 -6
- package/types/document/document-base.d.ts +10 -0
- package/types/document/factory/api-document-factory.d.ts +50 -0
- package/types/document/factory/type-document-factory.d.ts +56 -0
- package/types/document/index.d.ts +7 -1
- package/types/document/resource/action-decorator.d.ts +6 -0
- package/types/document/resource/collection-class.d.ts +17 -12
- package/types/document/resource/collection-decorator.d.ts +192 -0
- package/types/document/resource/collection.d.ts +11 -19
- package/types/document/resource/container-class.d.ts +66 -0
- package/types/document/resource/container-decorator.d.ts +37 -0
- package/types/document/resource/container.d.ts +25 -0
- package/types/document/resource/crud-resource.d.ts +16 -0
- package/types/document/resource/endpoint.d.ts +21 -21
- package/types/document/resource/operation-decorator.d.ts +6 -0
- package/types/document/resource/parameter.d.ts +35 -0
- package/types/document/resource/resource-decorator.d.ts +32 -0
- package/types/document/resource/resource.d.ts +15 -13
- package/types/document/resource/singleton-class.d.ts +15 -14
- package/types/document/resource/singleton-decorator.d.ts +125 -0
- package/types/document/resource/singleton.d.ts +11 -16
- package/types/document/resource/storage-class.d.ts +13 -6
- package/types/document/resource/storage-decorator.d.ts +98 -0
- package/types/document/resource/storage.d.ts +9 -12
- package/types/document/type-document.d.ts +68 -0
- package/types/http/opra-url-path.d.ts +1 -1
- package/types/schema/data-type/complex-type.interface.d.ts +1 -1
- package/types/schema/data-type/data-type.interface.d.ts +3 -3
- package/types/schema/data-type/enum-type.interface.d.ts +6 -7
- package/types/schema/data-type/mapped-type.interface.d.ts +4 -3
- package/types/schema/data-type/simple-type.interface.d.ts +3 -3
- package/types/schema/data-type/union-type.interface.d.ts +6 -4
- package/types/schema/document/api-document.interface.d.ts +11 -0
- package/types/schema/document/document-base.interface.d.ts +24 -0
- package/types/schema/document/type-document.interface.d.ts +6 -0
- package/types/schema/opra-schema.ns.d.ts +3 -1
- package/types/schema/resource/collection.interface.d.ts +31 -31
- package/types/schema/resource/container.interface.d.ts +4 -3
- package/types/schema/resource/resource.interface.d.ts +1 -1
- package/types/schema/resource/singleton.interface.d.ts +15 -10
- package/types/schema/resource/storage.interface.d.ts +49 -45
- package/types/schema/type-guards.d.ts +3 -2
- package/cjs/document/decorators/build-operation-decorator.js +0 -27
- package/cjs/document/decorators/collection-decorator.js +0 -30
- package/cjs/document/decorators/singleton.decorator.js +0 -25
- package/cjs/document/decorators/storage.decorator.js +0 -27
- package/cjs/document/factory/add-references.js +0 -20
- package/cjs/document/factory/create-document.js +0 -83
- package/cjs/document/factory/factory.js +0 -66
- package/cjs/document/factory/import-resource-class.js +0 -54
- package/cjs/document/factory/import-type-class.js +0 -146
- package/cjs/document/factory/index.js +0 -4
- package/cjs/document/factory/process-resources.js +0 -70
- package/cjs/document/factory/process-types.js +0 -191
- package/cjs/document/utils/generate-codec.js +0 -39
- package/esm/document/decorators/build-operation-decorator.js +0 -23
- package/esm/document/decorators/collection-decorator.js +0 -26
- package/esm/document/decorators/resource.decorator.js +0 -33
- package/esm/document/decorators/singleton.decorator.js +0 -21
- package/esm/document/decorators/storage.decorator.js +0 -23
- package/esm/document/factory/add-references.js +0 -16
- package/esm/document/factory/create-document.js +0 -77
- package/esm/document/factory/factory.js +0 -62
- package/esm/document/factory/import-resource-class.js +0 -48
- package/esm/document/factory/import-type-class.js +0 -136
- package/esm/document/factory/index.js +0 -1
- package/esm/document/factory/process-resources.js +0 -63
- package/esm/document/factory/process-types.js +0 -185
- package/esm/document/utils/generate-codec.js +0 -33
- package/types/document/decorators/build-operation-decorator.d.ts +0 -13
- package/types/document/decorators/collection-decorator.d.ts +0 -33
- package/types/document/decorators/resource.decorator.d.ts +0 -9
- package/types/document/decorators/singleton.decorator.d.ts +0 -25
- package/types/document/decorators/storage.decorator.d.ts +0 -25
- package/types/document/factory/add-references.d.ts +0 -4
- package/types/document/factory/create-document.d.ts +0 -12
- package/types/document/factory/factory.d.ts +0 -63
- package/types/document/factory/import-resource-class.d.ts +0 -10
- package/types/document/factory/import-type-class.d.ts +0 -17
- package/types/document/factory/index.d.ts +0 -1
- package/types/document/factory/process-resources.d.ts +0 -9
- package/types/document/factory/process-types.d.ts +0 -6
- package/types/document/utils/generate-codec.d.ts +0 -10
- package/types/schema/document.interface.d.ts +0 -34
- /package/cjs/document/{decorators → data-type}/complex-type.decorator.js +0 -0
- /package/cjs/document/{decorators → data-type}/simple-type.decorator.js +0 -0
- /package/cjs/schema/{document.interface.js → document/api-document.interface.js} +0 -0
- /package/esm/document/{decorators → data-type}/complex-type.decorator.js +0 -0
- /package/esm/document/{decorators → data-type}/simple-type.decorator.js +0 -0
- /package/esm/schema/{document.interface.js → document/api-document.interface.js} +0 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { validator } from 'valgen';
|
|
2
|
+
import { cloneObject, isConstructor, resolveThunk, ResponsiveMap } from '../../helpers/index.js';
|
|
3
|
+
import { OpraSchema } from '../../schema/index.js';
|
|
4
|
+
import { DATATYPE_METADATA } from '../constants.js';
|
|
5
|
+
import { AnyType, Base64Type, BigintType, BooleanType, DateType, IntegerType, NullType, NumberType, ObjectIdType, ObjectType, StringType, TimestampType, TimeType, UuidType } from '../data-type/builtin/index.js';
|
|
6
|
+
import { ComplexType } from '../data-type/complex-type.js';
|
|
7
|
+
import { EnumType } from '../data-type/enum-type.js';
|
|
8
|
+
import { MappedType } from '../data-type/mapped-type.js';
|
|
9
|
+
import { SimpleType } from '../data-type/simple-type.js';
|
|
10
|
+
import { UnionType } from '../data-type/union-type.js';
|
|
11
|
+
import { TypeDocument } from '../type-document.js';
|
|
12
|
+
/**
|
|
13
|
+
* @class TypeDocumentFactory
|
|
14
|
+
*/
|
|
15
|
+
export class TypeDocumentFactory {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.typeQueue = new ResponsiveMap();
|
|
18
|
+
this.circularRefs = new Map();
|
|
19
|
+
this.curPath = [];
|
|
20
|
+
this.cache = new Map();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates ApiDocument instance from given schema object
|
|
24
|
+
*/
|
|
25
|
+
static async createDocument(init) {
|
|
26
|
+
const factory = new TypeDocumentFactory();
|
|
27
|
+
const document = factory.document = new TypeDocument();
|
|
28
|
+
await factory.initDocument(init);
|
|
29
|
+
return document;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Downloads schema from the given URL and creates the document instance * @param url
|
|
33
|
+
*/
|
|
34
|
+
static async createDocumentFromUrl(url) {
|
|
35
|
+
const factory = new TypeDocumentFactory();
|
|
36
|
+
const document = factory.document = new TypeDocument();
|
|
37
|
+
await factory.initDocumentFromUrl(url);
|
|
38
|
+
return document;
|
|
39
|
+
}
|
|
40
|
+
async initDocument(init) {
|
|
41
|
+
this.document.url = init.url;
|
|
42
|
+
if (init.info)
|
|
43
|
+
Object.assign(this.document.info, init.info);
|
|
44
|
+
if (!init?.noBuiltinTypes) {
|
|
45
|
+
const builtinDocument = await this.createBuiltinTypeDocument();
|
|
46
|
+
this.document.references.set('Opra', builtinDocument);
|
|
47
|
+
}
|
|
48
|
+
if (init.references)
|
|
49
|
+
await this.addReferences(init.references);
|
|
50
|
+
if (init.types) {
|
|
51
|
+
this.curPath.push('Types->');
|
|
52
|
+
// Add type sources into typeQueue
|
|
53
|
+
if (Array.isArray(init.types)) {
|
|
54
|
+
let i = 0;
|
|
55
|
+
for (const thunk of init.types) {
|
|
56
|
+
const metadata = Reflect.getMetadata(DATATYPE_METADATA, thunk) || thunk[DATATYPE_METADATA];
|
|
57
|
+
if (!(metadata && metadata.name))
|
|
58
|
+
throw new TypeError(`Metadata information not found at types[${i++}] "${String(thunk)}"`);
|
|
59
|
+
this.typeQueue.set(metadata.name, thunk);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
for (const [name, schema] of Object.entries(init.types)) {
|
|
64
|
+
this.typeQueue.set(name, { ...schema, name });
|
|
65
|
+
}
|
|
66
|
+
// Create type instances
|
|
67
|
+
for (const thunk of this.typeQueue.values()) {
|
|
68
|
+
await this.importDataType(thunk);
|
|
69
|
+
}
|
|
70
|
+
this.document.types.sort();
|
|
71
|
+
this.curPath.pop();
|
|
72
|
+
}
|
|
73
|
+
this.document.invalidate();
|
|
74
|
+
return this.document;
|
|
75
|
+
}
|
|
76
|
+
async initDocumentFromUrl(url) {
|
|
77
|
+
const resp = await fetch(url, { method: 'GET' });
|
|
78
|
+
const init = await resp.json();
|
|
79
|
+
if (!init)
|
|
80
|
+
throw new TypeError(`Invalid response returned from url: ${url}`);
|
|
81
|
+
return await this.initDocument({ ...init, url });
|
|
82
|
+
}
|
|
83
|
+
async createBuiltinTypeDocument() {
|
|
84
|
+
const init = {
|
|
85
|
+
version: OpraSchema.SpecVersion,
|
|
86
|
+
info: {
|
|
87
|
+
version: OpraSchema.SpecVersion,
|
|
88
|
+
title: 'Opra built-in types',
|
|
89
|
+
contact: [{
|
|
90
|
+
url: 'https://github.com/oprajs/opra'
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
license: {
|
|
94
|
+
url: 'https://github.com/oprajs/opra/blob/main/LICENSE',
|
|
95
|
+
name: 'MIT'
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
types: [AnyType, Base64Type, BigintType, BooleanType,
|
|
99
|
+
DateType, UuidType, IntegerType, NullType,
|
|
100
|
+
NumberType, ObjectType, ObjectIdType, StringType,
|
|
101
|
+
TimeType, TimestampType
|
|
102
|
+
]
|
|
103
|
+
};
|
|
104
|
+
const factory = new TypeDocumentFactory();
|
|
105
|
+
factory.document = new TypeDocument();
|
|
106
|
+
return await factory.initDocument({ ...init, noBuiltinTypes: true });
|
|
107
|
+
}
|
|
108
|
+
async addReferences(references) {
|
|
109
|
+
const { document } = this;
|
|
110
|
+
for (const [ns, r] of Object.entries(references)) {
|
|
111
|
+
if (typeof r === 'string') {
|
|
112
|
+
document.references.set(ns, await this.initDocumentFromUrl(r));
|
|
113
|
+
}
|
|
114
|
+
else if (r instanceof TypeDocument)
|
|
115
|
+
document.references.set(ns, r);
|
|
116
|
+
else if (typeof r === 'object') {
|
|
117
|
+
document.references.set(ns, await this.initDocument(r));
|
|
118
|
+
}
|
|
119
|
+
else
|
|
120
|
+
throw new TypeError(`Invalid document reference (${ns}) in schema`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async importDataType(thunk) {
|
|
124
|
+
thunk = await resolveThunk(thunk);
|
|
125
|
+
let name = '';
|
|
126
|
+
let schema;
|
|
127
|
+
let ctor;
|
|
128
|
+
if (typeof thunk === 'string') {
|
|
129
|
+
name = thunk;
|
|
130
|
+
schema = this.typeQueue.get(name);
|
|
131
|
+
}
|
|
132
|
+
else if (typeof thunk === 'function') {
|
|
133
|
+
const metadata = Reflect.getMetadata(DATATYPE_METADATA, thunk);
|
|
134
|
+
if (!metadata) {
|
|
135
|
+
// Check if is an internal type class like String, Number etc
|
|
136
|
+
const dataType = this.document.getDataType(thunk, true);
|
|
137
|
+
if (dataType)
|
|
138
|
+
return dataType;
|
|
139
|
+
throw new TypeError(`Class "${thunk.name}" doesn't have a valid DataType metadata`);
|
|
140
|
+
}
|
|
141
|
+
name = metadata.name;
|
|
142
|
+
schema = metadata;
|
|
143
|
+
ctor = thunk;
|
|
144
|
+
}
|
|
145
|
+
else if (typeof thunk === 'object') {
|
|
146
|
+
if (OpraSchema.isDataType(thunk)) {
|
|
147
|
+
name = thunk.name;
|
|
148
|
+
ctor = thunk.ctor || ctor;
|
|
149
|
+
schema = thunk;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// It should be an enum object
|
|
153
|
+
const metadata = thunk[DATATYPE_METADATA];
|
|
154
|
+
if (!metadata)
|
|
155
|
+
throw new TypeError(`No EnumType metadata found for object ${JSON.stringify(thunk).substring(0, 20)}...`);
|
|
156
|
+
name = metadata.name;
|
|
157
|
+
const dataType = this.document.getDataType(name, true);
|
|
158
|
+
if (dataType)
|
|
159
|
+
return dataType;
|
|
160
|
+
schema = cloneObject(metadata);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
ctor = ctor ?? (schema && (isConstructor(schema.ctor)) ? schema.ctor : undefined);
|
|
164
|
+
if (name) {
|
|
165
|
+
if (this.circularRefs.has(name.toLowerCase()))
|
|
166
|
+
throw new TypeError('Circular reference detected');
|
|
167
|
+
const dataType = this.document.getDataType(name, true);
|
|
168
|
+
if (dataType)
|
|
169
|
+
return dataType;
|
|
170
|
+
this.curPath.push('/' + name);
|
|
171
|
+
this.circularRefs.set(name, 1);
|
|
172
|
+
}
|
|
173
|
+
if (ctor) {
|
|
174
|
+
if (this.circularRefs.has(ctor))
|
|
175
|
+
throw new TypeError('Circular reference detected');
|
|
176
|
+
const dataType = this.document.getDataType(ctor, true);
|
|
177
|
+
if (dataType)
|
|
178
|
+
return dataType;
|
|
179
|
+
this.circularRefs.set(ctor, 1);
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
if (!OpraSchema.isDataType(schema))
|
|
183
|
+
throw new TypeError(`No DataType schema determined`);
|
|
184
|
+
// Create an empty DataType instance and add in to document.
|
|
185
|
+
// This will help us for circular dependent data types
|
|
186
|
+
const instance = this.createDataTypeInstance(schema.kind, name);
|
|
187
|
+
if (name)
|
|
188
|
+
this.document.types.set(name, instance);
|
|
189
|
+
const initArguments = cloneObject(schema);
|
|
190
|
+
await this.prepareDataTypeInitArguments(initArguments, ctor);
|
|
191
|
+
if (initArguments.kind === 'ComplexType')
|
|
192
|
+
ComplexType.apply(instance, [this.document, initArguments]);
|
|
193
|
+
else if (initArguments.kind === 'SimpleType')
|
|
194
|
+
SimpleType.apply(instance, [this.document, initArguments]);
|
|
195
|
+
else if (initArguments.kind === 'EnumType')
|
|
196
|
+
EnumType.apply(instance, [this.document, initArguments]);
|
|
197
|
+
else if (initArguments.kind === 'MappedType')
|
|
198
|
+
MappedType.apply(instance, [this.document, initArguments]);
|
|
199
|
+
else if (initArguments.kind === 'UnionType')
|
|
200
|
+
UnionType.apply(instance, [this.document, initArguments]);
|
|
201
|
+
else
|
|
202
|
+
throw new TypeError(`Invalid data type schema: ${String(schema)}`);
|
|
203
|
+
return instance;
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
if (name) {
|
|
207
|
+
this.curPath.pop();
|
|
208
|
+
this.circularRefs.delete(name.toLowerCase());
|
|
209
|
+
}
|
|
210
|
+
if (ctor)
|
|
211
|
+
this.circularRefs.delete(ctor);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async prepareDataTypeInitArguments(schema, ctor) {
|
|
215
|
+
const initArguments = schema;
|
|
216
|
+
// Import extending class first
|
|
217
|
+
if (initArguments.kind === 'SimpleType' || initArguments.kind === 'ComplexType' ||
|
|
218
|
+
initArguments.kind === 'EnumType') {
|
|
219
|
+
if (ctor) {
|
|
220
|
+
const baseClass = Object.getPrototypeOf(ctor.prototype).constructor;
|
|
221
|
+
const baseMeta = Reflect.getMetadata(DATATYPE_METADATA, baseClass);
|
|
222
|
+
if (baseMeta) {
|
|
223
|
+
initArguments.base = await this.importDataType(baseClass);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (initArguments.base) {
|
|
227
|
+
initArguments.base = await this.importDataType(initArguments.base);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (initArguments.kind === 'SimpleType' && ctor) {
|
|
231
|
+
if (typeof ctor.prototype.decode === 'function')
|
|
232
|
+
initArguments.decoder = initArguments.name
|
|
233
|
+
? validator(initArguments.name, ctor.prototype.decode) : validator(ctor.prototype.decode);
|
|
234
|
+
if (typeof ctor.prototype.encode === 'function')
|
|
235
|
+
initArguments.decoder = initArguments.name
|
|
236
|
+
? validator(initArguments.name, ctor.prototype.encode) : validator(ctor.prototype.encode);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (initArguments.kind === 'ComplexType') {
|
|
240
|
+
initArguments.ctor = ctor;
|
|
241
|
+
if (initArguments.fields) {
|
|
242
|
+
const srcFields = initArguments.fields;
|
|
243
|
+
const trgFields = initArguments.fields = {};
|
|
244
|
+
for (const [fieldName, o] of Object.entries(srcFields)) {
|
|
245
|
+
try {
|
|
246
|
+
this.curPath.push('.' + fieldName);
|
|
247
|
+
const srcMeta = typeof o === 'string' ? { type: o } : o;
|
|
248
|
+
const fieldInit = trgFields[fieldName] = {
|
|
249
|
+
...srcMeta,
|
|
250
|
+
name: fieldName
|
|
251
|
+
};
|
|
252
|
+
if (srcMeta.enum) {
|
|
253
|
+
const enumObject = srcMeta.enum;
|
|
254
|
+
delete srcMeta.enum;
|
|
255
|
+
if (enumObject[DATATYPE_METADATA]) {
|
|
256
|
+
fieldInit.type = await this.importDataType(enumObject);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
const enumMeta = EnumType(enumObject);
|
|
260
|
+
fieldInit.type = await this.importDataType({ ...enumMeta, kind: 'EnumType', base: undefined });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
if (srcMeta.isArray && !srcMeta.type)
|
|
265
|
+
throw new TypeError(`"type" must be defined explicitly for array properties`);
|
|
266
|
+
fieldInit.type = await this.importDataType(srcMeta.type || srcMeta.designType || 'any');
|
|
267
|
+
}
|
|
268
|
+
this.curPath.pop();
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
e.message = `Error in resource "${initArguments.name}.${fieldName}". ` + e.message;
|
|
272
|
+
throw e;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (initArguments.kind === 'MappedType') {
|
|
278
|
+
const dataType = await this.importDataType(initArguments.base);
|
|
279
|
+
// istanbul ignore next
|
|
280
|
+
if (!(dataType instanceof ComplexType))
|
|
281
|
+
throw new TypeError('MappedType.type property must address to a ComplexType');
|
|
282
|
+
initArguments.base = dataType;
|
|
283
|
+
}
|
|
284
|
+
if (initArguments.kind === 'UnionType') {
|
|
285
|
+
const oldTypes = initArguments.types;
|
|
286
|
+
initArguments.types = [];
|
|
287
|
+
for (const type of oldTypes)
|
|
288
|
+
initArguments.types.push(await this.importDataType(type));
|
|
289
|
+
}
|
|
290
|
+
return initArguments;
|
|
291
|
+
}
|
|
292
|
+
createDataTypeInstance(kind, name) {
|
|
293
|
+
const dataType = {
|
|
294
|
+
document: this.document,
|
|
295
|
+
kind,
|
|
296
|
+
name
|
|
297
|
+
};
|
|
298
|
+
switch (kind) {
|
|
299
|
+
case OpraSchema.ComplexType.Kind:
|
|
300
|
+
Object.setPrototypeOf(dataType, ComplexType.prototype);
|
|
301
|
+
break;
|
|
302
|
+
case OpraSchema.EnumType.Kind:
|
|
303
|
+
Object.setPrototypeOf(dataType, EnumType.prototype);
|
|
304
|
+
break;
|
|
305
|
+
case OpraSchema.MappedType.Kind:
|
|
306
|
+
Object.setPrototypeOf(dataType, MappedType.prototype);
|
|
307
|
+
break;
|
|
308
|
+
case OpraSchema.SimpleType.Kind:
|
|
309
|
+
Object.setPrototypeOf(dataType, SimpleType.prototype);
|
|
310
|
+
break;
|
|
311
|
+
case OpraSchema.UnionType.Kind:
|
|
312
|
+
Object.setPrototypeOf(dataType, UnionType.prototype);
|
|
313
|
+
break;
|
|
314
|
+
default:
|
|
315
|
+
throw new TypeError(`Unknown DataType kind (${kind})`);
|
|
316
|
+
}
|
|
317
|
+
return dataType;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
TypeDocumentFactory.designTypeMap = new Map();
|
package/esm/document/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
export * from './constants.js';
|
|
3
3
|
export * from './api-document.js';
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './type-document.js';
|
|
5
|
+
export * from './factory/type-document-factory.js';
|
|
6
|
+
export * from './factory/api-document-factory.js';
|
|
5
7
|
export * from './data-type/data-type.js';
|
|
6
8
|
export * from './data-type/complex-type.js';
|
|
7
9
|
export * from './data-type/field.js';
|
|
@@ -10,9 +12,13 @@ export * from './data-type/mapped-type.js';
|
|
|
10
12
|
export * from './data-type/simple-type.js';
|
|
11
13
|
export * from './data-type/union-type.js';
|
|
12
14
|
export * from './resource/resource.js';
|
|
15
|
+
export * from './resource/crud-resource.js';
|
|
13
16
|
export * from './resource/collection.js';
|
|
17
|
+
export * from './resource/container.js';
|
|
14
18
|
export * from './resource/singleton.js';
|
|
15
19
|
export * from './resource/storage.js';
|
|
20
|
+
export * from './resource/endpoint.js';
|
|
21
|
+
export * from './resource/parameter.js';
|
|
16
22
|
export * from './interfaces/collection.interface.js';
|
|
17
23
|
export * from './interfaces/singleton.interface.js';
|
|
18
24
|
export * from './interfaces/storage.interface.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RESOURCE_METADATA } from '../constants.js';
|
|
2
|
+
export function createActionDecorator(options, bannedProperties, list) {
|
|
3
|
+
const decorator = ((target, propertyKey) => {
|
|
4
|
+
if (typeof propertyKey === 'string' && bannedProperties.includes(propertyKey))
|
|
5
|
+
throw new TypeError(`The "${propertyKey}" property is reserved for "${propertyKey}" operations and cannot be used as an action'`);
|
|
6
|
+
const resourceMetadata = (Reflect.getOwnMetadata(RESOURCE_METADATA, target.constructor) || {});
|
|
7
|
+
resourceMetadata.actions = resourceMetadata.actions || {};
|
|
8
|
+
const actionMeta = { ...options };
|
|
9
|
+
resourceMetadata.actions[propertyKey] = actionMeta;
|
|
10
|
+
for (const fn of list)
|
|
11
|
+
fn(actionMeta);
|
|
12
|
+
Reflect.defineMetadata(RESOURCE_METADATA, resourceMetadata, target.constructor);
|
|
13
|
+
});
|
|
14
|
+
decorator.Parameter = (name, arg0) => {
|
|
15
|
+
const parameterOptions = typeof arg0 === 'string' || typeof arg0 === 'function' ? { type: arg0 } : { ...arg0 };
|
|
16
|
+
list.push((operationMeta) => {
|
|
17
|
+
operationMeta.parameters = operationMeta.parameters || {};
|
|
18
|
+
operationMeta.parameters[name] = { ...parameterOptions };
|
|
19
|
+
});
|
|
20
|
+
return decorator;
|
|
21
|
+
};
|
|
22
|
+
return decorator;
|
|
23
|
+
}
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import * as vg from 'valgen';
|
|
2
2
|
import { BadRequestError } from '../../exception/index.js';
|
|
3
3
|
import { OpraFilter } from '../../filter/index.js';
|
|
4
|
-
import { omitUndefined } from '../../helpers/object-utils.js';
|
|
5
4
|
import { translate } from '../../i18n/index.js';
|
|
6
5
|
import { OpraSchema } from '../../schema/index.js';
|
|
7
6
|
import { SimpleType } from '../data-type/simple-type.js';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
super(document, init);
|
|
13
|
-
this._decoders = {};
|
|
14
|
-
this._encoders = {};
|
|
7
|
+
import { CrudResource } from './crud-resource.js';
|
|
8
|
+
export class CollectionClass extends CrudResource {
|
|
9
|
+
constructor(parent, init) {
|
|
10
|
+
super(parent, init);
|
|
15
11
|
this.kind = OpraSchema.Collection.Kind;
|
|
16
|
-
this.controller = init.controller;
|
|
17
|
-
this.operations = { ...init.operations };
|
|
18
12
|
const dataType = this.type = init.type;
|
|
19
13
|
// Validate key fields
|
|
20
14
|
this.primaryKey = init.primaryKey
|
|
@@ -27,15 +21,98 @@ export class CollectionClass extends Resource {
|
|
|
27
21
|
if (!(field?.type instanceof SimpleType))
|
|
28
22
|
throw new TypeError(`Only Simple type allowed for primary keys but "${f}" is a ${field.type.kind}`);
|
|
29
23
|
});
|
|
24
|
+
// ------------------
|
|
25
|
+
let endpoint = this.operations.get('create');
|
|
26
|
+
if (endpoint) {
|
|
27
|
+
endpoint.returnType = this.type;
|
|
28
|
+
endpoint.decode = this.type.generateCodec('decode', {
|
|
29
|
+
partial: true,
|
|
30
|
+
pick: endpoint.inputPickFields,
|
|
31
|
+
omit: endpoint.inputOmitFields,
|
|
32
|
+
});
|
|
33
|
+
endpoint.encode = this.type.generateCodec('encode', {
|
|
34
|
+
partial: true,
|
|
35
|
+
pick: endpoint.outputPickFields,
|
|
36
|
+
omit: endpoint.outputOmitFields,
|
|
37
|
+
});
|
|
38
|
+
endpoint.defineParameter('pick', { type: 'string', isArray: true, isBuiltin: true });
|
|
39
|
+
endpoint.defineParameter('omit', { type: 'string', isArray: true, isBuiltin: true });
|
|
40
|
+
endpoint.defineParameter('include', { type: 'string', isArray: true, isBuiltin: true });
|
|
41
|
+
}
|
|
42
|
+
// ------------------
|
|
43
|
+
endpoint = this.operations.get('deleteMany');
|
|
44
|
+
if (endpoint) {
|
|
45
|
+
endpoint.defineParameter('filter', { type: 'string', isBuiltin: true });
|
|
46
|
+
}
|
|
47
|
+
// ------------------
|
|
48
|
+
endpoint = this.operations.get('get');
|
|
49
|
+
if (endpoint) {
|
|
50
|
+
endpoint.returnType = this.type;
|
|
51
|
+
endpoint.encode = this.type.generateCodec('encode', {
|
|
52
|
+
partial: true,
|
|
53
|
+
pick: endpoint.outputPickFields,
|
|
54
|
+
omit: endpoint.outputOmitFields,
|
|
55
|
+
});
|
|
56
|
+
endpoint.defineParameter('pick', { type: 'string', isArray: true, isBuiltin: true });
|
|
57
|
+
endpoint.defineParameter('omit', { type: 'string', isArray: true, isBuiltin: true });
|
|
58
|
+
endpoint.defineParameter('include', { type: 'string', isArray: true, isBuiltin: true });
|
|
59
|
+
}
|
|
60
|
+
// ------------------
|
|
61
|
+
endpoint = this.operations.get('findMany');
|
|
62
|
+
if (endpoint) {
|
|
63
|
+
endpoint.returnType = this.type;
|
|
64
|
+
endpoint.encode = vg.isArray(this.type.generateCodec('encode', {
|
|
65
|
+
partial: true,
|
|
66
|
+
pick: endpoint.outputPickFields,
|
|
67
|
+
omit: endpoint.outputOmitFields,
|
|
68
|
+
}));
|
|
69
|
+
endpoint.defineParameter('pick', { type: 'string', isArray: true, isBuiltin: true });
|
|
70
|
+
endpoint.defineParameter('omit', { type: 'string', isArray: true, isBuiltin: true });
|
|
71
|
+
endpoint.defineParameter('include', { type: 'string', isArray: true, isBuiltin: true });
|
|
72
|
+
endpoint.defineParameter('sort', { type: 'string', isArray: true, isBuiltin: true });
|
|
73
|
+
endpoint.defineParameter('filter', { type: 'string', isBuiltin: true });
|
|
74
|
+
endpoint.defineParameter('limit', { type: 'integer', isBuiltin: true });
|
|
75
|
+
endpoint.defineParameter('skip', { type: 'integer', isBuiltin: true });
|
|
76
|
+
endpoint.defineParameter('distinct', { type: 'boolean', isBuiltin: true });
|
|
77
|
+
endpoint.defineParameter('count', { type: 'boolean', isBuiltin: true });
|
|
78
|
+
}
|
|
79
|
+
// ------------------
|
|
80
|
+
endpoint = this.operations.get('update');
|
|
81
|
+
if (endpoint) {
|
|
82
|
+
endpoint.returnType = this.type;
|
|
83
|
+
endpoint.decode = this.type.generateCodec('decode', {
|
|
84
|
+
pick: endpoint.inputPickFields,
|
|
85
|
+
omit: endpoint.inputOmitFields,
|
|
86
|
+
});
|
|
87
|
+
endpoint.encode = this.type.generateCodec('encode', {
|
|
88
|
+
partial: true,
|
|
89
|
+
pick: endpoint.outputPickFields,
|
|
90
|
+
omit: endpoint.outputOmitFields,
|
|
91
|
+
});
|
|
92
|
+
endpoint.defineParameter('pick', { type: 'string', isArray: true, isBuiltin: true });
|
|
93
|
+
endpoint.defineParameter('omit', { type: 'string', isArray: true, isBuiltin: true });
|
|
94
|
+
endpoint.defineParameter('include', { type: 'string', isArray: true, isBuiltin: true });
|
|
95
|
+
}
|
|
96
|
+
// ------------------
|
|
97
|
+
endpoint = this.operations.get('updateMany');
|
|
98
|
+
if (endpoint) {
|
|
99
|
+
endpoint.decode = this.type.generateCodec('decode', {
|
|
100
|
+
pick: endpoint.inputPickFields,
|
|
101
|
+
omit: endpoint.inputOmitFields,
|
|
102
|
+
});
|
|
103
|
+
endpoint.defineParameter('filter', { type: 'string', isBuiltin: true });
|
|
104
|
+
}
|
|
30
105
|
}
|
|
31
|
-
|
|
106
|
+
getOperation(name) {
|
|
107
|
+
return super.getOperation(name);
|
|
108
|
+
}
|
|
109
|
+
exportSchema(options) {
|
|
32
110
|
return {
|
|
33
|
-
...super.exportSchema(),
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
operations: this.operations,
|
|
111
|
+
...super.exportSchema(options),
|
|
112
|
+
type: this.type.name || 'object',
|
|
113
|
+
...{
|
|
37
114
|
primaryKey: this.primaryKey
|
|
38
|
-
}
|
|
115
|
+
}
|
|
39
116
|
};
|
|
40
117
|
}
|
|
41
118
|
parseKeyValue(value) {
|
|
@@ -79,7 +156,7 @@ export class CollectionClass extends Resource {
|
|
|
79
156
|
const normalized = this.type.normalizeFieldPath(fields);
|
|
80
157
|
if (!normalized)
|
|
81
158
|
return;
|
|
82
|
-
const findManyOp = this.
|
|
159
|
+
const findManyOp = this.getOperation('findMany');
|
|
83
160
|
const sortFields = findManyOp && findManyOp.sortFields;
|
|
84
161
|
(Array.isArray(normalized) ? normalized : [normalized]).forEach(field => {
|
|
85
162
|
if (!sortFields?.find(x => x === field))
|
|
@@ -98,7 +175,7 @@ export class CollectionClass extends Resource {
|
|
|
98
175
|
if (!(ast.left instanceof OpraFilter.QualifiedIdentifier && ast.left.field))
|
|
99
176
|
throw new TypeError(`Invalid filter query. Left side should be a data field.`);
|
|
100
177
|
// Check if filtering accepted for given field
|
|
101
|
-
const findManyOp = this.
|
|
178
|
+
const findManyOp = this.getOperation('findMany');
|
|
102
179
|
const fieldLower = ast.left.value.toLowerCase();
|
|
103
180
|
const filterDef = (findManyOp && findManyOp.filters || [])
|
|
104
181
|
.find(f => f.field.toLowerCase() === fieldLower);
|
|
@@ -140,30 +217,4 @@ export class CollectionClass extends Resource {
|
|
|
140
217
|
}
|
|
141
218
|
return ast;
|
|
142
219
|
}
|
|
143
|
-
getDecoder(endpoint) {
|
|
144
|
-
let decoder = this._decoders[endpoint];
|
|
145
|
-
if (decoder)
|
|
146
|
-
return decoder;
|
|
147
|
-
const options = {
|
|
148
|
-
partial: endpoint !== 'create'
|
|
149
|
-
};
|
|
150
|
-
if (endpoint !== 'create')
|
|
151
|
-
options.omit = [...this.primaryKey];
|
|
152
|
-
decoder = generateCodec(this.type, 'decode', options);
|
|
153
|
-
this._decoders[endpoint] = decoder;
|
|
154
|
-
return decoder;
|
|
155
|
-
}
|
|
156
|
-
getEncoder(endpoint) {
|
|
157
|
-
let encoder = this._encoders[endpoint];
|
|
158
|
-
if (encoder)
|
|
159
|
-
return encoder;
|
|
160
|
-
const options = {
|
|
161
|
-
partial: true
|
|
162
|
-
};
|
|
163
|
-
encoder = generateCodec(this.type, 'encode', options);
|
|
164
|
-
if (endpoint === 'findMany')
|
|
165
|
-
return vg.isArray(encoder);
|
|
166
|
-
this._encoders[endpoint] = encoder;
|
|
167
|
-
return encoder;
|
|
168
|
-
}
|
|
169
220
|
}
|