@opra/core 0.0.5
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/LICENSE +21 -0
- package/README.md +3 -0
- package/cjs/constants.js +5 -0
- package/cjs/decorators/entity-resource.decorator.js +24 -0
- package/cjs/enums/http-headers.enum.js +393 -0
- package/cjs/enums/http-status.enum.js +300 -0
- package/cjs/enums/index.js +5 -0
- package/cjs/enums/issue-severity.enum.js +2 -0
- package/cjs/exception/api-exception.js +63 -0
- package/cjs/exception/errors/bad-request.error.js +22 -0
- package/cjs/exception/errors/failed-dependency.error.js +21 -0
- package/cjs/exception/errors/forbidden.error.js +23 -0
- package/cjs/exception/errors/internal-server.error.js +21 -0
- package/cjs/exception/errors/method-not-allowed.error.js +22 -0
- package/cjs/exception/errors/not-found.error.js +25 -0
- package/cjs/exception/errors/unauthorized.error.js +22 -0
- package/cjs/exception/errors/unprocessable-entity.error.js +21 -0
- package/cjs/exception/index.js +11 -0
- package/cjs/implementation/adapter/adapter.js +72 -0
- package/cjs/implementation/adapter/express-adapter.js +93 -0
- package/cjs/implementation/adapter/http-adapter.js +262 -0
- package/cjs/implementation/data-type/complex-type.js +39 -0
- package/cjs/implementation/data-type/data-type.js +35 -0
- package/cjs/implementation/data-type/entity-type.js +33 -0
- package/cjs/implementation/data-type/simple-type.js +30 -0
- package/cjs/implementation/execution-context.js +49 -0
- package/cjs/implementation/opra-document.js +116 -0
- package/cjs/implementation/opra-service.js +59 -0
- package/cjs/implementation/resource/container-resource-controller.js +26 -0
- package/cjs/implementation/resource/entity-resource-info.js +68 -0
- package/cjs/implementation/resource/resource-info.js +24 -0
- package/cjs/implementation/schema-generator.js +173 -0
- package/cjs/index.js +25 -0
- package/cjs/interfaces/entity-resource.interface.js +2 -0
- package/cjs/interfaces/execution-query.interface.js +190 -0
- package/cjs/interfaces/http-context.interface.js +2 -0
- package/cjs/interfaces/opra-schema.metadata.js +2 -0
- package/cjs/interfaces/resource-container.interface.js +2 -0
- package/cjs/package.json +3 -0
- package/cjs/services/data-service.js +9 -0
- package/cjs/services/json-data-service.js +15 -0
- package/cjs/types.js +2 -0
- package/cjs/utils/class-utils.js +37 -0
- package/cjs/utils/headers.js +58 -0
- package/cjs/utils/internal-data-types.js +44 -0
- package/cjs/utils/responsive-object.js +49 -0
- package/cjs/utils/string-path-to-object-tree.js +26 -0
- package/cjs/utils/terminal-utils.js +7 -0
- package/esm/constants.d.ts +2 -0
- package/esm/constants.js +2 -0
- package/esm/decorators/entity-resource.decorator.d.ts +5 -0
- package/esm/decorators/entity-resource.decorator.js +19 -0
- package/esm/enums/http-headers.enum.d.ts +368 -0
- package/esm/enums/http-headers.enum.js +390 -0
- package/esm/enums/http-status.enum.d.ts +290 -0
- package/esm/enums/http-status.enum.js +297 -0
- package/esm/enums/index.d.ts +2 -0
- package/esm/enums/index.js +2 -0
- package/esm/enums/issue-severity.enum.d.ts +1 -0
- package/esm/enums/issue-severity.enum.js +1 -0
- package/esm/exception/api-exception.d.ts +38 -0
- package/esm/exception/api-exception.js +59 -0
- package/esm/exception/errors/bad-request.error.d.ts +9 -0
- package/esm/exception/errors/bad-request.error.js +18 -0
- package/esm/exception/errors/failed-dependency.error.d.ts +8 -0
- package/esm/exception/errors/failed-dependency.error.js +17 -0
- package/esm/exception/errors/forbidden.error.d.ts +10 -0
- package/esm/exception/errors/forbidden.error.js +19 -0
- package/esm/exception/errors/internal-server.error.d.ts +8 -0
- package/esm/exception/errors/internal-server.error.js +17 -0
- package/esm/exception/errors/method-not-allowed.error.d.ts +9 -0
- package/esm/exception/errors/method-not-allowed.error.js +18 -0
- package/esm/exception/errors/not-found.error.d.ts +12 -0
- package/esm/exception/errors/not-found.error.js +21 -0
- package/esm/exception/errors/unauthorized.error.d.ts +9 -0
- package/esm/exception/errors/unauthorized.error.js +18 -0
- package/esm/exception/errors/unprocessable-entity.error.d.ts +8 -0
- package/esm/exception/errors/unprocessable-entity.error.js +17 -0
- package/esm/exception/index.d.ts +8 -0
- package/esm/exception/index.js +8 -0
- package/esm/implementation/adapter/adapter.d.ts +18 -0
- package/esm/implementation/adapter/adapter.js +68 -0
- package/esm/implementation/adapter/express-adapter.d.ts +12 -0
- package/esm/implementation/adapter/express-adapter.js +89 -0
- package/esm/implementation/adapter/http-adapter.d.ts +27 -0
- package/esm/implementation/adapter/http-adapter.js +258 -0
- package/esm/implementation/data-type/complex-type.d.ts +18 -0
- package/esm/implementation/data-type/complex-type.js +35 -0
- package/esm/implementation/data-type/data-type.d.ts +15 -0
- package/esm/implementation/data-type/data-type.js +31 -0
- package/esm/implementation/data-type/entity-type.d.ts +10 -0
- package/esm/implementation/data-type/entity-type.js +29 -0
- package/esm/implementation/data-type/simple-type.d.ts +15 -0
- package/esm/implementation/data-type/simple-type.js +26 -0
- package/esm/implementation/execution-context.d.ts +42 -0
- package/esm/implementation/execution-context.js +43 -0
- package/esm/implementation/opra-document.d.ts +26 -0
- package/esm/implementation/opra-document.js +111 -0
- package/esm/implementation/opra-service.d.ts +19 -0
- package/esm/implementation/opra-service.js +55 -0
- package/esm/implementation/resource/container-resource-controller.d.ts +12 -0
- package/esm/implementation/resource/container-resource-controller.js +22 -0
- package/esm/implementation/resource/entity-resource-info.d.ts +24 -0
- package/esm/implementation/resource/entity-resource-info.js +63 -0
- package/esm/implementation/resource/resource-info.d.ts +10 -0
- package/esm/implementation/resource/resource-info.js +20 -0
- package/esm/implementation/schema-generator.d.ts +21 -0
- package/esm/implementation/schema-generator.js +169 -0
- package/esm/index.d.ts +22 -0
- package/esm/index.js +22 -0
- package/esm/interfaces/entity-resource.interface.d.ts +9 -0
- package/esm/interfaces/entity-resource.interface.js +1 -0
- package/esm/interfaces/execution-query.interface.d.ts +102 -0
- package/esm/interfaces/execution-query.interface.js +186 -0
- package/esm/interfaces/http-context.interface.d.ts +23 -0
- package/esm/interfaces/http-context.interface.js +1 -0
- package/esm/interfaces/opra-schema.metadata.d.ts +14 -0
- package/esm/interfaces/opra-schema.metadata.js +1 -0
- package/esm/interfaces/resource-container.interface.d.ts +6 -0
- package/esm/interfaces/resource-container.interface.js +1 -0
- package/esm/services/data-service.d.ts +2 -0
- package/esm/services/data-service.js +5 -0
- package/esm/services/json-data-service.d.ts +9 -0
- package/esm/services/json-data-service.js +10 -0
- package/esm/types.d.ts +11 -0
- package/esm/types.js +1 -0
- package/esm/utils/class-utils.d.ts +6 -0
- package/esm/utils/class-utils.js +30 -0
- package/esm/utils/headers.d.ts +9 -0
- package/esm/utils/headers.js +55 -0
- package/esm/utils/internal-data-types.d.ts +4 -0
- package/esm/utils/internal-data-types.js +41 -0
- package/esm/utils/responsive-object.d.ts +3 -0
- package/esm/utils/responsive-object.js +45 -0
- package/esm/utils/string-path-to-object-tree.d.ts +4 -0
- package/esm/utils/string-path-to-object-tree.js +22 -0
- package/esm/utils/terminal-utils.d.ts +4 -0
- package/esm/utils/terminal-utils.js +4 -0
- package/package.json +77 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpraService = void 0;
|
|
4
|
+
const schema_1 = require("@opra/schema");
|
|
5
|
+
const responsive_object_js_1 = require("../utils/responsive-object.js");
|
|
6
|
+
const entity_type_js_1 = require("./data-type/entity-type.js");
|
|
7
|
+
const opra_document_js_1 = require("./opra-document.js");
|
|
8
|
+
const entity_resource_info_js_1 = require("./resource/entity-resource-info.js");
|
|
9
|
+
const schema_generator_js_1 = require("./schema-generator.js");
|
|
10
|
+
class OpraService extends opra_document_js_1.OpraDocument {
|
|
11
|
+
_resources = (0, responsive_object_js_1.Responsive)();
|
|
12
|
+
constructor(schema) {
|
|
13
|
+
super(schema);
|
|
14
|
+
if (schema.resources)
|
|
15
|
+
this._addResources(schema.resources);
|
|
16
|
+
}
|
|
17
|
+
get resources() {
|
|
18
|
+
return this._resources;
|
|
19
|
+
}
|
|
20
|
+
get servers() {
|
|
21
|
+
return this._args.servers;
|
|
22
|
+
}
|
|
23
|
+
getResource(name) {
|
|
24
|
+
const t = this.resources[name];
|
|
25
|
+
if (!t)
|
|
26
|
+
throw new Error(`Resource "${name}" does not exists`);
|
|
27
|
+
return t;
|
|
28
|
+
}
|
|
29
|
+
getEntityResource(name) {
|
|
30
|
+
const t = this.getResource(name);
|
|
31
|
+
if (!(t instanceof entity_resource_info_js_1.EntityResourceInfo))
|
|
32
|
+
throw new Error(`"${name}" is not an EntityResource`);
|
|
33
|
+
return t;
|
|
34
|
+
}
|
|
35
|
+
_addResources(resources) {
|
|
36
|
+
for (const r of resources) {
|
|
37
|
+
if (schema_1.OpraSchema.isEntityResource(r)) {
|
|
38
|
+
const dataType = this.getDataType(r.type);
|
|
39
|
+
if (!dataType)
|
|
40
|
+
throw new TypeError(`Datatype "${r.type}" declared in EntityResource (${r.name}) does not exists`);
|
|
41
|
+
if (!(dataType instanceof entity_type_js_1.EntityType))
|
|
42
|
+
throw new TypeError(`${r.type} is not an EntityType`);
|
|
43
|
+
this.resources[r.name] = new entity_resource_info_js_1.EntityResourceInfo({ ...r, service: this, dataType });
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
throw new TypeError(`Unknown resource kind (${r.kind})`);
|
|
47
|
+
}
|
|
48
|
+
// Sort data types by name
|
|
49
|
+
const newResources = (0, responsive_object_js_1.Responsive)();
|
|
50
|
+
Object.keys(this.resources).sort()
|
|
51
|
+
.forEach(name => newResources[name] = this.resources[name]);
|
|
52
|
+
this._resources = newResources;
|
|
53
|
+
}
|
|
54
|
+
static async create(args) {
|
|
55
|
+
const schema = await schema_generator_js_1.SchemaGenerator.generateServiceSchema(args);
|
|
56
|
+
return new OpraService(schema);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.OpraService = OpraService;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContainerResourceController = void 0;
|
|
4
|
+
const entity_resource_info_js_1 = require("./entity-resource-info.js");
|
|
5
|
+
const resource_info_js_1 = require("./resource-info.js");
|
|
6
|
+
class ContainerResourceController extends resource_info_js_1.ResourceInfo {
|
|
7
|
+
constructor(args) {
|
|
8
|
+
super({
|
|
9
|
+
kind: 'ContainerResource',
|
|
10
|
+
...args
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
getResource(name) {
|
|
14
|
+
const t = this._args.resources[name];
|
|
15
|
+
if (!t)
|
|
16
|
+
throw new Error(`Resource "${name}" does not exists`);
|
|
17
|
+
return t;
|
|
18
|
+
}
|
|
19
|
+
getEntityResource(name) {
|
|
20
|
+
const t = this.getResource(name);
|
|
21
|
+
if (!(t instanceof entity_resource_info_js_1.EntityResourceInfo))
|
|
22
|
+
throw new Error(`"${name}" is not an EntityResource`);
|
|
23
|
+
return t;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.ContainerResourceController = ContainerResourceController;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityResourceInfo = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
6
|
+
const entity_type_js_1 = require("../data-type/entity-type.js");
|
|
7
|
+
const resource_info_js_1 = require("./resource-info.js");
|
|
8
|
+
class EntityResourceInfo extends resource_info_js_1.ResourceInfo {
|
|
9
|
+
service;
|
|
10
|
+
dataType;
|
|
11
|
+
constructor(args) {
|
|
12
|
+
super({
|
|
13
|
+
kind: 'EntityResource',
|
|
14
|
+
...lodash_1.default.omit(args, ['dataType', 'service'])
|
|
15
|
+
});
|
|
16
|
+
this.dataType = args.dataType;
|
|
17
|
+
this.service = args.service;
|
|
18
|
+
// noinspection SuspiciousTypeOfGuard
|
|
19
|
+
if (!(args.dataType instanceof entity_type_js_1.EntityType))
|
|
20
|
+
throw new TypeError(`You should provide an EntityType for EntityResourceController`);
|
|
21
|
+
}
|
|
22
|
+
get search() {
|
|
23
|
+
return this._args.search;
|
|
24
|
+
}
|
|
25
|
+
get create() {
|
|
26
|
+
return this._args.create;
|
|
27
|
+
}
|
|
28
|
+
get read() {
|
|
29
|
+
return this._args.read;
|
|
30
|
+
}
|
|
31
|
+
get update() {
|
|
32
|
+
return this._args.update;
|
|
33
|
+
}
|
|
34
|
+
get updateAll() {
|
|
35
|
+
return this._args.updateMany;
|
|
36
|
+
}
|
|
37
|
+
get delete() {
|
|
38
|
+
return this._args.delete;
|
|
39
|
+
}
|
|
40
|
+
get deleteMany() {
|
|
41
|
+
return this._args.deleteMany;
|
|
42
|
+
}
|
|
43
|
+
async execute(ctx) {
|
|
44
|
+
const { query } = ctx.request;
|
|
45
|
+
const fn = this._args[query.queryType];
|
|
46
|
+
const result = typeof fn === 'function' ? (await fn(ctx)) : undefined;
|
|
47
|
+
if (query.queryType === 'search') {
|
|
48
|
+
ctx.response.value = Array.isArray(result)
|
|
49
|
+
? result
|
|
50
|
+
: (ctx.response.value ? [result] : []);
|
|
51
|
+
}
|
|
52
|
+
else if (query.queryType === 'delete' ||
|
|
53
|
+
query.queryType === 'deleteMany' ||
|
|
54
|
+
query.queryType === 'updateMany') {
|
|
55
|
+
let affected = result;
|
|
56
|
+
if (affected && typeof affected === 'object')
|
|
57
|
+
affected = result.affected || result.affectedRows;
|
|
58
|
+
affected = typeof affected === 'number' ? affected :
|
|
59
|
+
(affected === false ? 0 : (affected ? 1 : 0));
|
|
60
|
+
ctx.response.value = {
|
|
61
|
+
affected
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
else
|
|
65
|
+
ctx.response.value = Array.isArray(result) ? result[0] : result;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.EntityResourceInfo = EntityResourceInfo;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResourceInfo = void 0;
|
|
4
|
+
const terminal_utils_js_1 = require("../../utils/terminal-utils.js");
|
|
5
|
+
class ResourceInfo {
|
|
6
|
+
_args;
|
|
7
|
+
constructor(args) {
|
|
8
|
+
this._args = args;
|
|
9
|
+
}
|
|
10
|
+
get name() {
|
|
11
|
+
return this._args.name;
|
|
12
|
+
}
|
|
13
|
+
get description() {
|
|
14
|
+
return this._args.description;
|
|
15
|
+
}
|
|
16
|
+
toString() {
|
|
17
|
+
return `[${Object.getPrototypeOf(this).constructor.name} ${this.name}]`;
|
|
18
|
+
}
|
|
19
|
+
[terminal_utils_js_1.nodeInspectCustom]() {
|
|
20
|
+
return `[${terminal_utils_js_1.colorFgYellow + Object.getPrototypeOf(this).constructor.name + terminal_utils_js_1.colorReset}` +
|
|
21
|
+
` ${terminal_utils_js_1.colorFgMagenta + this.name + terminal_utils_js_1.colorReset}]`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ResourceInfo = ResourceInfo;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaGenerator = void 0;
|
|
4
|
+
const types_1 = require("util/types");
|
|
5
|
+
const schema_1 = require("@opra/schema");
|
|
6
|
+
const constants_js_1 = require("../constants.js");
|
|
7
|
+
const class_utils_js_1 = require("../utils/class-utils.js");
|
|
8
|
+
const internal_data_types_js_1 = require("../utils/internal-data-types.js");
|
|
9
|
+
const entityMethods = ['search', 'create', 'read', 'update', 'updateMany', 'delete', 'deleteMany'];
|
|
10
|
+
class SchemaGenerator {
|
|
11
|
+
_dataTypes = {};
|
|
12
|
+
_resources = {};
|
|
13
|
+
constructor() {
|
|
14
|
+
//
|
|
15
|
+
}
|
|
16
|
+
async addDataType(thunk) {
|
|
17
|
+
let schema;
|
|
18
|
+
thunk = (0, types_1.isPromise)(thunk) ? await thunk : thunk;
|
|
19
|
+
if (typeof thunk === 'function' && !(0, class_utils_js_1.isConstructor)(thunk))
|
|
20
|
+
thunk = await thunk();
|
|
21
|
+
if (!(0, class_utils_js_1.isConstructor)(thunk) || schema_1.OpraSchema.isDataType(thunk))
|
|
22
|
+
throw new TypeError(`Function must return a type class or type schema`);
|
|
23
|
+
if ((0, class_utils_js_1.isConstructor)(thunk)) {
|
|
24
|
+
const ctor = thunk;
|
|
25
|
+
const metadata = Reflect.getOwnMetadata(schema_1.DATATYPE_METADATA, ctor);
|
|
26
|
+
if (!metadata)
|
|
27
|
+
throw new TypeError(`Class "${ctor}" has no type metadata`);
|
|
28
|
+
schema = this._dataTypes[metadata.name];
|
|
29
|
+
if (schema) {
|
|
30
|
+
if (schema.kind !== metadata.kind ||
|
|
31
|
+
(schema_1.OpraSchema.isComplexType(schema) && schema.ctor !== ctor))
|
|
32
|
+
throw new Error(`An other instance of "${schema.name}" data type previously defined`);
|
|
33
|
+
return schema;
|
|
34
|
+
}
|
|
35
|
+
// Add base data type
|
|
36
|
+
let base;
|
|
37
|
+
let baseCtor = Object.getPrototypeOf(ctor);
|
|
38
|
+
if (Reflect.hasMetadata(schema_1.DATATYPE_METADATA, baseCtor)) {
|
|
39
|
+
while (!Reflect.hasOwnMetadata(schema_1.DATATYPE_METADATA, baseCtor)) {
|
|
40
|
+
baseCtor = Object.getPrototypeOf(baseCtor);
|
|
41
|
+
}
|
|
42
|
+
const baseSchema = await this.addDataType(baseCtor);
|
|
43
|
+
base = baseSchema.name;
|
|
44
|
+
}
|
|
45
|
+
if (schema_1.OpraSchema.isComplexType(metadata) || schema_1.OpraSchema.isEntityType(metadata)) {
|
|
46
|
+
schema = {
|
|
47
|
+
...metadata,
|
|
48
|
+
ctor,
|
|
49
|
+
base
|
|
50
|
+
};
|
|
51
|
+
const properties = Reflect.getMetadata(schema_1.DATATYPE_PROPERTIES, ctor.prototype);
|
|
52
|
+
if (properties) {
|
|
53
|
+
for (const [k, p] of Object.entries(properties)) {
|
|
54
|
+
let type;
|
|
55
|
+
if ((0, class_utils_js_1.isConstructor)(p.type) && internal_data_types_js_1.builtinClassMap.has(p.type))
|
|
56
|
+
type = internal_data_types_js_1.builtinClassMap.get(p.type);
|
|
57
|
+
else if (typeof p.type === 'function' || typeof p.type === 'object') {
|
|
58
|
+
const t = await this.addDataType(p.type);
|
|
59
|
+
type = t.name;
|
|
60
|
+
}
|
|
61
|
+
else
|
|
62
|
+
type = p.type || 'string';
|
|
63
|
+
if (internal_data_types_js_1.internalDataTypes.has(type) && !this._dataTypes[type])
|
|
64
|
+
this._dataTypes[type] = internal_data_types_js_1.internalDataTypes.get(type.toLowerCase());
|
|
65
|
+
schema.properties = schema.properties || {};
|
|
66
|
+
schema.properties[k] = { ...p, type };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (schema_1.OpraSchema.isSimpleType(metadata)) {
|
|
71
|
+
if (!internal_data_types_js_1.primitiveDataTypeNames.includes(metadata.type))
|
|
72
|
+
throw new Error(`"type" of SimpleType schema must be one of enumerated value (${internal_data_types_js_1.primitiveDataTypeNames})`);
|
|
73
|
+
schema = {
|
|
74
|
+
...metadata
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
/* istanbul ignore next */
|
|
79
|
+
throw new TypeError(`Invalid metadata`);
|
|
80
|
+
}
|
|
81
|
+
else if (schema_1.OpraSchema.isDataType(thunk)) {
|
|
82
|
+
schema = thunk;
|
|
83
|
+
}
|
|
84
|
+
else
|
|
85
|
+
throw new TypeError(`Invalid data type schema`);
|
|
86
|
+
this._dataTypes[schema.name] = schema;
|
|
87
|
+
return schema;
|
|
88
|
+
}
|
|
89
|
+
async addResource(instance) {
|
|
90
|
+
if ((0, class_utils_js_1.isConstructor)(instance))
|
|
91
|
+
throw new Error(`You should provide Resource instance instead of Resource class`);
|
|
92
|
+
const proto = Object.getPrototypeOf(instance);
|
|
93
|
+
const ctor = proto.constructor;
|
|
94
|
+
const metadata = Reflect.getMetadata(constants_js_1.RESOURCE_METADATA, ctor);
|
|
95
|
+
let resourceSchema;
|
|
96
|
+
if (metadata) {
|
|
97
|
+
const name = metadata.name || ctor.name.replace(/Resource$/, '');
|
|
98
|
+
const t = typeof metadata.type === 'function'
|
|
99
|
+
? await (0, class_utils_js_1.resolveClassAsync)(metadata.type)
|
|
100
|
+
: metadata.type;
|
|
101
|
+
const type = typeof t === 'function'
|
|
102
|
+
? (await this.addDataType(t)).name
|
|
103
|
+
: t;
|
|
104
|
+
resourceSchema = {
|
|
105
|
+
...metadata,
|
|
106
|
+
type,
|
|
107
|
+
name
|
|
108
|
+
};
|
|
109
|
+
if (schema_1.OpraSchema.isEntityResource(resourceSchema)) {
|
|
110
|
+
for (const methodName of entityMethods) {
|
|
111
|
+
const fn = instance[methodName];
|
|
112
|
+
if (typeof fn === 'function') {
|
|
113
|
+
resourceSchema[methodName] = fn.bind(instance);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else
|
|
119
|
+
resourceSchema = instance;
|
|
120
|
+
if (schema_1.OpraSchema.isResource(resourceSchema)) {
|
|
121
|
+
if (schema_1.OpraSchema.isEntityResource(resourceSchema)) {
|
|
122
|
+
const t = this._dataTypes[resourceSchema.type];
|
|
123
|
+
if (!t)
|
|
124
|
+
throw new Error(`Resource registration error. Type "${resourceSchema.type}" not found.`);
|
|
125
|
+
if (this._resources[resourceSchema.name])
|
|
126
|
+
throw new Error(`An other instance of "${resourceSchema.name}" resource previously defined`);
|
|
127
|
+
this._resources[resourceSchema.name] = resourceSchema;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
throw new Error(`Invalid resource metadata`);
|
|
131
|
+
}
|
|
132
|
+
throw new Error(`Invalid resource object`);
|
|
133
|
+
}
|
|
134
|
+
static async generateDocumentSchema(args) {
|
|
135
|
+
const generator = new SchemaGenerator();
|
|
136
|
+
if (args.types) {
|
|
137
|
+
for (const thunk of args.types) {
|
|
138
|
+
await generator.addDataType(thunk);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const types = Object.keys(generator._dataTypes).sort()
|
|
142
|
+
.map(name => generator._dataTypes[name]);
|
|
143
|
+
return {
|
|
144
|
+
version: '1',
|
|
145
|
+
...args,
|
|
146
|
+
types
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
static async generateServiceSchema(args) {
|
|
150
|
+
const generator = new SchemaGenerator();
|
|
151
|
+
if (args.types) {
|
|
152
|
+
for (const thunk of args.types) {
|
|
153
|
+
await generator.addDataType(thunk);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (args.resources) {
|
|
157
|
+
for (const resource of args.resources) {
|
|
158
|
+
await generator.addResource(resource);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const types = Object.keys(generator._dataTypes).sort()
|
|
162
|
+
.map(name => generator._dataTypes[name]);
|
|
163
|
+
const resources = Object.keys(generator._resources).sort()
|
|
164
|
+
.map(name => generator._resources[name]);
|
|
165
|
+
return {
|
|
166
|
+
version: '1',
|
|
167
|
+
...args,
|
|
168
|
+
types,
|
|
169
|
+
resources
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.SchemaGenerator = SchemaGenerator;
|
package/cjs/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
tslib_1.__exportStar(require("./constants.js"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./types.js"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./enums/index.js"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./exception/index.js"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./decorators/entity-resource.decorator.js"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./interfaces/http-context.interface.js"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./interfaces/execution-query.interface.js"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./interfaces/entity-resource.interface.js"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./interfaces/resource-container.interface.js"), exports);
|
|
14
|
+
tslib_1.__exportStar(require("./implementation/execution-context.js"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./implementation/opra-document.js"), exports);
|
|
16
|
+
tslib_1.__exportStar(require("./implementation/opra-service.js"), exports);
|
|
17
|
+
tslib_1.__exportStar(require("./implementation/schema-generator.js"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./implementation/adapter/adapter.js"), exports);
|
|
19
|
+
tslib_1.__exportStar(require("./implementation/adapter/express-adapter.js"), exports);
|
|
20
|
+
tslib_1.__exportStar(require("./implementation/data-type/data-type.js"), exports);
|
|
21
|
+
tslib_1.__exportStar(require("./implementation/data-type/complex-type.js"), exports);
|
|
22
|
+
tslib_1.__exportStar(require("./implementation/data-type/simple-type.js"), exports);
|
|
23
|
+
tslib_1.__exportStar(require("./implementation/resource/resource-info.js"), exports);
|
|
24
|
+
tslib_1.__exportStar(require("./implementation/resource/entity-resource-info.js"), exports);
|
|
25
|
+
tslib_1.__exportStar(require("./services/json-data-service.js"), exports);
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExecutionQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
6
|
+
const complex_type_js_1 = require("../implementation/data-type/complex-type.js");
|
|
7
|
+
const string_path_to_object_tree_js_1 = require("../utils/string-path-to-object-tree.js");
|
|
8
|
+
var ExecutionQuery;
|
|
9
|
+
(function (ExecutionQuery) {
|
|
10
|
+
function forCreate(resource, values, options) {
|
|
11
|
+
if (options?.pick)
|
|
12
|
+
options.pick = normalizePick(resource, options.pick);
|
|
13
|
+
if (options?.omit)
|
|
14
|
+
options.omit = normalizePick(resource, options.omit);
|
|
15
|
+
if (options?.include)
|
|
16
|
+
options.include = normalizePick(resource, options.include);
|
|
17
|
+
const out = {
|
|
18
|
+
queryType: 'create',
|
|
19
|
+
scope: 'collection',
|
|
20
|
+
operationType: 'create',
|
|
21
|
+
resource,
|
|
22
|
+
data: values
|
|
23
|
+
};
|
|
24
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
ExecutionQuery.forCreate = forCreate;
|
|
28
|
+
function forRead(resource, key, options) {
|
|
29
|
+
if (options?.pick)
|
|
30
|
+
options.pick = normalizePick(resource, options.pick);
|
|
31
|
+
if (options?.omit)
|
|
32
|
+
options.omit = normalizePick(resource, options.omit);
|
|
33
|
+
if (options?.include)
|
|
34
|
+
options.include = normalizePick(resource, options.include);
|
|
35
|
+
checkKeyFields(resource, key);
|
|
36
|
+
const out = {
|
|
37
|
+
queryType: 'read',
|
|
38
|
+
scope: 'instance',
|
|
39
|
+
operationType: 'read',
|
|
40
|
+
resource,
|
|
41
|
+
keyValue: key
|
|
42
|
+
};
|
|
43
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
ExecutionQuery.forRead = forRead;
|
|
47
|
+
function forSearch(resource, options) {
|
|
48
|
+
if (options?.pick)
|
|
49
|
+
options.pick = normalizePick(resource, options.pick);
|
|
50
|
+
if (options?.omit)
|
|
51
|
+
options.omit = normalizePick(resource, options.omit);
|
|
52
|
+
if (options?.include)
|
|
53
|
+
options.include = normalizePick(resource, options.include);
|
|
54
|
+
if (options?.sort)
|
|
55
|
+
options.sort = normalizePick(resource, options.sort); // todo check allowed sort fields
|
|
56
|
+
const out = {
|
|
57
|
+
queryType: 'search',
|
|
58
|
+
scope: 'collection',
|
|
59
|
+
operationType: 'read',
|
|
60
|
+
resource
|
|
61
|
+
};
|
|
62
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
ExecutionQuery.forSearch = forSearch;
|
|
66
|
+
function forProperty(property, options) {
|
|
67
|
+
const out = {
|
|
68
|
+
queryType: 'read',
|
|
69
|
+
scope: 'property',
|
|
70
|
+
operationType: 'read',
|
|
71
|
+
property
|
|
72
|
+
};
|
|
73
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
ExecutionQuery.forProperty = forProperty;
|
|
77
|
+
function forUpdate(resource, keyValue, values, options) {
|
|
78
|
+
if (options?.pick)
|
|
79
|
+
options.pick = normalizePick(resource, options.pick);
|
|
80
|
+
if (options?.omit)
|
|
81
|
+
options.omit = normalizePick(resource, options.omit);
|
|
82
|
+
if (options?.include)
|
|
83
|
+
options.include = normalizePick(resource, options.include);
|
|
84
|
+
checkKeyFields(resource, keyValue);
|
|
85
|
+
const out = {
|
|
86
|
+
queryType: 'update',
|
|
87
|
+
scope: 'instance',
|
|
88
|
+
operationType: 'update',
|
|
89
|
+
resource,
|
|
90
|
+
keyValue,
|
|
91
|
+
data: values
|
|
92
|
+
};
|
|
93
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
ExecutionQuery.forUpdate = forUpdate;
|
|
97
|
+
function forUpdateMany(resource, values, options) {
|
|
98
|
+
const out = {
|
|
99
|
+
queryType: 'updateMany',
|
|
100
|
+
scope: 'collection',
|
|
101
|
+
operationType: 'update',
|
|
102
|
+
resource,
|
|
103
|
+
data: values
|
|
104
|
+
};
|
|
105
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
ExecutionQuery.forUpdateMany = forUpdateMany;
|
|
109
|
+
function forDelete(resource, key) {
|
|
110
|
+
checkKeyFields(resource, key);
|
|
111
|
+
return {
|
|
112
|
+
queryType: 'delete',
|
|
113
|
+
scope: 'instance',
|
|
114
|
+
operationType: 'delete',
|
|
115
|
+
resource,
|
|
116
|
+
keyValue: key
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
ExecutionQuery.forDelete = forDelete;
|
|
120
|
+
function forDeleteMany(resource, options) {
|
|
121
|
+
const out = {
|
|
122
|
+
queryType: 'deleteMany',
|
|
123
|
+
scope: 'collection',
|
|
124
|
+
operationType: 'delete',
|
|
125
|
+
resource,
|
|
126
|
+
};
|
|
127
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
ExecutionQuery.forDeleteMany = forDeleteMany;
|
|
131
|
+
function isCreateQuery(q) {
|
|
132
|
+
return q && typeof q === 'object' && q.scope === 'collection' && q.queryType === 'create';
|
|
133
|
+
}
|
|
134
|
+
ExecutionQuery.isCreateQuery = isCreateQuery;
|
|
135
|
+
function isSearchQuery(q) {
|
|
136
|
+
return q && typeof q === 'object' && q.scope === 'collection' && q.queryType === 'search';
|
|
137
|
+
}
|
|
138
|
+
ExecutionQuery.isSearchQuery = isSearchQuery;
|
|
139
|
+
function isReadQuery(q) {
|
|
140
|
+
return q && typeof q === 'object' && q.scope === 'instance' && q.queryType === 'read';
|
|
141
|
+
}
|
|
142
|
+
ExecutionQuery.isReadQuery = isReadQuery;
|
|
143
|
+
function isDeleteQuery(q) {
|
|
144
|
+
return q && typeof q === 'object' && q.scope === 'instance' && q.queryType === 'delete';
|
|
145
|
+
}
|
|
146
|
+
ExecutionQuery.isDeleteQuery = isDeleteQuery;
|
|
147
|
+
})(ExecutionQuery = exports.ExecutionQuery || (exports.ExecutionQuery = {}));
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
149
|
+
function checkKeyFields(resource, key) {
|
|
150
|
+
if (!resource.dataType.primaryKey)
|
|
151
|
+
throw new Error(`"${resource.name}" has no primary key`);
|
|
152
|
+
}
|
|
153
|
+
function normalizePick(resource, fields) {
|
|
154
|
+
const fieldsTree = (0, string_path_to_object_tree_js_1.stringPathToObjectTree)(fields) || {};
|
|
155
|
+
return _normalizeFieldsList([], resource.service, resource, resource.dataType, fieldsTree, '', {
|
|
156
|
+
additionalProperties: true
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function _normalizeFieldsList(target, service, resource, dataType, node, parentPath = '', options) {
|
|
160
|
+
let curPath = '';
|
|
161
|
+
for (const k of Object.keys(node)) {
|
|
162
|
+
const nodeVal = node[k];
|
|
163
|
+
const prop = dataType?.properties?.[k];
|
|
164
|
+
if (!prop) {
|
|
165
|
+
curPath = parentPath ? parentPath + '.' + k : k;
|
|
166
|
+
if (!options?.additionalProperties || (dataType && !dataType.additionalProperties))
|
|
167
|
+
throw new TypeError(`Unknown field path "${resource.name + '.' + curPath}"`);
|
|
168
|
+
if (typeof nodeVal === 'object')
|
|
169
|
+
_normalizeFieldsList(target, service, resource, undefined, nodeVal, curPath, options);
|
|
170
|
+
else
|
|
171
|
+
target.push(curPath);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
curPath = parentPath ? parentPath + '.' + prop.name : prop.name;
|
|
175
|
+
const propType = service.getDataType(prop.type || 'string');
|
|
176
|
+
if (typeof nodeVal === 'object') {
|
|
177
|
+
if (!(propType instanceof complex_type_js_1.ComplexType))
|
|
178
|
+
throw new TypeError(`"${curPath}" is not a complex type and has no sub fields`);
|
|
179
|
+
if (target.findIndex(x => x === parentPath) >= 0)
|
|
180
|
+
continue;
|
|
181
|
+
target = _normalizeFieldsList(target, service, resource, propType, nodeVal, curPath, options);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (target.findIndex(x => x.startsWith(curPath + '.')) >= 0) {
|
|
185
|
+
target = target.filter(x => !x.startsWith(curPath + '.'));
|
|
186
|
+
}
|
|
187
|
+
target.push(curPath);
|
|
188
|
+
}
|
|
189
|
+
return target;
|
|
190
|
+
}
|
package/cjs/package.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
// import { Type } from 'ts-gems';
|
|
4
|
+
// import { ComplexType } from '../implementation/data-type/complex-type.js';
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DataService = void 0;
|
|
7
|
+
class DataService {
|
|
8
|
+
}
|
|
9
|
+
exports.DataService = DataService;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JsonDataService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const rule_judgment_1 = tslib_1.__importDefault(require("rule-judgment"));
|
|
6
|
+
const data_service_js_1 = require("./data-service.js");
|
|
7
|
+
// Fix invalid importing (with ESM) of rule-judgment package
|
|
8
|
+
const toArrayFilter = typeof rule_judgment_1.default === 'function' ? rule_judgment_1.default : rule_judgment_1.default.default;
|
|
9
|
+
class JsonDataService extends data_service_js_1.DataService {
|
|
10
|
+
data;
|
|
11
|
+
constructor(args) {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.JsonDataService = JsonDataService;
|
package/cjs/types.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isInternalClass = exports.resolveClassAsync = exports.resolveClass = exports.isConstructor = void 0;
|
|
4
|
+
const knownInternalClasses = [String, Number, Boolean, Date];
|
|
5
|
+
function isConstructor(obj) {
|
|
6
|
+
return typeof obj === 'function' &&
|
|
7
|
+
!!(obj.prototype && obj.prototype.constructor);
|
|
8
|
+
}
|
|
9
|
+
exports.isConstructor = isConstructor;
|
|
10
|
+
function resolveClass(typeOrFunc) {
|
|
11
|
+
if (typeof typeOrFunc === 'function' && !isConstructor(typeOrFunc)) {
|
|
12
|
+
typeOrFunc = typeOrFunc();
|
|
13
|
+
if (isConstructor(typeOrFunc))
|
|
14
|
+
return typeOrFunc;
|
|
15
|
+
throw new TypeError(`Function must return a constructor`);
|
|
16
|
+
}
|
|
17
|
+
if (isConstructor(typeOrFunc))
|
|
18
|
+
return typeOrFunc;
|
|
19
|
+
throw new TypeError(`${typeOrFunc} is not a constructor`);
|
|
20
|
+
}
|
|
21
|
+
exports.resolveClass = resolveClass;
|
|
22
|
+
async function resolveClassAsync(typeOrFunc) {
|
|
23
|
+
if (typeof typeOrFunc === 'function' && !isConstructor(typeOrFunc)) {
|
|
24
|
+
typeOrFunc = await typeOrFunc();
|
|
25
|
+
if (isConstructor(typeOrFunc))
|
|
26
|
+
return typeOrFunc;
|
|
27
|
+
throw new TypeError(`Function must return a constructor`);
|
|
28
|
+
}
|
|
29
|
+
if (isConstructor(typeOrFunc))
|
|
30
|
+
return typeOrFunc;
|
|
31
|
+
throw new TypeError(`${typeOrFunc} is not a constructor`);
|
|
32
|
+
}
|
|
33
|
+
exports.resolveClassAsync = resolveClassAsync;
|
|
34
|
+
function isInternalClass(t) {
|
|
35
|
+
return knownInternalClasses.includes(t) || Buffer.isBuffer(t);
|
|
36
|
+
}
|
|
37
|
+
exports.isInternalClass = isInternalClass;
|