@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,169 @@
|
|
|
1
|
+
import { isPromise } from 'util/types';
|
|
2
|
+
import { DATATYPE_METADATA, DATATYPE_PROPERTIES, OpraSchema } from '@opra/schema';
|
|
3
|
+
import { RESOURCE_METADATA } from '../constants.js';
|
|
4
|
+
import { isConstructor, resolveClassAsync } from '../utils/class-utils.js';
|
|
5
|
+
import { builtinClassMap, internalDataTypes, primitiveDataTypeNames } from '../utils/internal-data-types.js';
|
|
6
|
+
const entityMethods = ['search', 'create', 'read', 'update', 'updateMany', 'delete', 'deleteMany'];
|
|
7
|
+
export class SchemaGenerator {
|
|
8
|
+
_dataTypes = {};
|
|
9
|
+
_resources = {};
|
|
10
|
+
constructor() {
|
|
11
|
+
//
|
|
12
|
+
}
|
|
13
|
+
async addDataType(thunk) {
|
|
14
|
+
let schema;
|
|
15
|
+
thunk = isPromise(thunk) ? await thunk : thunk;
|
|
16
|
+
if (typeof thunk === 'function' && !isConstructor(thunk))
|
|
17
|
+
thunk = await thunk();
|
|
18
|
+
if (!isConstructor(thunk) || OpraSchema.isDataType(thunk))
|
|
19
|
+
throw new TypeError(`Function must return a type class or type schema`);
|
|
20
|
+
if (isConstructor(thunk)) {
|
|
21
|
+
const ctor = thunk;
|
|
22
|
+
const metadata = Reflect.getOwnMetadata(DATATYPE_METADATA, ctor);
|
|
23
|
+
if (!metadata)
|
|
24
|
+
throw new TypeError(`Class "${ctor}" has no type metadata`);
|
|
25
|
+
schema = this._dataTypes[metadata.name];
|
|
26
|
+
if (schema) {
|
|
27
|
+
if (schema.kind !== metadata.kind ||
|
|
28
|
+
(OpraSchema.isComplexType(schema) && schema.ctor !== ctor))
|
|
29
|
+
throw new Error(`An other instance of "${schema.name}" data type previously defined`);
|
|
30
|
+
return schema;
|
|
31
|
+
}
|
|
32
|
+
// Add base data type
|
|
33
|
+
let base;
|
|
34
|
+
let baseCtor = Object.getPrototypeOf(ctor);
|
|
35
|
+
if (Reflect.hasMetadata(DATATYPE_METADATA, baseCtor)) {
|
|
36
|
+
while (!Reflect.hasOwnMetadata(DATATYPE_METADATA, baseCtor)) {
|
|
37
|
+
baseCtor = Object.getPrototypeOf(baseCtor);
|
|
38
|
+
}
|
|
39
|
+
const baseSchema = await this.addDataType(baseCtor);
|
|
40
|
+
base = baseSchema.name;
|
|
41
|
+
}
|
|
42
|
+
if (OpraSchema.isComplexType(metadata) || OpraSchema.isEntityType(metadata)) {
|
|
43
|
+
schema = {
|
|
44
|
+
...metadata,
|
|
45
|
+
ctor,
|
|
46
|
+
base
|
|
47
|
+
};
|
|
48
|
+
const properties = Reflect.getMetadata(DATATYPE_PROPERTIES, ctor.prototype);
|
|
49
|
+
if (properties) {
|
|
50
|
+
for (const [k, p] of Object.entries(properties)) {
|
|
51
|
+
let type;
|
|
52
|
+
if (isConstructor(p.type) && builtinClassMap.has(p.type))
|
|
53
|
+
type = builtinClassMap.get(p.type);
|
|
54
|
+
else if (typeof p.type === 'function' || typeof p.type === 'object') {
|
|
55
|
+
const t = await this.addDataType(p.type);
|
|
56
|
+
type = t.name;
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
type = p.type || 'string';
|
|
60
|
+
if (internalDataTypes.has(type) && !this._dataTypes[type])
|
|
61
|
+
this._dataTypes[type] = internalDataTypes.get(type.toLowerCase());
|
|
62
|
+
schema.properties = schema.properties || {};
|
|
63
|
+
schema.properties[k] = { ...p, type };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (OpraSchema.isSimpleType(metadata)) {
|
|
68
|
+
if (!primitiveDataTypeNames.includes(metadata.type))
|
|
69
|
+
throw new Error(`"type" of SimpleType schema must be one of enumerated value (${primitiveDataTypeNames})`);
|
|
70
|
+
schema = {
|
|
71
|
+
...metadata
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
else
|
|
75
|
+
/* istanbul ignore next */
|
|
76
|
+
throw new TypeError(`Invalid metadata`);
|
|
77
|
+
}
|
|
78
|
+
else if (OpraSchema.isDataType(thunk)) {
|
|
79
|
+
schema = thunk;
|
|
80
|
+
}
|
|
81
|
+
else
|
|
82
|
+
throw new TypeError(`Invalid data type schema`);
|
|
83
|
+
this._dataTypes[schema.name] = schema;
|
|
84
|
+
return schema;
|
|
85
|
+
}
|
|
86
|
+
async addResource(instance) {
|
|
87
|
+
if (isConstructor(instance))
|
|
88
|
+
throw new Error(`You should provide Resource instance instead of Resource class`);
|
|
89
|
+
const proto = Object.getPrototypeOf(instance);
|
|
90
|
+
const ctor = proto.constructor;
|
|
91
|
+
const metadata = Reflect.getMetadata(RESOURCE_METADATA, ctor);
|
|
92
|
+
let resourceSchema;
|
|
93
|
+
if (metadata) {
|
|
94
|
+
const name = metadata.name || ctor.name.replace(/Resource$/, '');
|
|
95
|
+
const t = typeof metadata.type === 'function'
|
|
96
|
+
? await resolveClassAsync(metadata.type)
|
|
97
|
+
: metadata.type;
|
|
98
|
+
const type = typeof t === 'function'
|
|
99
|
+
? (await this.addDataType(t)).name
|
|
100
|
+
: t;
|
|
101
|
+
resourceSchema = {
|
|
102
|
+
...metadata,
|
|
103
|
+
type,
|
|
104
|
+
name
|
|
105
|
+
};
|
|
106
|
+
if (OpraSchema.isEntityResource(resourceSchema)) {
|
|
107
|
+
for (const methodName of entityMethods) {
|
|
108
|
+
const fn = instance[methodName];
|
|
109
|
+
if (typeof fn === 'function') {
|
|
110
|
+
resourceSchema[methodName] = fn.bind(instance);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else
|
|
116
|
+
resourceSchema = instance;
|
|
117
|
+
if (OpraSchema.isResource(resourceSchema)) {
|
|
118
|
+
if (OpraSchema.isEntityResource(resourceSchema)) {
|
|
119
|
+
const t = this._dataTypes[resourceSchema.type];
|
|
120
|
+
if (!t)
|
|
121
|
+
throw new Error(`Resource registration error. Type "${resourceSchema.type}" not found.`);
|
|
122
|
+
if (this._resources[resourceSchema.name])
|
|
123
|
+
throw new Error(`An other instance of "${resourceSchema.name}" resource previously defined`);
|
|
124
|
+
this._resources[resourceSchema.name] = resourceSchema;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
throw new Error(`Invalid resource metadata`);
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`Invalid resource object`);
|
|
130
|
+
}
|
|
131
|
+
static async generateDocumentSchema(args) {
|
|
132
|
+
const generator = new SchemaGenerator();
|
|
133
|
+
if (args.types) {
|
|
134
|
+
for (const thunk of args.types) {
|
|
135
|
+
await generator.addDataType(thunk);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const types = Object.keys(generator._dataTypes).sort()
|
|
139
|
+
.map(name => generator._dataTypes[name]);
|
|
140
|
+
return {
|
|
141
|
+
version: '1',
|
|
142
|
+
...args,
|
|
143
|
+
types
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
static async generateServiceSchema(args) {
|
|
147
|
+
const generator = new SchemaGenerator();
|
|
148
|
+
if (args.types) {
|
|
149
|
+
for (const thunk of args.types) {
|
|
150
|
+
await generator.addDataType(thunk);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (args.resources) {
|
|
154
|
+
for (const resource of args.resources) {
|
|
155
|
+
await generator.addResource(resource);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const types = Object.keys(generator._dataTypes).sort()
|
|
159
|
+
.map(name => generator._dataTypes[name]);
|
|
160
|
+
const resources = Object.keys(generator._resources).sort()
|
|
161
|
+
.map(name => generator._resources[name]);
|
|
162
|
+
return {
|
|
163
|
+
version: '1',
|
|
164
|
+
...args,
|
|
165
|
+
types,
|
|
166
|
+
resources
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
export * from './constants.js';
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './enums/index.js';
|
|
5
|
+
export * from './exception/index.js';
|
|
6
|
+
export * from './decorators/entity-resource.decorator.js';
|
|
7
|
+
export * from './interfaces/http-context.interface.js';
|
|
8
|
+
export * from './interfaces/execution-query.interface.js';
|
|
9
|
+
export * from './interfaces/entity-resource.interface.js';
|
|
10
|
+
export * from './interfaces/resource-container.interface.js';
|
|
11
|
+
export * from './implementation/execution-context.js';
|
|
12
|
+
export * from './implementation/opra-document.js';
|
|
13
|
+
export * from './implementation/opra-service.js';
|
|
14
|
+
export * from './implementation/schema-generator.js';
|
|
15
|
+
export * from './implementation/adapter/adapter.js';
|
|
16
|
+
export * from './implementation/adapter/express-adapter.js';
|
|
17
|
+
export * from './implementation/data-type/data-type.js';
|
|
18
|
+
export * from './implementation/data-type/complex-type.js';
|
|
19
|
+
export * from './implementation/data-type/simple-type.js';
|
|
20
|
+
export * from './implementation/resource/resource-info.js';
|
|
21
|
+
export * from './implementation/resource/entity-resource-info.js';
|
|
22
|
+
export * from './services/json-data-service.js';
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
export * from './constants.js';
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './enums/index.js';
|
|
5
|
+
export * from './exception/index.js';
|
|
6
|
+
export * from './decorators/entity-resource.decorator.js';
|
|
7
|
+
export * from './interfaces/http-context.interface.js';
|
|
8
|
+
export * from './interfaces/execution-query.interface.js';
|
|
9
|
+
export * from './interfaces/entity-resource.interface.js';
|
|
10
|
+
export * from './interfaces/resource-container.interface.js';
|
|
11
|
+
export * from './implementation/execution-context.js';
|
|
12
|
+
export * from './implementation/opra-document.js';
|
|
13
|
+
export * from './implementation/opra-service.js';
|
|
14
|
+
export * from './implementation/schema-generator.js';
|
|
15
|
+
export * from './implementation/adapter/adapter.js';
|
|
16
|
+
export * from './implementation/adapter/express-adapter.js';
|
|
17
|
+
export * from './implementation/data-type/data-type.js';
|
|
18
|
+
export * from './implementation/data-type/complex-type.js';
|
|
19
|
+
export * from './implementation/data-type/simple-type.js';
|
|
20
|
+
export * from './implementation/resource/resource-info.js';
|
|
21
|
+
export * from './implementation/resource/entity-resource-info.js';
|
|
22
|
+
export * from './services/json-data-service.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface IEntityResource {
|
|
2
|
+
search?(...args: any[]): any;
|
|
3
|
+
read?(...args: any[]): any;
|
|
4
|
+
create?(...args: any[]): any;
|
|
5
|
+
update?(...args: any[]): any;
|
|
6
|
+
updateMany?(...args: any[]): any;
|
|
7
|
+
delete?(...args: any[]): any;
|
|
8
|
+
deleteMany?(...args: any[]): any;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { StrictOmit } from 'ts-gems';
|
|
2
|
+
import { OpraSchema } from '@opra/schema';
|
|
3
|
+
import { Expression } from '@opra/url';
|
|
4
|
+
import { EntityResourceInfo } from '../implementation/resource/entity-resource-info.js';
|
|
5
|
+
import { KeyValue, OperationType, QueryScope, QueryType } from '../types.js';
|
|
6
|
+
export declare type ExecutionQuery = CreateQuery | ReadQuery | SearchQuery | UpdateQuery | UpdateManyQuery | DeleteQuery | DeleteManyQuery;
|
|
7
|
+
interface BaseQuery {
|
|
8
|
+
queryType: QueryType;
|
|
9
|
+
scope: QueryScope;
|
|
10
|
+
operationType: OperationType;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateQuery extends BaseQuery {
|
|
13
|
+
queryType: 'create';
|
|
14
|
+
scope: 'collection';
|
|
15
|
+
operationType: 'create';
|
|
16
|
+
resource: EntityResourceInfo;
|
|
17
|
+
data: {};
|
|
18
|
+
pick?: string[];
|
|
19
|
+
omit?: string[];
|
|
20
|
+
include?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface ReadQuery extends BaseQuery {
|
|
23
|
+
queryType: 'read';
|
|
24
|
+
scope: 'instance';
|
|
25
|
+
operationType: 'read';
|
|
26
|
+
resource: EntityResourceInfo;
|
|
27
|
+
keyValue: KeyValue;
|
|
28
|
+
pick?: string[];
|
|
29
|
+
omit?: string[];
|
|
30
|
+
include?: string[];
|
|
31
|
+
nested?: PropertyQuery;
|
|
32
|
+
}
|
|
33
|
+
export interface PropertyQuery extends BaseQuery {
|
|
34
|
+
queryType: 'read';
|
|
35
|
+
scope: 'property';
|
|
36
|
+
operationType: 'read';
|
|
37
|
+
property: OpraSchema.Property;
|
|
38
|
+
nested?: PropertyQuery;
|
|
39
|
+
}
|
|
40
|
+
export interface UpdateQuery extends BaseQuery {
|
|
41
|
+
queryType: 'update';
|
|
42
|
+
scope: 'instance';
|
|
43
|
+
operationType: 'update';
|
|
44
|
+
resource: EntityResourceInfo;
|
|
45
|
+
keyValue: KeyValue;
|
|
46
|
+
data: {};
|
|
47
|
+
pick?: string[];
|
|
48
|
+
omit?: string[];
|
|
49
|
+
include?: string[];
|
|
50
|
+
}
|
|
51
|
+
export interface UpdateManyQuery extends BaseQuery {
|
|
52
|
+
queryType: 'updateMany';
|
|
53
|
+
scope: 'collection';
|
|
54
|
+
operationType: 'update';
|
|
55
|
+
resource: EntityResourceInfo;
|
|
56
|
+
filter?: string | Expression;
|
|
57
|
+
data: {};
|
|
58
|
+
}
|
|
59
|
+
export interface DeleteQuery extends BaseQuery {
|
|
60
|
+
queryType: 'delete';
|
|
61
|
+
scope: 'instance';
|
|
62
|
+
operationType: 'delete';
|
|
63
|
+
resource: EntityResourceInfo;
|
|
64
|
+
keyValue: KeyValue;
|
|
65
|
+
}
|
|
66
|
+
export interface DeleteManyQuery extends BaseQuery {
|
|
67
|
+
queryType: 'deleteMany';
|
|
68
|
+
scope: 'collection';
|
|
69
|
+
operationType: 'delete';
|
|
70
|
+
resource: EntityResourceInfo;
|
|
71
|
+
filter?: string | Expression;
|
|
72
|
+
}
|
|
73
|
+
export interface SearchQuery extends BaseQuery {
|
|
74
|
+
queryType: 'search';
|
|
75
|
+
scope: 'collection';
|
|
76
|
+
operationType: 'read';
|
|
77
|
+
resource: EntityResourceInfo;
|
|
78
|
+
pick?: string[];
|
|
79
|
+
omit?: string[];
|
|
80
|
+
include?: string[];
|
|
81
|
+
filter?: string | Expression;
|
|
82
|
+
limit?: number;
|
|
83
|
+
skip?: number;
|
|
84
|
+
distinct?: boolean;
|
|
85
|
+
total?: boolean;
|
|
86
|
+
sort?: string[];
|
|
87
|
+
}
|
|
88
|
+
export declare namespace ExecutionQuery {
|
|
89
|
+
function forCreate(resource: EntityResourceInfo, values: {}, options?: StrictOmit<CreateQuery, 'queryType' | 'scope' | 'operationType' | 'resource' | 'data'>): CreateQuery;
|
|
90
|
+
function forRead(resource: EntityResourceInfo, key: KeyValue, options?: StrictOmit<ReadQuery, 'queryType' | 'scope' | 'operationType' | 'resource' | 'keyValue'>): ReadQuery;
|
|
91
|
+
function forSearch(resource: EntityResourceInfo, options?: StrictOmit<SearchQuery, 'queryType' | 'scope' | 'operationType' | 'resource'>): SearchQuery;
|
|
92
|
+
function forProperty(property: OpraSchema.Property, options?: StrictOmit<PropertyQuery, 'queryType' | 'scope' | 'operationType' | 'property'>): PropertyQuery;
|
|
93
|
+
function forUpdate(resource: EntityResourceInfo, keyValue: KeyValue, values: any, options?: StrictOmit<UpdateQuery, 'queryType' | 'scope' | 'operationType' | 'resource' | 'keyValue' | 'data'>): UpdateQuery;
|
|
94
|
+
function forUpdateMany(resource: EntityResourceInfo, values: any, options?: StrictOmit<UpdateManyQuery, 'queryType' | 'scope' | 'operationType' | 'resource' | 'data'>): UpdateManyQuery;
|
|
95
|
+
function forDelete(resource: EntityResourceInfo, key: KeyValue): DeleteQuery;
|
|
96
|
+
function forDeleteMany(resource: EntityResourceInfo, options?: StrictOmit<DeleteManyQuery, 'queryType' | 'scope' | 'operationType' | 'resource'>): DeleteManyQuery;
|
|
97
|
+
function isCreateQuery(q: any): q is CreateQuery;
|
|
98
|
+
function isSearchQuery(q: any): q is SearchQuery;
|
|
99
|
+
function isReadQuery(q: any): q is ReadQuery;
|
|
100
|
+
function isDeleteQuery(q: any): q is DeleteQuery;
|
|
101
|
+
}
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { ComplexType } from '../implementation/data-type/complex-type.js';
|
|
3
|
+
import { stringPathToObjectTree } from '../utils/string-path-to-object-tree.js';
|
|
4
|
+
export var ExecutionQuery;
|
|
5
|
+
(function (ExecutionQuery) {
|
|
6
|
+
function forCreate(resource, values, options) {
|
|
7
|
+
if (options?.pick)
|
|
8
|
+
options.pick = normalizePick(resource, options.pick);
|
|
9
|
+
if (options?.omit)
|
|
10
|
+
options.omit = normalizePick(resource, options.omit);
|
|
11
|
+
if (options?.include)
|
|
12
|
+
options.include = normalizePick(resource, options.include);
|
|
13
|
+
const out = {
|
|
14
|
+
queryType: 'create',
|
|
15
|
+
scope: 'collection',
|
|
16
|
+
operationType: 'create',
|
|
17
|
+
resource,
|
|
18
|
+
data: values
|
|
19
|
+
};
|
|
20
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
ExecutionQuery.forCreate = forCreate;
|
|
24
|
+
function forRead(resource, key, options) {
|
|
25
|
+
if (options?.pick)
|
|
26
|
+
options.pick = normalizePick(resource, options.pick);
|
|
27
|
+
if (options?.omit)
|
|
28
|
+
options.omit = normalizePick(resource, options.omit);
|
|
29
|
+
if (options?.include)
|
|
30
|
+
options.include = normalizePick(resource, options.include);
|
|
31
|
+
checkKeyFields(resource, key);
|
|
32
|
+
const out = {
|
|
33
|
+
queryType: 'read',
|
|
34
|
+
scope: 'instance',
|
|
35
|
+
operationType: 'read',
|
|
36
|
+
resource,
|
|
37
|
+
keyValue: key
|
|
38
|
+
};
|
|
39
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
ExecutionQuery.forRead = forRead;
|
|
43
|
+
function forSearch(resource, options) {
|
|
44
|
+
if (options?.pick)
|
|
45
|
+
options.pick = normalizePick(resource, options.pick);
|
|
46
|
+
if (options?.omit)
|
|
47
|
+
options.omit = normalizePick(resource, options.omit);
|
|
48
|
+
if (options?.include)
|
|
49
|
+
options.include = normalizePick(resource, options.include);
|
|
50
|
+
if (options?.sort)
|
|
51
|
+
options.sort = normalizePick(resource, options.sort); // todo check allowed sort fields
|
|
52
|
+
const out = {
|
|
53
|
+
queryType: 'search',
|
|
54
|
+
scope: 'collection',
|
|
55
|
+
operationType: 'read',
|
|
56
|
+
resource
|
|
57
|
+
};
|
|
58
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
ExecutionQuery.forSearch = forSearch;
|
|
62
|
+
function forProperty(property, options) {
|
|
63
|
+
const out = {
|
|
64
|
+
queryType: 'read',
|
|
65
|
+
scope: 'property',
|
|
66
|
+
operationType: 'read',
|
|
67
|
+
property
|
|
68
|
+
};
|
|
69
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
ExecutionQuery.forProperty = forProperty;
|
|
73
|
+
function forUpdate(resource, keyValue, values, options) {
|
|
74
|
+
if (options?.pick)
|
|
75
|
+
options.pick = normalizePick(resource, options.pick);
|
|
76
|
+
if (options?.omit)
|
|
77
|
+
options.omit = normalizePick(resource, options.omit);
|
|
78
|
+
if (options?.include)
|
|
79
|
+
options.include = normalizePick(resource, options.include);
|
|
80
|
+
checkKeyFields(resource, keyValue);
|
|
81
|
+
const out = {
|
|
82
|
+
queryType: 'update',
|
|
83
|
+
scope: 'instance',
|
|
84
|
+
operationType: 'update',
|
|
85
|
+
resource,
|
|
86
|
+
keyValue,
|
|
87
|
+
data: values
|
|
88
|
+
};
|
|
89
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
ExecutionQuery.forUpdate = forUpdate;
|
|
93
|
+
function forUpdateMany(resource, values, options) {
|
|
94
|
+
const out = {
|
|
95
|
+
queryType: 'updateMany',
|
|
96
|
+
scope: 'collection',
|
|
97
|
+
operationType: 'update',
|
|
98
|
+
resource,
|
|
99
|
+
data: values
|
|
100
|
+
};
|
|
101
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
ExecutionQuery.forUpdateMany = forUpdateMany;
|
|
105
|
+
function forDelete(resource, key) {
|
|
106
|
+
checkKeyFields(resource, key);
|
|
107
|
+
return {
|
|
108
|
+
queryType: 'delete',
|
|
109
|
+
scope: 'instance',
|
|
110
|
+
operationType: 'delete',
|
|
111
|
+
resource,
|
|
112
|
+
keyValue: key
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
ExecutionQuery.forDelete = forDelete;
|
|
116
|
+
function forDeleteMany(resource, options) {
|
|
117
|
+
const out = {
|
|
118
|
+
queryType: 'deleteMany',
|
|
119
|
+
scope: 'collection',
|
|
120
|
+
operationType: 'delete',
|
|
121
|
+
resource,
|
|
122
|
+
};
|
|
123
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
ExecutionQuery.forDeleteMany = forDeleteMany;
|
|
127
|
+
function isCreateQuery(q) {
|
|
128
|
+
return q && typeof q === 'object' && q.scope === 'collection' && q.queryType === 'create';
|
|
129
|
+
}
|
|
130
|
+
ExecutionQuery.isCreateQuery = isCreateQuery;
|
|
131
|
+
function isSearchQuery(q) {
|
|
132
|
+
return q && typeof q === 'object' && q.scope === 'collection' && q.queryType === 'search';
|
|
133
|
+
}
|
|
134
|
+
ExecutionQuery.isSearchQuery = isSearchQuery;
|
|
135
|
+
function isReadQuery(q) {
|
|
136
|
+
return q && typeof q === 'object' && q.scope === 'instance' && q.queryType === 'read';
|
|
137
|
+
}
|
|
138
|
+
ExecutionQuery.isReadQuery = isReadQuery;
|
|
139
|
+
function isDeleteQuery(q) {
|
|
140
|
+
return q && typeof q === 'object' && q.scope === 'instance' && q.queryType === 'delete';
|
|
141
|
+
}
|
|
142
|
+
ExecutionQuery.isDeleteQuery = isDeleteQuery;
|
|
143
|
+
})(ExecutionQuery || (ExecutionQuery = {}));
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
145
|
+
function checkKeyFields(resource, key) {
|
|
146
|
+
if (!resource.dataType.primaryKey)
|
|
147
|
+
throw new Error(`"${resource.name}" has no primary key`);
|
|
148
|
+
}
|
|
149
|
+
function normalizePick(resource, fields) {
|
|
150
|
+
const fieldsTree = stringPathToObjectTree(fields) || {};
|
|
151
|
+
return _normalizeFieldsList([], resource.service, resource, resource.dataType, fieldsTree, '', {
|
|
152
|
+
additionalProperties: true
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function _normalizeFieldsList(target, service, resource, dataType, node, parentPath = '', options) {
|
|
156
|
+
let curPath = '';
|
|
157
|
+
for (const k of Object.keys(node)) {
|
|
158
|
+
const nodeVal = node[k];
|
|
159
|
+
const prop = dataType?.properties?.[k];
|
|
160
|
+
if (!prop) {
|
|
161
|
+
curPath = parentPath ? parentPath + '.' + k : k;
|
|
162
|
+
if (!options?.additionalProperties || (dataType && !dataType.additionalProperties))
|
|
163
|
+
throw new TypeError(`Unknown field path "${resource.name + '.' + curPath}"`);
|
|
164
|
+
if (typeof nodeVal === 'object')
|
|
165
|
+
_normalizeFieldsList(target, service, resource, undefined, nodeVal, curPath, options);
|
|
166
|
+
else
|
|
167
|
+
target.push(curPath);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
curPath = parentPath ? parentPath + '.' + prop.name : prop.name;
|
|
171
|
+
const propType = service.getDataType(prop.type || 'string');
|
|
172
|
+
if (typeof nodeVal === 'object') {
|
|
173
|
+
if (!(propType instanceof ComplexType))
|
|
174
|
+
throw new TypeError(`"${curPath}" is not a complex type and has no sub fields`);
|
|
175
|
+
if (target.findIndex(x => x === parentPath) >= 0)
|
|
176
|
+
continue;
|
|
177
|
+
target = _normalizeFieldsList(target, service, resource, propType, nodeVal, curPath, options);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (target.findIndex(x => x.startsWith(curPath + '.')) >= 0) {
|
|
181
|
+
target = target.filter(x => !x.startsWith(curPath + '.'));
|
|
182
|
+
}
|
|
183
|
+
target.push(curPath);
|
|
184
|
+
}
|
|
185
|
+
return target;
|
|
186
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface IHttpAdapterContext {
|
|
2
|
+
getRequest(): IHttpRequest;
|
|
3
|
+
getResponse(): IHttpResponse;
|
|
4
|
+
}
|
|
5
|
+
export interface IHttpRequest {
|
|
6
|
+
getInstance(): any;
|
|
7
|
+
getUrl(): string;
|
|
8
|
+
getMethod(): string;
|
|
9
|
+
getHeaderNames(): string[];
|
|
10
|
+
getHeader(name: string): string | undefined;
|
|
11
|
+
getHeaders(): Record<string, any>;
|
|
12
|
+
getBody(): any;
|
|
13
|
+
}
|
|
14
|
+
export interface IHttpResponse {
|
|
15
|
+
getInstance(): any;
|
|
16
|
+
getStatus(): number | undefined;
|
|
17
|
+
setStatus(value: number): this;
|
|
18
|
+
getHeaderNames(name: string): string[];
|
|
19
|
+
getHeader(name: string): string | undefined;
|
|
20
|
+
setHeader(name: string, value: string): this;
|
|
21
|
+
send(body: any): this;
|
|
22
|
+
end(): this;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { StrictOmit } from 'ts-gems';
|
|
2
|
+
import { OpraSchema } from '@opra/schema';
|
|
3
|
+
import { TypeThunkAsync } from '../types.js';
|
|
4
|
+
export declare type EntityResourceMetadata = StrictOmit<OpraSchema.EntityResource, 'type' | 'name'> & {
|
|
5
|
+
type: TypeThunkAsync | string;
|
|
6
|
+
name?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare type ResourceReadOperationMetadata = StrictOmit<OpraSchema.ResourceReadOperation, 'handler'>;
|
|
9
|
+
export declare type ResourceSearchOperationMetadata = StrictOmit<OpraSchema.ResourceSearchOperation, 'handler'>;
|
|
10
|
+
export declare type ResourceCreateOperationMetadata = StrictOmit<OpraSchema.ResourceCreateOperation, 'handler'>;
|
|
11
|
+
export declare type ResourceUpdateOperationMetadata = StrictOmit<OpraSchema.ResourceUpdateOperation, 'handler'>;
|
|
12
|
+
export declare type ResourcePatchOperationMetadata = StrictOmit<OpraSchema.ResourcePatchOperation, 'handler'>;
|
|
13
|
+
export declare type ResourceDeleteOperationMetadata = StrictOmit<OpraSchema.ResourceDeleteOperation, 'handler'>;
|
|
14
|
+
export declare type ResourceExecuteOperationMetadata = StrictOmit<OpraSchema.ResourceExecuteOperation, 'handler'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EntityResourceInfo } from '../implementation/resource/entity-resource-info.js';
|
|
2
|
+
import { ResourceInfo } from '../implementation/resource/resource-info.js';
|
|
3
|
+
export interface IResourceContainer {
|
|
4
|
+
getResource<T extends ResourceInfo>(name: string): T;
|
|
5
|
+
getEntityResource(name: string): EntityResourceInfo;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import ruleJudgment from 'rule-judgment';
|
|
2
|
+
import { DataService } from './data-service.js';
|
|
3
|
+
// Fix invalid importing (with ESM) of rule-judgment package
|
|
4
|
+
const toArrayFilter = typeof ruleJudgment === 'function' ? ruleJudgment : ruleJudgment.default;
|
|
5
|
+
export class JsonDataService extends DataService {
|
|
6
|
+
data;
|
|
7
|
+
constructor(args) {
|
|
8
|
+
super();
|
|
9
|
+
}
|
|
10
|
+
}
|
package/esm/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DeepPartial, DeepPickJson, DeepPickWritable, Type } from 'ts-gems';
|
|
2
|
+
export declare type Thunk<T> = T | (() => T);
|
|
3
|
+
export declare type ThunkAsync<T> = T | Promise<T> | (() => T) | (() => Promise<T>);
|
|
4
|
+
export declare type TypeThunk<T = any> = Thunk<Type<T>>;
|
|
5
|
+
export declare type TypeThunkAsync<T = any> = ThunkAsync<Type<T>>;
|
|
6
|
+
export declare type QueryScope = 'collection' | 'instance' | 'property';
|
|
7
|
+
export declare type QueryType = 'create' | 'read' | 'update' | 'patch' | 'delete' | 'execute' | 'search' | 'updateMany' | 'patchMany' | 'deleteMany';
|
|
8
|
+
export declare type OperationType = 'create' | 'read' | 'update' | 'patch' | 'delete' | 'execute';
|
|
9
|
+
export declare type KeyValue = string | number | boolean | object;
|
|
10
|
+
export declare type PartialInput<T> = DeepPartial<DeepPickWritable<DeepPickJson<T>>>;
|
|
11
|
+
export declare type PartialOutput<T> = DeepPartial<DeepPickJson<T>>;
|
package/esm/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Type } from 'ts-gems';
|
|
2
|
+
import { TypeThunk, TypeThunkAsync } from '../types.js';
|
|
3
|
+
export declare function isConstructor(obj: any): obj is Type;
|
|
4
|
+
export declare function resolveClass<T>(typeOrFunc: TypeThunk<T>): Type<T>;
|
|
5
|
+
export declare function resolveClassAsync<T>(typeOrFunc: TypeThunkAsync<T>): Promise<Type<T>>;
|
|
6
|
+
export declare function isInternalClass(t: any): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const knownInternalClasses = [String, Number, Boolean, Date];
|
|
2
|
+
export function isConstructor(obj) {
|
|
3
|
+
return typeof obj === 'function' &&
|
|
4
|
+
!!(obj.prototype && obj.prototype.constructor);
|
|
5
|
+
}
|
|
6
|
+
export function resolveClass(typeOrFunc) {
|
|
7
|
+
if (typeof typeOrFunc === 'function' && !isConstructor(typeOrFunc)) {
|
|
8
|
+
typeOrFunc = typeOrFunc();
|
|
9
|
+
if (isConstructor(typeOrFunc))
|
|
10
|
+
return typeOrFunc;
|
|
11
|
+
throw new TypeError(`Function must return a constructor`);
|
|
12
|
+
}
|
|
13
|
+
if (isConstructor(typeOrFunc))
|
|
14
|
+
return typeOrFunc;
|
|
15
|
+
throw new TypeError(`${typeOrFunc} is not a constructor`);
|
|
16
|
+
}
|
|
17
|
+
export async function resolveClassAsync(typeOrFunc) {
|
|
18
|
+
if (typeof typeOrFunc === 'function' && !isConstructor(typeOrFunc)) {
|
|
19
|
+
typeOrFunc = await typeOrFunc();
|
|
20
|
+
if (isConstructor(typeOrFunc))
|
|
21
|
+
return typeOrFunc;
|
|
22
|
+
throw new TypeError(`Function must return a constructor`);
|
|
23
|
+
}
|
|
24
|
+
if (isConstructor(typeOrFunc))
|
|
25
|
+
return typeOrFunc;
|
|
26
|
+
throw new TypeError(`${typeOrFunc} is not a constructor`);
|
|
27
|
+
}
|
|
28
|
+
export function isInternalClass(t) {
|
|
29
|
+
return knownInternalClasses.includes(t) || Buffer.isBuffer(t);
|
|
30
|
+
}
|