@opra/core 0.0.12 → 0.1.0
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/exception/http-errors/not-acceptable.error.js +26 -0
- package/cjs/exception/index.js +2 -0
- package/cjs/exception/resource-errors/resource-not-found.error.js +19 -0
- 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} +40 -7
- package/cjs/implementation/{adapter/express-adapter.js → express-adapter.js} +0 -0
- package/cjs/implementation/http-adapter.js +267 -0
- 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 +26 -9
- package/cjs/services/json-data-service.js +241 -4
- package/cjs/utils/create-i18n.js +1 -1
- package/cjs/utils/get-caller-file.util.js +6 -1
- 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/exception/http-errors/not-acceptable.error.d.ts +10 -0
- package/esm/exception/http-errors/not-acceptable.error.js +22 -0
- package/esm/exception/index.d.ts +2 -0
- package/esm/exception/index.js +2 -0
- package/esm/exception/resource-errors/resource-not-found.error.d.ts +4 -0
- package/esm/exception/resource-errors/resource-not-found.error.js +15 -0
- 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 -9
- package/esm/implementation/{adapter/adapter.js → adapter.js} +39 -6
- 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 -6
- package/esm/implementation/http-adapter.js +263 -0
- 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 +31 -25
- package/esm/interfaces/query.interface.js +26 -9
- package/esm/services/json-data-service.d.ts +66 -7
- package/esm/services/json-data-service.js +241 -4
- package/esm/types.d.ts +10 -8
- package/esm/utils/create-i18n.d.ts +1 -1
- package/esm/utils/create-i18n.js +1 -1
- package/esm/utils/get-caller-file.util.d.ts +1 -1
- package/esm/utils/get-caller-file.util.js +6 -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/i18n/en/error.json +3 -0
- package/package.json +6 -7
- package/cjs/constants.js +0 -5
- package/cjs/decorators/entity-resource.decorator.js +0 -24
- package/cjs/implementation/adapter/http-adapter.js +0 -238
- package/cjs/implementation/data-type/complex-type.js +0 -39
- package/cjs/implementation/data-type/data-type.js +0 -35
- package/cjs/implementation/data-type/entity-type.js +0 -33
- package/cjs/implementation/data-type/simple-type.js +0 -30
- package/cjs/implementation/opra-document.js +0 -116
- package/cjs/implementation/opra-service.js +0 -59
- package/cjs/implementation/resource/container-resource-handler.js +0 -30
- package/cjs/implementation/resource/entity-resource-handler.js +0 -80
- package/cjs/implementation/resource/resource-handler.js +0 -31
- package/cjs/implementation/schema-generator.js +0 -163
- package/cjs/interfaces/opra-schema.metadata.js +0 -2
- 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 -2
- package/esm/constants.js +0 -2
- package/esm/decorators/entity-resource.decorator.d.ts +0 -5
- package/esm/decorators/entity-resource.decorator.js +0 -19
- package/esm/implementation/adapter/http-adapter.js +0 -234
- package/esm/implementation/data-type/complex-type.d.ts +0 -18
- package/esm/implementation/data-type/complex-type.js +0 -35
- package/esm/implementation/data-type/data-type.d.ts +0 -15
- package/esm/implementation/data-type/data-type.js +0 -31
- 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 -111
- package/esm/implementation/opra-service.d.ts +0 -19
- package/esm/implementation/opra-service.js +0 -55
- 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 -75
- package/esm/implementation/resource/resource-handler.d.ts +0 -15
- package/esm/implementation/resource/resource-handler.js +0 -27
- package/esm/implementation/schema-generator.d.ts +0 -21
- package/esm/implementation/schema-generator.js +0 -159
- package/esm/interfaces/opra-schema.metadata.d.ts +0 -14
- package/esm/interfaces/opra-schema.metadata.js +0 -1
- 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
|
@@ -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;
|
|
@@ -38,16 +41,20 @@ export class OpraAdapter {
|
|
|
38
41
|
continue;
|
|
39
42
|
}
|
|
40
43
|
try {
|
|
41
|
-
const resource = context.query.resource;
|
|
42
44
|
const promise = (async () => {
|
|
43
|
-
|
|
45
|
+
if (context.query.queryType === 'schema') {
|
|
46
|
+
await this._getSchemaExecute(context);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const resource = context.query.resource;
|
|
50
|
+
await resourcePrepare(resource, context);
|
|
44
51
|
if (this.userContextResolver && !userContext)
|
|
45
52
|
userContext = this.userContextResolver({
|
|
46
53
|
executionContext,
|
|
47
54
|
isBatch: this.isBatch(executionContext)
|
|
48
55
|
});
|
|
49
56
|
context.userContext = userContext;
|
|
50
|
-
await resource
|
|
57
|
+
await resourceExecute(this.service, resource, context);
|
|
51
58
|
})().catch(e => {
|
|
52
59
|
context.response.errors.push(e);
|
|
53
60
|
});
|
|
@@ -88,6 +95,32 @@ export class OpraAdapter {
|
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
}
|
|
98
|
+
async _getSchemaExecute(ctx) {
|
|
99
|
+
const query = ctx.query;
|
|
100
|
+
let out;
|
|
101
|
+
if (query.resourcePath.length > 2)
|
|
102
|
+
throw new BadRequestError();
|
|
103
|
+
if (query.resourcePath?.length) {
|
|
104
|
+
if (query.resourcePath[0] === 'resources') {
|
|
105
|
+
const resource = this.service.getResource(query.resourcePath[1]);
|
|
106
|
+
out = resource.getSchema(true);
|
|
107
|
+
query.resourcePath[1] = resource.name;
|
|
108
|
+
ctx.response.headers.set(HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + resource.kind);
|
|
109
|
+
}
|
|
110
|
+
else if (query.resourcePath[0] === 'types') {
|
|
111
|
+
const dataType = this.service.getDataType(query.resourcePath[1]);
|
|
112
|
+
out = dataType.getSchema(true);
|
|
113
|
+
query.resourcePath[1] = dataType.name;
|
|
114
|
+
ctx.response.headers.set(HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + dataType.kind);
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
throw new BadRequestError();
|
|
118
|
+
ctx.response.value = out;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
ctx.response.headers.set(HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema');
|
|
122
|
+
ctx.response.value = this.service.getSchema(true);
|
|
123
|
+
}
|
|
91
124
|
static async initI18n(options) {
|
|
92
125
|
if (options?.i18n instanceof I18n)
|
|
93
126
|
return options.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 { OpraQuery } from '
|
|
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,7 +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:
|
|
19
|
+
prepareRequest(executionContext: IHttpExecutionContext, url: OpraURL, method: string, headers: Map<string, string>, body?: any): QueryContext;
|
|
20
|
+
buildGetSchemaQuery(url: OpraURL): OpraGetSchemaQuery;
|
|
21
21
|
buildQuery(url: OpraURL, method: string, body?: any): OpraQuery | undefined;
|
|
22
22
|
protected sendResponse(executionContext: TExecutionContext, queryContexts: QueryContext[]): Promise<void>;
|
|
23
23
|
protected isBatch(executionContext: TExecutionContext): boolean;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { ComplexType, ContainerResource, EntityResource, OpraSchema, ResponsiveMap } from '@opra/schema';
|
|
2
|
+
import { OpraURL } from '@opra/url';
|
|
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';
|
|
7
|
+
import { OpraAdapter } from './adapter.js';
|
|
8
|
+
import { QueryContext } from './query-context.js';
|
|
9
|
+
export class OpraHttpAdapter extends OpraAdapter {
|
|
10
|
+
prepareRequests(executionContext) {
|
|
11
|
+
const req = executionContext.getRequestWrapper();
|
|
12
|
+
// todo implement batch requests
|
|
13
|
+
if (this.isBatch(executionContext)) {
|
|
14
|
+
throw new Error('not implemented yet');
|
|
15
|
+
}
|
|
16
|
+
const url = new OpraURL(req.getUrl());
|
|
17
|
+
return [
|
|
18
|
+
this.prepareRequest(executionContext, url, req.getMethod(), new ResponsiveMap(req.getHeaders()), req.getBody())
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
prepareRequest(executionContext, url, method, headers, body) {
|
|
22
|
+
if (!url.path.size)
|
|
23
|
+
throw new BadRequestError();
|
|
24
|
+
if (method !== 'GET' && url.path.size > 1)
|
|
25
|
+
throw new BadRequestError();
|
|
26
|
+
const query = this.buildQuery(url, method, body);
|
|
27
|
+
if (!query)
|
|
28
|
+
throw new MethodNotAllowedError({
|
|
29
|
+
message: `Method "${method}" is not allowed by target endpoint`
|
|
30
|
+
});
|
|
31
|
+
return new QueryContext({
|
|
32
|
+
service: this.service,
|
|
33
|
+
executionContext,
|
|
34
|
+
query,
|
|
35
|
+
headers,
|
|
36
|
+
params: url.searchParams,
|
|
37
|
+
continueOnError: query.operation === 'read'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
buildGetSchemaQuery(url) {
|
|
41
|
+
const pathLen = url.path.size;
|
|
42
|
+
const resourcePath = [];
|
|
43
|
+
let pathIndex = 0;
|
|
44
|
+
while (pathIndex < pathLen) {
|
|
45
|
+
const p = url.path.get(pathIndex++);
|
|
46
|
+
if (p.key)
|
|
47
|
+
throw new BadRequestError();
|
|
48
|
+
if (p.resource !== '$schema') {
|
|
49
|
+
if (pathIndex === 1)
|
|
50
|
+
resourcePath.push('resources');
|
|
51
|
+
resourcePath.push(p.resource);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const opts = {
|
|
55
|
+
pick: url.searchParams.get('$pick'),
|
|
56
|
+
omit: url.searchParams.get('$omit'),
|
|
57
|
+
include: url.searchParams.get('$include'),
|
|
58
|
+
};
|
|
59
|
+
return OpraQuery.forGetSchema(resourcePath, opts);
|
|
60
|
+
}
|
|
61
|
+
buildQuery(url, method, body) {
|
|
62
|
+
let container = this.service;
|
|
63
|
+
try {
|
|
64
|
+
const pathLen = url.path.size;
|
|
65
|
+
// Check if requesting metadata
|
|
66
|
+
for (let i = 0; i < pathLen; i++) {
|
|
67
|
+
const p = url.path.get(i);
|
|
68
|
+
if (p.resource === '$schema') {
|
|
69
|
+
if (method !== 'GET')
|
|
70
|
+
return;
|
|
71
|
+
return this.buildGetSchemaQuery(url);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
let pathIndex = 0;
|
|
75
|
+
while (pathIndex < pathLen) {
|
|
76
|
+
let p = url.path.get(pathIndex++);
|
|
77
|
+
const resource = container.getResource(p.resource);
|
|
78
|
+
// Move through path directories (containers)
|
|
79
|
+
if (resource instanceof ContainerResource) {
|
|
80
|
+
container = resource;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
method = method.toUpperCase();
|
|
84
|
+
if (resource instanceof EntityResource) {
|
|
85
|
+
const scope = p.key ? 'instance' : 'collection';
|
|
86
|
+
if (pathIndex < pathLen && !(method === 'GET' && scope === 'instance'))
|
|
87
|
+
return;
|
|
88
|
+
let query;
|
|
89
|
+
switch (method) {
|
|
90
|
+
case 'GET': {
|
|
91
|
+
if (scope === 'collection') {
|
|
92
|
+
query = OpraQuery.forSearch(resource, {
|
|
93
|
+
filter: url.searchParams.get('$filter'),
|
|
94
|
+
limit: url.searchParams.get('$limit'),
|
|
95
|
+
skip: url.searchParams.get('$skip'),
|
|
96
|
+
distinct: url.searchParams.get('$distinct'),
|
|
97
|
+
count: url.searchParams.get('$count'),
|
|
98
|
+
sort: url.searchParams.get('$sort'),
|
|
99
|
+
pick: url.searchParams.get('$pick'),
|
|
100
|
+
omit: url.searchParams.get('$omit'),
|
|
101
|
+
include: url.searchParams.get('$include'),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
query = OpraQuery.forGetEntity(resource, p.key, {
|
|
106
|
+
pick: url.searchParams.get('$pick'),
|
|
107
|
+
omit: url.searchParams.get('$omit'),
|
|
108
|
+
include: url.searchParams.get('$include')
|
|
109
|
+
});
|
|
110
|
+
// Move through properties
|
|
111
|
+
let nested;
|
|
112
|
+
let path = resource.name;
|
|
113
|
+
while (pathIndex < pathLen) {
|
|
114
|
+
const dataType = nested
|
|
115
|
+
? this.service.getDataType(nested.property.type || 'string')
|
|
116
|
+
: query.resource.dataType;
|
|
117
|
+
if (!(dataType instanceof ComplexType))
|
|
118
|
+
throw new Error(`"${path}" is not a ComplexType and has no fields.`);
|
|
119
|
+
p = url.path.get(pathIndex++);
|
|
120
|
+
path += '.' + p.resource;
|
|
121
|
+
const prop = dataType.fields.get(p.resource);
|
|
122
|
+
if (!prop)
|
|
123
|
+
throw new NotFoundError({ message: `Invalid or unknown resource path (${path})` });
|
|
124
|
+
const q = OpraQuery.forGetProperty(prop);
|
|
125
|
+
if (nested) {
|
|
126
|
+
nested.nested = q;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
query.nested = q;
|
|
130
|
+
}
|
|
131
|
+
nested = q;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'DELETE': {
|
|
137
|
+
if (scope === 'collection') {
|
|
138
|
+
query = OpraQuery.forDeleteMany(resource, {
|
|
139
|
+
filter: url.searchParams.get('$filter'),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
query = OpraQuery.forDelete(resource, p.key);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case 'POST': {
|
|
148
|
+
if (scope === 'collection') {
|
|
149
|
+
query = OpraQuery.forCreate(resource, body, {
|
|
150
|
+
pick: url.searchParams.get('$pick'),
|
|
151
|
+
omit: url.searchParams.get('$omit'),
|
|
152
|
+
include: url.searchParams.get('$include')
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case 'PATCH': {
|
|
158
|
+
if (scope === 'collection') {
|
|
159
|
+
query = OpraQuery.forUpdateMany(resource, body, {
|
|
160
|
+
filter: url.searchParams.get('$filter')
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
query = OpraQuery.forUpdate(resource, p.key, body, {
|
|
165
|
+
pick: url.searchParams.get('$pick'),
|
|
166
|
+
omit: url.searchParams.get('$omit'),
|
|
167
|
+
include: url.searchParams.get('$include')
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return query;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
throw new InternalServerError();
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
throw BadRequestError.wrap(e);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async sendResponse(executionContext, queryContexts) {
|
|
183
|
+
const outputPackets = [];
|
|
184
|
+
for (const ctx of queryContexts) {
|
|
185
|
+
const v = this.createOutput(ctx);
|
|
186
|
+
outputPackets.push(v);
|
|
187
|
+
}
|
|
188
|
+
if (this.isBatch(executionContext)) {
|
|
189
|
+
// this.writeError([], new InternalServerError({message: 'Not implemented yet'}));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (!outputPackets.length) {
|
|
193
|
+
const err = new NotFoundError();
|
|
194
|
+
outputPackets.push({
|
|
195
|
+
status: err.status,
|
|
196
|
+
body: {
|
|
197
|
+
errors: [err.response]
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const out = outputPackets[0];
|
|
202
|
+
const resp = executionContext.getResponseWrapper();
|
|
203
|
+
resp.setStatus(out.status);
|
|
204
|
+
resp.setHeader(HttpHeaders.Content_Type, 'application/json');
|
|
205
|
+
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
206
|
+
resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
207
|
+
resp.setHeader(HttpHeaders.Expires, '-1');
|
|
208
|
+
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
209
|
+
if (out.headers) {
|
|
210
|
+
for (const [k, v] of Object.entries(out.headers)) {
|
|
211
|
+
resp.setHeader(k, v);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
resp.send(JSON.stringify(out.body));
|
|
215
|
+
}
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
217
|
+
isBatch(executionContext) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
createOutput(ctx) {
|
|
221
|
+
const { query } = ctx;
|
|
222
|
+
let status = ctx.response.status;
|
|
223
|
+
let body = ctx.response.value || {};
|
|
224
|
+
const errors = ctx.response.errors?.map(e => wrapError(e));
|
|
225
|
+
if (errors && errors.length) {
|
|
226
|
+
if (!status || status < 400) {
|
|
227
|
+
status = 0;
|
|
228
|
+
for (const e of errors) {
|
|
229
|
+
status = Math.max(status, e.status || status);
|
|
230
|
+
}
|
|
231
|
+
if (status < HttpStatus.BAD_REQUEST)
|
|
232
|
+
status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
233
|
+
}
|
|
234
|
+
body.errors = errors.map(e => e.response);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
delete body.errors;
|
|
238
|
+
status = status || (query.operation === 'create' ? HttpStatus.CREATED : HttpStatus.OK);
|
|
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
|
+
}, {});
|
|
246
|
+
body = this.i18n.deep(body);
|
|
247
|
+
return {
|
|
248
|
+
status,
|
|
249
|
+
headers,
|
|
250
|
+
body
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async sendError(executionContext, error) {
|
|
254
|
+
const resp = executionContext.getResponseWrapper();
|
|
255
|
+
resp.setStatus(error.status || 500);
|
|
256
|
+
resp.setHeader(HttpHeaders.Content_Type, 'application/json');
|
|
257
|
+
resp.setHeader(HttpHeaders.Cache_Control, 'no-cache');
|
|
258
|
+
resp.setHeader(HttpHeaders.Pragma, 'no-cache');
|
|
259
|
+
resp.setHeader(HttpHeaders.Expires, '-1');
|
|
260
|
+
resp.setHeader(HttpHeaders.X_Opra_Version, OpraSchema.Version);
|
|
261
|
+
resp.send(JSON.stringify(error.response));
|
|
262
|
+
}
|
|
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/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/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,29 +1,34 @@
|
|
|
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 = OpraCreateQuery | OpraGetQuery | 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;
|
|
10
|
+
}
|
|
11
|
+
export interface OpraGetSchemaQuery extends BaseOpraQuery {
|
|
12
|
+
queryType: 'schema';
|
|
13
|
+
scope: OpraSchema.QueryScope;
|
|
14
|
+
operation: 'read';
|
|
15
|
+
resourcePath: string[];
|
|
11
16
|
}
|
|
12
17
|
export interface OpraCreateQuery extends BaseOpraQuery {
|
|
13
18
|
queryType: 'create';
|
|
14
19
|
scope: 'collection';
|
|
15
20
|
operation: 'create';
|
|
16
|
-
resource:
|
|
21
|
+
resource: EntityResource;
|
|
17
22
|
data: {};
|
|
18
23
|
pick?: string[];
|
|
19
24
|
omit?: string[];
|
|
20
25
|
include?: string[];
|
|
21
26
|
}
|
|
22
|
-
export interface
|
|
27
|
+
export interface OpraGetEntityQuery extends BaseOpraQuery {
|
|
23
28
|
queryType: 'get';
|
|
24
29
|
scope: 'instance';
|
|
25
30
|
operation: 'read';
|
|
26
|
-
resource:
|
|
31
|
+
resource: EntityResource;
|
|
27
32
|
keyValue: KeyValue;
|
|
28
33
|
pick?: string[];
|
|
29
34
|
omit?: string[];
|
|
@@ -34,14 +39,14 @@ export interface OpraPropertyQuery extends BaseOpraQuery {
|
|
|
34
39
|
queryType: 'get';
|
|
35
40
|
scope: 'property';
|
|
36
41
|
operation: 'read';
|
|
37
|
-
property: OpraSchema.
|
|
42
|
+
property: OpraSchema.Field;
|
|
38
43
|
nested?: OpraPropertyQuery;
|
|
39
44
|
}
|
|
40
45
|
export interface OpraUpdateQuery extends BaseOpraQuery {
|
|
41
46
|
queryType: 'update';
|
|
42
47
|
scope: 'instance';
|
|
43
48
|
operation: 'update';
|
|
44
|
-
resource:
|
|
49
|
+
resource: EntityResource;
|
|
45
50
|
keyValue: KeyValue;
|
|
46
51
|
data: {};
|
|
47
52
|
pick?: string[];
|
|
@@ -52,7 +57,7 @@ export interface OpraUpdateManyQuery extends BaseOpraQuery {
|
|
|
52
57
|
queryType: 'updateMany';
|
|
53
58
|
scope: 'collection';
|
|
54
59
|
operation: 'update';
|
|
55
|
-
resource:
|
|
60
|
+
resource: EntityResource;
|
|
56
61
|
filter?: string | Expression;
|
|
57
62
|
data: {};
|
|
58
63
|
}
|
|
@@ -60,21 +65,21 @@ export interface OpraDeleteQuery extends BaseOpraQuery {
|
|
|
60
65
|
queryType: 'delete';
|
|
61
66
|
scope: 'instance';
|
|
62
67
|
operation: 'delete';
|
|
63
|
-
resource:
|
|
68
|
+
resource: EntityResource;
|
|
64
69
|
keyValue: KeyValue;
|
|
65
70
|
}
|
|
66
71
|
export interface OpraDeleteManyQuery extends BaseOpraQuery {
|
|
67
72
|
queryType: 'deleteMany';
|
|
68
73
|
scope: 'collection';
|
|
69
74
|
operation: 'delete';
|
|
70
|
-
resource:
|
|
75
|
+
resource: EntityResource;
|
|
71
76
|
filter?: string | Expression;
|
|
72
77
|
}
|
|
73
78
|
export interface OpraSearchQuery extends BaseOpraQuery {
|
|
74
79
|
queryType: 'search';
|
|
75
80
|
scope: 'collection';
|
|
76
81
|
operation: 'read';
|
|
77
|
-
resource:
|
|
82
|
+
resource: EntityResource;
|
|
78
83
|
pick?: string[];
|
|
79
84
|
omit?: string[];
|
|
80
85
|
include?: string[];
|
|
@@ -86,24 +91,25 @@ export interface OpraSearchQuery extends BaseOpraQuery {
|
|
|
86
91
|
sort?: string[];
|
|
87
92
|
}
|
|
88
93
|
export declare type CreateQueryOptions = StrictOmit<OpraCreateQuery, 'queryType' | 'scope' | 'operation' | 'resource' | 'data'>;
|
|
89
|
-
export declare type
|
|
94
|
+
export declare type GetEntityQueryOptions = StrictOmit<OpraGetEntityQuery, 'queryType' | 'scope' | 'operation' | 'resource' | 'keyValue'>;
|
|
90
95
|
export declare type SearchQueryOptions = StrictOmit<OpraSearchQuery, 'queryType' | 'scope' | 'operation' | 'resource'>;
|
|
91
96
|
export declare type UpdateQueryOptions = StrictOmit<OpraUpdateQuery, 'queryType' | 'scope' | 'operation' | 'resource' | 'keyValue' | 'data'>;
|
|
92
97
|
export declare type UpdateManyQueryOptions = StrictOmit<OpraUpdateManyQuery, 'queryType' | 'scope' | 'operation' | 'resource' | 'data'>;
|
|
93
98
|
export declare type DeleteQueryOptions = StrictOmit<OpraDeleteQuery, 'queryType' | 'scope' | 'operation' | 'resource' | 'keyValue'>;
|
|
94
99
|
export declare type DeleteManyQueryOption = StrictOmit<OpraDeleteManyQuery, 'queryType' | 'scope' | 'operation' | 'resource'>;
|
|
95
100
|
export declare namespace OpraQuery {
|
|
96
|
-
function forCreate(resource:
|
|
97
|
-
function
|
|
98
|
-
function
|
|
99
|
-
function
|
|
100
|
-
function
|
|
101
|
-
function
|
|
102
|
-
function
|
|
103
|
-
function
|
|
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;
|
|
104
110
|
function isCreateQuery(q: any): q is OpraCreateQuery;
|
|
105
111
|
function isSearchQuery(q: any): q is OpraSearchQuery;
|
|
106
|
-
function isReadQuery(q: any): q is
|
|
112
|
+
function isReadQuery(q: any): q is OpraGetEntityQuery;
|
|
107
113
|
function isDeleteQuery(q: any): q is OpraDeleteQuery;
|
|
108
114
|
}
|
|
109
115
|
export {};
|