@opra/core 0.0.13 → 0.1.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/cjs/enums/http-headers.enum.js +2 -1
- package/cjs/implementation/adapter-utils/entity-resource-execute.util.js +84 -0
- package/cjs/implementation/adapter-utils/resource-execute.util.js +11 -0
- package/cjs/implementation/adapter-utils/resource-prepare.util.js +11 -0
- package/cjs/implementation/{adapter/adapter.js → adapter.js} +21 -18
- package/cjs/implementation/{adapter/express-adapter.js → express-adapter.js} +0 -0
- package/cjs/implementation/{adapter/http-adapter.js → http-adapter.js} +26 -24
- package/cjs/implementation/query-context.js +5 -3
- package/cjs/index.js +5 -15
- package/cjs/{services/entity-resource-controller.js → interfaces/entity-service.interface.js} +0 -0
- package/cjs/interfaces/query.interface.js +10 -10
- package/cjs/services/json-data-service.js +11 -5
- package/cjs/utils/{string-path-to-object-tree.js → path-to-tree.js} +3 -3
- package/esm/enums/http-headers.enum.d.ts +2 -1
- package/esm/enums/http-headers.enum.js +2 -1
- package/esm/implementation/adapter-utils/entity-resource-execute.util.d.ts +3 -0
- package/esm/implementation/adapter-utils/entity-resource-execute.util.js +80 -0
- package/esm/implementation/adapter-utils/resource-execute.util.d.ts +3 -0
- package/esm/implementation/adapter-utils/resource-execute.util.js +7 -0
- package/esm/implementation/adapter-utils/resource-prepare.util.d.ts +3 -0
- package/esm/implementation/adapter-utils/resource-prepare.util.js +7 -0
- package/esm/implementation/{adapter/adapter.d.ts → adapter.d.ts} +5 -5
- package/esm/implementation/{adapter/adapter.js → adapter.js} +18 -15
- package/esm/implementation/{adapter/express-adapter.d.ts → express-adapter.d.ts} +2 -2
- package/esm/implementation/{adapter/express-adapter.js → express-adapter.js} +0 -0
- package/esm/implementation/{adapter/http-adapter.d.ts → http-adapter.d.ts} +6 -7
- package/esm/implementation/{adapter/http-adapter.js → http-adapter.js} +25 -23
- package/esm/implementation/query-context.d.ts +3 -4
- package/esm/implementation/query-context.js +5 -3
- package/esm/index.d.ts +5 -15
- package/esm/index.js +5 -15
- package/esm/{services/entity-resource-controller.d.ts → interfaces/entity-service.interface.d.ts} +0 -0
- package/esm/{services/entity-resource-controller.js → interfaces/entity-service.interface.js} +0 -0
- package/esm/interfaces/query.interface.d.ts +25 -26
- package/esm/interfaces/query.interface.js +10 -10
- package/esm/services/json-data-service.d.ts +2 -2
- package/esm/services/json-data-service.js +11 -5
- package/esm/types.d.ts +1 -8
- package/esm/utils/create-i18n.d.ts +1 -1
- package/esm/utils/path-to-tree.d.ts +4 -0
- package/esm/utils/{string-path-to-object-tree.js → path-to-tree.js} +1 -1
- package/package.json +6 -6
- package/cjs/constants.js +0 -6
- package/cjs/decorators/api-entity-resource.decorator.js +0 -24
- package/cjs/decorators/api-resolver.decorator.js +0 -13
- package/cjs/implementation/data-type/complex-type.js +0 -53
- package/cjs/implementation/data-type/data-type.js +0 -47
- package/cjs/implementation/data-type/entity-type.js +0 -34
- package/cjs/implementation/data-type/simple-type.js +0 -30
- package/cjs/implementation/opra-document.js +0 -112
- package/cjs/implementation/opra-service.js +0 -81
- package/cjs/implementation/resource/container-resource-handler.js +0 -30
- package/cjs/implementation/resource/entity-resource-handler.js +0 -103
- package/cjs/implementation/resource/resource-handler.js +0 -45
- package/cjs/implementation/schema-generator.js +0 -184
- package/cjs/interfaces/metadata/api-resolver.metadata.js +0 -2
- package/cjs/interfaces/metadata/opra-schema.metadata.js +0 -11
- package/cjs/interfaces/resource-container.interface.js +0 -2
- package/cjs/utils/class-utils.js +0 -37
- package/cjs/utils/headers.js +0 -58
- package/cjs/utils/internal-data-types.js +0 -81
- package/cjs/utils/responsive-object.js +0 -49
- package/cjs/utils/terminal-utils.js +0 -7
- package/esm/constants.d.ts +0 -3
- package/esm/constants.js +0 -3
- package/esm/decorators/api-entity-resource.decorator.d.ts +0 -5
- package/esm/decorators/api-entity-resource.decorator.js +0 -19
- package/esm/decorators/api-resolver.decorator.d.ts +0 -2
- package/esm/decorators/api-resolver.decorator.js +0 -9
- package/esm/implementation/data-type/complex-type.d.ts +0 -19
- package/esm/implementation/data-type/complex-type.js +0 -48
- package/esm/implementation/data-type/data-type.d.ts +0 -17
- package/esm/implementation/data-type/data-type.js +0 -43
- package/esm/implementation/data-type/entity-type.d.ts +0 -10
- package/esm/implementation/data-type/entity-type.js +0 -29
- package/esm/implementation/data-type/simple-type.d.ts +0 -15
- package/esm/implementation/data-type/simple-type.js +0 -26
- package/esm/implementation/opra-document.d.ts +0 -26
- package/esm/implementation/opra-document.js +0 -107
- package/esm/implementation/opra-service.d.ts +0 -20
- package/esm/implementation/opra-service.js +0 -76
- package/esm/implementation/resource/container-resource-handler.d.ts +0 -14
- package/esm/implementation/resource/container-resource-handler.js +0 -26
- package/esm/implementation/resource/entity-resource-handler.d.ts +0 -18
- package/esm/implementation/resource/entity-resource-handler.js +0 -98
- package/esm/implementation/resource/resource-handler.d.ts +0 -15
- package/esm/implementation/resource/resource-handler.js +0 -40
- package/esm/implementation/schema-generator.d.ts +0 -21
- package/esm/implementation/schema-generator.js +0 -180
- package/esm/interfaces/metadata/api-resolver.metadata.d.ts +0 -3
- package/esm/interfaces/metadata/api-resolver.metadata.js +0 -1
- package/esm/interfaces/metadata/opra-schema.metadata.d.ts +0 -7
- package/esm/interfaces/metadata/opra-schema.metadata.js +0 -10
- package/esm/interfaces/resource-container.interface.d.ts +0 -6
- package/esm/interfaces/resource-container.interface.js +0 -1
- package/esm/utils/class-utils.d.ts +0 -6
- package/esm/utils/class-utils.js +0 -30
- package/esm/utils/headers.d.ts +0 -9
- package/esm/utils/headers.js +0 -55
- package/esm/utils/internal-data-types.d.ts +0 -5
- package/esm/utils/internal-data-types.js +0 -78
- package/esm/utils/responsive-object.d.ts +0 -3
- package/esm/utils/responsive-object.js +0 -45
- package/esm/utils/string-path-to-object-tree.d.ts +0 -4
- package/esm/utils/terminal-utils.d.ts +0 -4
- package/esm/utils/terminal-utils.js +0 -4
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { translate } from '@opra/i18n';
|
|
2
|
+
import { ComplexType } from '@opra/schema';
|
|
3
|
+
import { HttpHeaders } from '../../enums/index.js';
|
|
4
|
+
import { ForbiddenError, ResourceNotFoundError } from '../../exception/index.js';
|
|
5
|
+
import { OpraQuery } from '../../interfaces/query.interface.js';
|
|
6
|
+
export async function entityResourceExecute(service, resource, context) {
|
|
7
|
+
const { query } = context;
|
|
8
|
+
if (OpraQuery.isSearchQuery(query)) {
|
|
9
|
+
const promises = [];
|
|
10
|
+
let search;
|
|
11
|
+
let count;
|
|
12
|
+
promises.push(executeFn(service, resource, context, query.queryType)
|
|
13
|
+
.then(v => search = v));
|
|
14
|
+
if (query.count) {
|
|
15
|
+
promises.push(executeFn(service, resource, context, 'count')
|
|
16
|
+
.then(v => count = v));
|
|
17
|
+
}
|
|
18
|
+
await Promise.all(promises);
|
|
19
|
+
context.response.value = {
|
|
20
|
+
...search,
|
|
21
|
+
...count
|
|
22
|
+
};
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
context.response.value = await executeFn(service, resource, context, query.queryType);
|
|
26
|
+
}
|
|
27
|
+
async function executeFn(service, resource, context, queryType) {
|
|
28
|
+
const resolverInfo = resource.metadata.methods?.[queryType];
|
|
29
|
+
if (!resolverInfo.handler)
|
|
30
|
+
throw new ForbiddenError({
|
|
31
|
+
message: translate('RESOLVER_FORBIDDEN', { queryType }),
|
|
32
|
+
severity: 'error',
|
|
33
|
+
code: 'RESOLVER_FORBIDDEN'
|
|
34
|
+
});
|
|
35
|
+
let result = await resolverInfo.handler(context);
|
|
36
|
+
switch (queryType) {
|
|
37
|
+
case 'search':
|
|
38
|
+
context.response.headers.set(HttpHeaders.X_Opra_Schema, '/$schema/types/' + resource.dataType.name);
|
|
39
|
+
return {
|
|
40
|
+
items: Array.isArray(result) ? result : (context.response.value ? [result] : [])
|
|
41
|
+
};
|
|
42
|
+
case 'get':
|
|
43
|
+
case 'update':
|
|
44
|
+
if (!result) {
|
|
45
|
+
const query = context.query;
|
|
46
|
+
throw new ResourceNotFoundError(resource.name, query.keyValue);
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case 'count':
|
|
50
|
+
return { count: result || 0 };
|
|
51
|
+
case 'delete':
|
|
52
|
+
case 'deleteMany':
|
|
53
|
+
case 'updateMany':
|
|
54
|
+
let affectedRecords;
|
|
55
|
+
if (typeof result === 'number')
|
|
56
|
+
affectedRecords = result;
|
|
57
|
+
if (typeof result === 'boolean')
|
|
58
|
+
affectedRecords = result ? 1 : 0;
|
|
59
|
+
if (typeof result === 'object')
|
|
60
|
+
affectedRecords = result.affectedRows || result.affectedRecords;
|
|
61
|
+
return { affectedRecords };
|
|
62
|
+
}
|
|
63
|
+
if (!result)
|
|
64
|
+
return;
|
|
65
|
+
result = Array.isArray(result) ? result[0] : result;
|
|
66
|
+
let dataType = resource.dataType;
|
|
67
|
+
if (context.resultPath) {
|
|
68
|
+
const pathArray = context.resultPath.split('.');
|
|
69
|
+
for (const field of pathArray) {
|
|
70
|
+
const prop = dataType instanceof ComplexType ? dataType.fields.get(field) : undefined;
|
|
71
|
+
dataType = prop && prop.type ? service.types.get(prop.type) : undefined;
|
|
72
|
+
result = result && typeof result === 'object' && result[field];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (queryType === 'create')
|
|
76
|
+
context.response.status = 201;
|
|
77
|
+
if (dataType)
|
|
78
|
+
context.response.headers.set(HttpHeaders.X_Opra_Schema, '/$schema/types/' + dataType.name);
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { EntityResource } from '@opra/schema';
|
|
2
|
+
import { entityResourceExecute } from './entity-resource-execute.util.js';
|
|
3
|
+
export async function resourceExecute(service, resource, context) {
|
|
4
|
+
if (resource instanceof EntityResource)
|
|
5
|
+
return await entityResourceExecute(service, resource, context);
|
|
6
|
+
throw new Error(`Executing "${resource.kind}" has not been implemented yet`);
|
|
7
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { FallbackLng, I18n, LanguageResource } from '@opra/i18n';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { QueryContext } from '
|
|
2
|
+
import { OpraService } from '@opra/schema';
|
|
3
|
+
import { ApiException } from '../exception/index.js';
|
|
4
|
+
import { IExecutionContext } from '../interfaces/execution-context.interface.js';
|
|
5
|
+
import { QueryContext } from './query-context.js';
|
|
6
6
|
export declare namespace OpraAdapter {
|
|
7
7
|
type UserContextResolver = (args: {
|
|
8
8
|
executionContext: IExecutionContext;
|
|
@@ -52,6 +52,6 @@ export declare abstract class OpraAdapter<TExecutionContext extends IExecutionCo
|
|
|
52
52
|
protected abstract sendError(executionContext: TExecutionContext, error: ApiException): Promise<void>;
|
|
53
53
|
protected abstract isBatch(executionContext: TExecutionContext): boolean;
|
|
54
54
|
protected handler(executionContext: TExecutionContext): Promise<void>;
|
|
55
|
-
protected
|
|
55
|
+
protected _getSchemaExecute(ctx: QueryContext): Promise<void>;
|
|
56
56
|
protected static initI18n(options?: OpraAdapter.Options): Promise<I18n>;
|
|
57
57
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
2
|
import { I18n } from '@opra/i18n';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { HttpHeaders } from '../enums/index.js';
|
|
4
|
+
import { BadRequestError, FailedDependencyError } from '../exception/index.js';
|
|
5
|
+
import { wrapError } from '../exception/wrap-error.js';
|
|
6
|
+
import { createI18n } from '../utils/create-i18n.js';
|
|
7
|
+
import { resourceExecute } from './adapter-utils/resource-execute.util.js';
|
|
8
|
+
import { resourcePrepare } from './adapter-utils/resource-prepare.util.js';
|
|
6
9
|
export class OpraAdapter {
|
|
7
10
|
service;
|
|
8
11
|
i18n;
|
|
@@ -39,19 +42,19 @@ export class OpraAdapter {
|
|
|
39
42
|
}
|
|
40
43
|
try {
|
|
41
44
|
const promise = (async () => {
|
|
42
|
-
if (context.query.queryType === '
|
|
43
|
-
await this.
|
|
45
|
+
if (context.query.queryType === 'schema') {
|
|
46
|
+
await this._getSchemaExecute(context);
|
|
44
47
|
return;
|
|
45
48
|
}
|
|
46
49
|
const resource = context.query.resource;
|
|
47
|
-
await resource
|
|
50
|
+
await resourcePrepare(resource, context);
|
|
48
51
|
if (this.userContextResolver && !userContext)
|
|
49
52
|
userContext = this.userContextResolver({
|
|
50
53
|
executionContext,
|
|
51
54
|
isBatch: this.isBatch(executionContext)
|
|
52
55
|
});
|
|
53
56
|
context.userContext = userContext;
|
|
54
|
-
await resource
|
|
57
|
+
await resourceExecute(this.service, resource, context);
|
|
55
58
|
})().catch(e => {
|
|
56
59
|
context.response.errors.push(e);
|
|
57
60
|
});
|
|
@@ -92,7 +95,7 @@ export class OpraAdapter {
|
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
|
-
async
|
|
98
|
+
async _getSchemaExecute(ctx) {
|
|
96
99
|
const query = ctx.query;
|
|
97
100
|
let out;
|
|
98
101
|
if (query.resourcePath.length > 2)
|
|
@@ -100,23 +103,23 @@ export class OpraAdapter {
|
|
|
100
103
|
if (query.resourcePath?.length) {
|
|
101
104
|
if (query.resourcePath[0] === 'resources') {
|
|
102
105
|
const resource = this.service.getResource(query.resourcePath[1]);
|
|
103
|
-
out = resource.
|
|
106
|
+
out = resource.getSchema(true);
|
|
104
107
|
query.resourcePath[1] = resource.name;
|
|
108
|
+
ctx.response.headers.set(HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + resource.kind);
|
|
105
109
|
}
|
|
106
110
|
else if (query.resourcePath[0] === 'types') {
|
|
107
111
|
const dataType = this.service.getDataType(query.resourcePath[1]);
|
|
108
|
-
out = dataType.
|
|
112
|
+
out = dataType.getSchema(true);
|
|
109
113
|
query.resourcePath[1] = dataType.name;
|
|
114
|
+
ctx.response.headers.set(HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + dataType.kind);
|
|
110
115
|
}
|
|
111
116
|
else
|
|
112
117
|
throw new BadRequestError();
|
|
113
|
-
ctx.response.value =
|
|
114
|
-
'@opra:metadata': '/$metadata/' + query.resourcePath.join('/'),
|
|
115
|
-
...out
|
|
116
|
-
};
|
|
118
|
+
ctx.response.value = out;
|
|
117
119
|
return;
|
|
118
120
|
}
|
|
119
|
-
ctx.response.
|
|
121
|
+
ctx.response.headers.set(HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema');
|
|
122
|
+
ctx.response.value = this.service.getSchema(true);
|
|
120
123
|
}
|
|
121
124
|
static async initI18n(options) {
|
|
122
125
|
if (options?.i18n instanceof I18n)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Application } from 'express';
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
2
|
+
import { OpraService } from '@opra/schema';
|
|
3
|
+
import type { IHttpExecutionContext } from '../interfaces/execution-context.interface';
|
|
4
4
|
import { OpraHttpAdapter } from './http-adapter.js';
|
|
5
5
|
export declare namespace OpraExpressAdapter {
|
|
6
6
|
interface Options extends OpraHttpAdapter.Options {
|
|
File without changes
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { OpraURL } from '@opra/url';
|
|
2
|
-
import { ApiException } from '
|
|
3
|
-
import { IHttpExecutionContext } from '
|
|
4
|
-
import {
|
|
5
|
-
import { HeadersObject } from '../../utils/headers.js';
|
|
6
|
-
import { QueryContext } from '../query-context.js';
|
|
2
|
+
import { ApiException } from '../exception/index.js';
|
|
3
|
+
import { IHttpExecutionContext } from '../interfaces/execution-context.interface.js';
|
|
4
|
+
import { OpraGetSchemaQuery, OpraQuery } from '../interfaces/query.interface.js';
|
|
7
5
|
import { OpraAdapter } from './adapter.js';
|
|
6
|
+
import { QueryContext } from './query-context.js';
|
|
8
7
|
export declare namespace OpraHttpAdapter {
|
|
9
8
|
type Options = OpraAdapter.Options & {
|
|
10
9
|
prefix?: string;
|
|
@@ -17,8 +16,8 @@ interface PreparedOutput {
|
|
|
17
16
|
}
|
|
18
17
|
export declare class OpraHttpAdapter<TExecutionContext extends IHttpExecutionContext> extends OpraAdapter<IHttpExecutionContext> {
|
|
19
18
|
protected prepareRequests(executionContext: TExecutionContext): QueryContext[];
|
|
20
|
-
prepareRequest(executionContext: IHttpExecutionContext, url: OpraURL, method: string, headers:
|
|
21
|
-
|
|
19
|
+
prepareRequest(executionContext: IHttpExecutionContext, url: OpraURL, method: string, headers: Map<string, string>, body?: any): QueryContext;
|
|
20
|
+
buildGetSchemaQuery(url: OpraURL): OpraGetSchemaQuery;
|
|
22
21
|
buildQuery(url: OpraURL, method: string, body?: any): OpraQuery | undefined;
|
|
23
22
|
protected sendResponse(executionContext: TExecutionContext, queryContexts: QueryContext[]): Promise<void>;
|
|
24
23
|
protected isBatch(executionContext: TExecutionContext): boolean;
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
+
import { ComplexType, ContainerResource, EntityResource, OpraSchema, ResponsiveMap } from '@opra/schema';
|
|
1
2
|
import { OpraURL } from '@opra/url';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { OpraQuery } from '../../interfaces/query.interface.js';
|
|
7
|
-
import { Headers } from '../../utils/headers.js';
|
|
8
|
-
import { ComplexType } from '../data-type/complex-type.js';
|
|
9
|
-
import { QueryContext } from '../query-context.js';
|
|
10
|
-
import { ContainerResourceHandler } from '../resource/container-resource-handler.js';
|
|
11
|
-
import { EntityResourceHandler } from '../resource/entity-resource-handler.js';
|
|
3
|
+
import { HttpHeaders, HttpStatus } from '../enums/index.js';
|
|
4
|
+
import { BadRequestError, InternalServerError, MethodNotAllowedError, NotFoundError, } from '../exception/index.js';
|
|
5
|
+
import { wrapError } from '../exception/wrap-error.js';
|
|
6
|
+
import { OpraQuery } from '../interfaces/query.interface.js';
|
|
12
7
|
import { OpraAdapter } from './adapter.js';
|
|
8
|
+
import { QueryContext } from './query-context.js';
|
|
13
9
|
export class OpraHttpAdapter extends OpraAdapter {
|
|
14
10
|
prepareRequests(executionContext) {
|
|
15
11
|
const req = executionContext.getRequestWrapper();
|
|
@@ -19,7 +15,7 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
19
15
|
}
|
|
20
16
|
const url = new OpraURL(req.getUrl());
|
|
21
17
|
return [
|
|
22
|
-
this.prepareRequest(executionContext, url, req.getMethod(),
|
|
18
|
+
this.prepareRequest(executionContext, url, req.getMethod(), new ResponsiveMap(req.getHeaders()), req.getBody())
|
|
23
19
|
];
|
|
24
20
|
}
|
|
25
21
|
prepareRequest(executionContext, url, method, headers, body) {
|
|
@@ -41,7 +37,7 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
41
37
|
continueOnError: query.operation === 'read'
|
|
42
38
|
});
|
|
43
39
|
}
|
|
44
|
-
|
|
40
|
+
buildGetSchemaQuery(url) {
|
|
45
41
|
const pathLen = url.path.size;
|
|
46
42
|
const resourcePath = [];
|
|
47
43
|
let pathIndex = 0;
|
|
@@ -49,7 +45,7 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
49
45
|
const p = url.path.get(pathIndex++);
|
|
50
46
|
if (p.key)
|
|
51
47
|
throw new BadRequestError();
|
|
52
|
-
if (p.resource !== '$
|
|
48
|
+
if (p.resource !== '$schema') {
|
|
53
49
|
if (pathIndex === 1)
|
|
54
50
|
resourcePath.push('resources');
|
|
55
51
|
resourcePath.push(p.resource);
|
|
@@ -60,7 +56,7 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
60
56
|
omit: url.searchParams.get('$omit'),
|
|
61
57
|
include: url.searchParams.get('$include'),
|
|
62
58
|
};
|
|
63
|
-
return OpraQuery.
|
|
59
|
+
return OpraQuery.forGetSchema(resourcePath, opts);
|
|
64
60
|
}
|
|
65
61
|
buildQuery(url, method, body) {
|
|
66
62
|
let container = this.service;
|
|
@@ -69,10 +65,10 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
69
65
|
// Check if requesting metadata
|
|
70
66
|
for (let i = 0; i < pathLen; i++) {
|
|
71
67
|
const p = url.path.get(i);
|
|
72
|
-
if (p.resource === '$
|
|
68
|
+
if (p.resource === '$schema') {
|
|
73
69
|
if (method !== 'GET')
|
|
74
70
|
return;
|
|
75
|
-
return this.
|
|
71
|
+
return this.buildGetSchemaQuery(url);
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
let pathIndex = 0;
|
|
@@ -80,12 +76,12 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
80
76
|
let p = url.path.get(pathIndex++);
|
|
81
77
|
const resource = container.getResource(p.resource);
|
|
82
78
|
// Move through path directories (containers)
|
|
83
|
-
if (resource instanceof
|
|
79
|
+
if (resource instanceof ContainerResource) {
|
|
84
80
|
container = resource;
|
|
85
81
|
continue;
|
|
86
82
|
}
|
|
87
83
|
method = method.toUpperCase();
|
|
88
|
-
if (resource instanceof
|
|
84
|
+
if (resource instanceof EntityResource) {
|
|
89
85
|
const scope = p.key ? 'instance' : 'collection';
|
|
90
86
|
if (pathIndex < pathLen && !(method === 'GET' && scope === 'instance'))
|
|
91
87
|
return;
|
|
@@ -119,10 +115,10 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
119
115
|
? this.service.getDataType(nested.property.type || 'string')
|
|
120
116
|
: query.resource.dataType;
|
|
121
117
|
if (!(dataType instanceof ComplexType))
|
|
122
|
-
throw new Error(`"${path}" is not a ComplexType and has no
|
|
118
|
+
throw new Error(`"${path}" is not a ComplexType and has no fields.`);
|
|
123
119
|
p = url.path.get(pathIndex++);
|
|
124
120
|
path += '.' + p.resource;
|
|
125
|
-
const prop = dataType.
|
|
121
|
+
const prop = dataType.fields.get(p.resource);
|
|
126
122
|
if (!prop)
|
|
127
123
|
throw new NotFoundError({ message: `Invalid or unknown resource path (${path})` });
|
|
128
124
|
const q = OpraQuery.forGetProperty(prop);
|
|
@@ -209,7 +205,7 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
209
205
|
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
210
206
|
resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
211
207
|
resp.setHeader(HttpHeaders.Expires, '-1');
|
|
212
|
-
resp.setHeader(HttpHeaders.X_Opra_Version,
|
|
208
|
+
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
213
209
|
if (out.headers) {
|
|
214
210
|
for (const [k, v] of Object.entries(out.headers)) {
|
|
215
211
|
resp.setHeader(k, v);
|
|
@@ -241,10 +237,16 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
241
237
|
delete body.errors;
|
|
242
238
|
status = status || (query.operation === 'create' ? HttpStatus.CREATED : HttpStatus.OK);
|
|
243
239
|
}
|
|
240
|
+
// Convert headers map to object
|
|
241
|
+
const headers = Array.from(ctx.response.headers.keys()).map(k => k.toLowerCase()).sort()
|
|
242
|
+
.reduce((a, k) => {
|
|
243
|
+
a[k] = ctx.response.headers.get(k);
|
|
244
|
+
return a;
|
|
245
|
+
}, {});
|
|
244
246
|
body = this.i18n.deep(body);
|
|
245
247
|
return {
|
|
246
248
|
status,
|
|
247
|
-
headers
|
|
249
|
+
headers,
|
|
248
250
|
body
|
|
249
251
|
};
|
|
250
252
|
}
|
|
@@ -255,7 +257,7 @@ export class OpraHttpAdapter extends OpraAdapter {
|
|
|
255
257
|
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
256
258
|
resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
257
259
|
resp.setHeader(HttpHeaders.Expires, '-1');
|
|
258
|
-
resp.setHeader(HttpHeaders.X_Opra_Version,
|
|
260
|
+
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
259
261
|
resp.send(JSON.stringify(error.response));
|
|
260
262
|
}
|
|
261
263
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
import { OpraService, ResponsiveMap } from '@opra/schema';
|
|
1
2
|
import { SearchParams } from '@opra/url';
|
|
2
3
|
import { HttpStatus } from '../enums/index.js';
|
|
3
4
|
import { ApiException } from '../exception/index.js';
|
|
4
5
|
import { ContextType, IExecutionContext, IHttpExecutionContext } from '../interfaces/execution-context.interface.js';
|
|
5
6
|
import { OpraQuery } from '../interfaces/query.interface.js';
|
|
6
|
-
import { HeadersObject } from '../utils/headers.js';
|
|
7
|
-
import { OpraService } from './opra-service.js';
|
|
8
7
|
export declare type QueryContextArgs = Pick<QueryContext, 'service' | 'executionContext' | 'query' | 'params' | 'headers' | 'userContext' | 'parentValue' | 'continueOnError'>;
|
|
9
8
|
export declare class QueryContext {
|
|
10
9
|
readonly service: OpraService;
|
|
11
10
|
readonly executionContext: IExecutionContext;
|
|
12
11
|
readonly query: OpraQuery;
|
|
13
12
|
readonly params: SearchParams;
|
|
14
|
-
readonly headers:
|
|
13
|
+
readonly headers: Map<string, string>;
|
|
15
14
|
readonly parentValue?: any;
|
|
16
15
|
readonly resultPath: string;
|
|
17
16
|
readonly response: QueryResponse;
|
|
@@ -23,7 +22,7 @@ export declare class QueryContext {
|
|
|
23
22
|
}
|
|
24
23
|
export declare type QueryResponseArgs = Pick<QueryResponse, 'status' | 'value' | 'total'>;
|
|
25
24
|
export declare class QueryResponse {
|
|
26
|
-
headers:
|
|
25
|
+
headers: ResponsiveMap<string, string>;
|
|
27
26
|
errors: ApiException[];
|
|
28
27
|
status?: HttpStatus;
|
|
29
28
|
value?: any;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { ResponsiveMap } from '@opra/schema';
|
|
1
2
|
import { OpraURLSearchParams } from '@opra/url';
|
|
2
|
-
import {
|
|
3
|
+
import { HttpHeaders } from '../enums/index.js';
|
|
3
4
|
export class QueryContext {
|
|
4
5
|
service;
|
|
5
6
|
executionContext;
|
|
@@ -15,7 +16,7 @@ export class QueryContext {
|
|
|
15
16
|
Object.assign(this, args);
|
|
16
17
|
this.response = new QueryResponse();
|
|
17
18
|
this.params = this.params || new OpraURLSearchParams();
|
|
18
|
-
this.headers = this.headers ||
|
|
19
|
+
this.headers = this.headers || new ResponsiveMap();
|
|
19
20
|
this.resultPath = this.resultPath || '';
|
|
20
21
|
}
|
|
21
22
|
get type() {
|
|
@@ -28,7 +29,7 @@ export class QueryContext {
|
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
export class QueryResponse {
|
|
31
|
-
headers
|
|
32
|
+
headers;
|
|
32
33
|
errors = [];
|
|
33
34
|
status;
|
|
34
35
|
value;
|
|
@@ -36,5 +37,6 @@ export class QueryResponse {
|
|
|
36
37
|
constructor(args) {
|
|
37
38
|
if (args)
|
|
38
39
|
Object.assign(this, args);
|
|
40
|
+
this.headers = new ResponsiveMap(undefined, Array.from(Object.values(HttpHeaders)));
|
|
39
41
|
}
|
|
40
42
|
}
|
package/esm/index.d.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
export * from './constants.js';
|
|
3
2
|
export * from './types.js';
|
|
4
3
|
export * from './enums/index.js';
|
|
5
4
|
export * from './exception/index.js';
|
|
6
|
-
export * from './decorators/api-entity-resource.decorator.js';
|
|
7
5
|
export * from './interfaces/execution-context.interface.js';
|
|
8
6
|
export * from './interfaces/query.interface.js';
|
|
9
|
-
export * from './interfaces/
|
|
7
|
+
export * from './interfaces/entity-service.interface.js';
|
|
10
8
|
export * from './implementation/query-context.js';
|
|
11
|
-
export * from './implementation/
|
|
12
|
-
export * from './implementation/
|
|
13
|
-
export * from './implementation/
|
|
14
|
-
export * from './
|
|
15
|
-
export * from './implementation/adapter/http-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-handler.js';
|
|
21
|
-
export * from './implementation/resource/entity-resource-handler.js';
|
|
22
|
-
export * from './services/entity-resource-controller.js';
|
|
9
|
+
export * from './implementation/adapter.js';
|
|
10
|
+
export * from './implementation/http-adapter.js';
|
|
11
|
+
export * from './implementation/express-adapter.js';
|
|
12
|
+
export * from './services/data-service.js';
|
|
23
13
|
export * from './services/json-data-service.js';
|
package/esm/index.js
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
export * from './constants.js';
|
|
3
2
|
export * from './types.js';
|
|
4
3
|
export * from './enums/index.js';
|
|
5
4
|
export * from './exception/index.js';
|
|
6
|
-
export * from './decorators/api-entity-resource.decorator.js';
|
|
7
5
|
export * from './interfaces/execution-context.interface.js';
|
|
8
6
|
export * from './interfaces/query.interface.js';
|
|
9
|
-
export * from './interfaces/
|
|
7
|
+
export * from './interfaces/entity-service.interface.js';
|
|
10
8
|
export * from './implementation/query-context.js';
|
|
11
|
-
export * from './implementation/
|
|
12
|
-
export * from './implementation/
|
|
13
|
-
export * from './implementation/
|
|
14
|
-
export * from './
|
|
15
|
-
export * from './implementation/adapter/http-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-handler.js';
|
|
21
|
-
export * from './implementation/resource/entity-resource-handler.js';
|
|
22
|
-
export * from './services/entity-resource-controller.js';
|
|
9
|
+
export * from './implementation/adapter.js';
|
|
10
|
+
export * from './implementation/http-adapter.js';
|
|
11
|
+
export * from './implementation/express-adapter.js';
|
|
12
|
+
export * from './services/data-service.js';
|
|
23
13
|
export * from './services/json-data-service.js';
|
package/esm/{services/entity-resource-controller.d.ts → interfaces/entity-service.interface.d.ts}
RENAMED
|
File without changes
|
package/esm/{services/entity-resource-controller.js → interfaces/entity-service.interface.js}
RENAMED
|
File without changes
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { StrictOmit } from 'ts-gems';
|
|
2
|
-
import { OpraSchema } from '@opra/schema';
|
|
2
|
+
import { EntityResource, OpraSchema } from '@opra/schema';
|
|
3
3
|
import { Expression } from '@opra/url';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export declare type OpraQuery = OpraMetadataQuery | OpraCreateQuery | OpraGetEntityQuery | OpraSearchQuery | OpraUpdateQuery | OpraUpdateManyQuery | OpraDeleteQuery | OpraDeleteManyQuery;
|
|
4
|
+
import { KeyValue, QueryType } from '../types.js';
|
|
5
|
+
export declare type OpraQuery = OpraGetSchemaQuery | OpraCreateQuery | OpraGetEntityQuery | OpraSearchQuery | OpraUpdateQuery | OpraUpdateManyQuery | OpraDeleteQuery | OpraDeleteManyQuery;
|
|
7
6
|
interface BaseOpraQuery {
|
|
8
7
|
queryType: QueryType;
|
|
9
|
-
scope: QueryScope;
|
|
10
|
-
operation: OperationType;
|
|
8
|
+
scope: OpraSchema.QueryScope;
|
|
9
|
+
operation: OpraSchema.OperationType;
|
|
11
10
|
}
|
|
12
|
-
export interface
|
|
13
|
-
queryType: '
|
|
14
|
-
scope: QueryScope;
|
|
11
|
+
export interface OpraGetSchemaQuery extends BaseOpraQuery {
|
|
12
|
+
queryType: 'schema';
|
|
13
|
+
scope: OpraSchema.QueryScope;
|
|
15
14
|
operation: 'read';
|
|
16
15
|
resourcePath: string[];
|
|
17
16
|
}
|
|
@@ -19,7 +18,7 @@ export interface OpraCreateQuery extends BaseOpraQuery {
|
|
|
19
18
|
queryType: 'create';
|
|
20
19
|
scope: 'collection';
|
|
21
20
|
operation: 'create';
|
|
22
|
-
resource:
|
|
21
|
+
resource: EntityResource;
|
|
23
22
|
data: {};
|
|
24
23
|
pick?: string[];
|
|
25
24
|
omit?: string[];
|
|
@@ -29,7 +28,7 @@ export interface OpraGetEntityQuery extends BaseOpraQuery {
|
|
|
29
28
|
queryType: 'get';
|
|
30
29
|
scope: 'instance';
|
|
31
30
|
operation: 'read';
|
|
32
|
-
resource:
|
|
31
|
+
resource: EntityResource;
|
|
33
32
|
keyValue: KeyValue;
|
|
34
33
|
pick?: string[];
|
|
35
34
|
omit?: string[];
|
|
@@ -40,14 +39,14 @@ export interface OpraPropertyQuery extends BaseOpraQuery {
|
|
|
40
39
|
queryType: 'get';
|
|
41
40
|
scope: 'property';
|
|
42
41
|
operation: 'read';
|
|
43
|
-
property: OpraSchema.
|
|
42
|
+
property: OpraSchema.Field;
|
|
44
43
|
nested?: OpraPropertyQuery;
|
|
45
44
|
}
|
|
46
45
|
export interface OpraUpdateQuery extends BaseOpraQuery {
|
|
47
46
|
queryType: 'update';
|
|
48
47
|
scope: 'instance';
|
|
49
48
|
operation: 'update';
|
|
50
|
-
resource:
|
|
49
|
+
resource: EntityResource;
|
|
51
50
|
keyValue: KeyValue;
|
|
52
51
|
data: {};
|
|
53
52
|
pick?: string[];
|
|
@@ -58,7 +57,7 @@ export interface OpraUpdateManyQuery extends BaseOpraQuery {
|
|
|
58
57
|
queryType: 'updateMany';
|
|
59
58
|
scope: 'collection';
|
|
60
59
|
operation: 'update';
|
|
61
|
-
resource:
|
|
60
|
+
resource: EntityResource;
|
|
62
61
|
filter?: string | Expression;
|
|
63
62
|
data: {};
|
|
64
63
|
}
|
|
@@ -66,21 +65,21 @@ export interface OpraDeleteQuery extends BaseOpraQuery {
|
|
|
66
65
|
queryType: 'delete';
|
|
67
66
|
scope: 'instance';
|
|
68
67
|
operation: 'delete';
|
|
69
|
-
resource:
|
|
68
|
+
resource: EntityResource;
|
|
70
69
|
keyValue: KeyValue;
|
|
71
70
|
}
|
|
72
71
|
export interface OpraDeleteManyQuery extends BaseOpraQuery {
|
|
73
72
|
queryType: 'deleteMany';
|
|
74
73
|
scope: 'collection';
|
|
75
74
|
operation: 'delete';
|
|
76
|
-
resource:
|
|
75
|
+
resource: EntityResource;
|
|
77
76
|
filter?: string | Expression;
|
|
78
77
|
}
|
|
79
78
|
export interface OpraSearchQuery extends BaseOpraQuery {
|
|
80
79
|
queryType: 'search';
|
|
81
80
|
scope: 'collection';
|
|
82
81
|
operation: 'read';
|
|
83
|
-
resource:
|
|
82
|
+
resource: EntityResource;
|
|
84
83
|
pick?: string[];
|
|
85
84
|
omit?: string[];
|
|
86
85
|
include?: string[];
|
|
@@ -99,15 +98,15 @@ export declare type UpdateManyQueryOptions = StrictOmit<OpraUpdateManyQuery, 'qu
|
|
|
99
98
|
export declare type DeleteQueryOptions = StrictOmit<OpraDeleteQuery, 'queryType' | 'scope' | 'operation' | 'resource' | 'keyValue'>;
|
|
100
99
|
export declare type DeleteManyQueryOption = StrictOmit<OpraDeleteManyQuery, 'queryType' | 'scope' | 'operation' | 'resource'>;
|
|
101
100
|
export declare namespace OpraQuery {
|
|
102
|
-
function forCreate(resource:
|
|
103
|
-
function
|
|
104
|
-
function forGetEntity(resource:
|
|
105
|
-
function forSearch(resource:
|
|
106
|
-
function forGetProperty(property: OpraSchema.
|
|
107
|
-
function forUpdate(resource:
|
|
108
|
-
function forUpdateMany(resource:
|
|
109
|
-
function forDelete(resource:
|
|
110
|
-
function forDeleteMany(resource:
|
|
101
|
+
function forCreate(resource: EntityResource, values: {}, options?: CreateQueryOptions): OpraCreateQuery;
|
|
102
|
+
function forGetSchema(resourcePath: string[], options?: GetEntityQueryOptions): OpraGetSchemaQuery;
|
|
103
|
+
function forGetEntity(resource: EntityResource, key: KeyValue, options?: GetEntityQueryOptions): OpraGetEntityQuery;
|
|
104
|
+
function forSearch(resource: EntityResource, options?: SearchQueryOptions): OpraSearchQuery;
|
|
105
|
+
function forGetProperty(property: OpraSchema.Field, options?: StrictOmit<OpraPropertyQuery, 'queryType' | 'scope' | 'operation' | 'property'>): OpraPropertyQuery;
|
|
106
|
+
function forUpdate(resource: EntityResource, keyValue: KeyValue, values: any, options?: UpdateQueryOptions): OpraUpdateQuery;
|
|
107
|
+
function forUpdateMany(resource: EntityResource, values: any, options?: UpdateManyQueryOptions): OpraUpdateManyQuery;
|
|
108
|
+
function forDelete(resource: EntityResource, key: KeyValue): OpraDeleteQuery;
|
|
109
|
+
function forDeleteMany(resource: EntityResource, options?: DeleteManyQueryOption): OpraDeleteManyQuery;
|
|
111
110
|
function isCreateQuery(q: any): q is OpraCreateQuery;
|
|
112
111
|
function isSearchQuery(q: any): q is OpraSearchQuery;
|
|
113
112
|
function isReadQuery(q: any): q is OpraGetEntityQuery;
|