@opra/core 0.0.11 → 0.0.13
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/constants.js +2 -1
- package/cjs/decorators/{entity-resource.decorator.js → api-entity-resource.decorator.js} +0 -0
- package/cjs/decorators/api-resolver.decorator.js +13 -0
- 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/adapter.js +31 -1
- package/cjs/implementation/adapter/http-adapter.js +117 -90
- package/cjs/implementation/data-type/complex-type.js +14 -0
- package/cjs/implementation/data-type/data-type.js +12 -0
- package/cjs/implementation/data-type/entity-type.js +4 -3
- package/cjs/implementation/opra-document.js +2 -6
- package/cjs/implementation/opra-service.js +22 -0
- package/cjs/implementation/resource/entity-resource-handler.js +35 -12
- package/cjs/implementation/resource/resource-handler.js +14 -0
- package/cjs/implementation/schema-generator.js +32 -11
- package/cjs/index.js +1 -1
- package/cjs/interfaces/{opra-schema.metadata.js → metadata/api-resolver.metadata.js} +0 -0
- package/cjs/interfaces/metadata/opra-schema.metadata.js +11 -0
- package/cjs/interfaces/query.interface.js +19 -2
- package/cjs/services/json-data-service.js +235 -4
- package/cjs/utils/create-i18n.js +1 -1
- package/cjs/utils/get-caller-file.util.js +6 -1
- package/esm/constants.d.ts +1 -0
- package/esm/constants.js +1 -0
- package/esm/decorators/{entity-resource.decorator.d.ts → api-entity-resource.decorator.d.ts} +1 -1
- package/esm/decorators/{entity-resource.decorator.js → api-entity-resource.decorator.js} +0 -0
- package/esm/decorators/api-resolver.decorator.d.ts +2 -0
- package/esm/decorators/api-resolver.decorator.js +9 -0
- 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/adapter.d.ts +1 -5
- package/esm/implementation/adapter/adapter.js +32 -2
- package/esm/implementation/adapter/http-adapter.d.ts +2 -1
- package/esm/implementation/adapter/http-adapter.js +118 -91
- package/esm/implementation/data-type/complex-type.d.ts +1 -0
- package/esm/implementation/data-type/complex-type.js +13 -0
- package/esm/implementation/data-type/data-type.d.ts +2 -0
- package/esm/implementation/data-type/data-type.js +12 -0
- package/esm/implementation/data-type/entity-type.js +3 -3
- package/esm/implementation/opra-document.js +2 -6
- package/esm/implementation/opra-service.d.ts +1 -0
- package/esm/implementation/opra-service.js +21 -0
- package/esm/implementation/resource/entity-resource-handler.d.ts +1 -1
- package/esm/implementation/resource/entity-resource-handler.js +35 -12
- package/esm/implementation/resource/resource-handler.d.ts +3 -3
- package/esm/implementation/resource/resource-handler.js +13 -0
- package/esm/implementation/schema-generator.js +33 -12
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/interfaces/metadata/api-resolver.metadata.d.ts +3 -0
- package/esm/interfaces/{opra-schema.metadata.js → metadata/api-resolver.metadata.js} +0 -0
- package/esm/interfaces/metadata/opra-schema.metadata.d.ts +7 -0
- package/esm/interfaces/metadata/opra-schema.metadata.js +10 -0
- package/esm/interfaces/query.interface.d.ts +13 -5
- package/esm/interfaces/query.interface.js +19 -2
- package/esm/services/json-data-service.d.ts +66 -7
- package/esm/services/json-data-service.js +235 -4
- package/esm/types.d.ts +10 -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/i18n/en/error.json +3 -0
- package/package.json +6 -7
- package/esm/interfaces/opra-schema.metadata.d.ts +0 -14
|
@@ -6,7 +6,6 @@ const schema_1 = require("@opra/schema");
|
|
|
6
6
|
const constants_js_1 = require("../constants.js");
|
|
7
7
|
const class_utils_js_1 = require("../utils/class-utils.js");
|
|
8
8
|
const internal_data_types_js_1 = require("../utils/internal-data-types.js");
|
|
9
|
-
var isDataType = schema_1.OpraSchema.isDataType;
|
|
10
9
|
const entityMethods = ['search', 'count', 'create', 'get', 'update', 'updateMany', 'delete', 'deleteMany'];
|
|
11
10
|
class SchemaGenerator {
|
|
12
11
|
_dataTypes = {};
|
|
@@ -58,7 +57,7 @@ class SchemaGenerator {
|
|
|
58
57
|
}
|
|
59
58
|
return this.addDataType(schema);
|
|
60
59
|
}
|
|
61
|
-
if (!isDataType(thunk))
|
|
60
|
+
if (!schema_1.OpraSchema.isDataType(thunk))
|
|
62
61
|
throw new TypeError(`Invalid data type schema`);
|
|
63
62
|
// Check if datatype previously added
|
|
64
63
|
const currentSchema = this._dataTypes[thunk.name];
|
|
@@ -92,16 +91,25 @@ class SchemaGenerator {
|
|
|
92
91
|
...metadata,
|
|
93
92
|
type,
|
|
94
93
|
name,
|
|
95
|
-
instance
|
|
94
|
+
instance,
|
|
95
|
+
resolvers: {}
|
|
96
96
|
};
|
|
97
97
|
if (schema_1.OpraSchema.isEntityResource(resourceSchema)) {
|
|
98
98
|
for (const methodName of entityMethods) {
|
|
99
|
-
let fn = instance[
|
|
100
|
-
if (typeof fn === 'function')
|
|
101
|
-
resourceSchema[
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
let fn = instance[methodName];
|
|
100
|
+
if (typeof fn === 'function') {
|
|
101
|
+
const info = resourceSchema.resolvers[methodName] = {
|
|
102
|
+
...Reflect.getMetadata(constants_js_1.RESOLVER_METADATA, proto, methodName)
|
|
103
|
+
};
|
|
104
|
+
if (!info.forbidden) {
|
|
105
|
+
info.handler = fn.bind(instance);
|
|
106
|
+
fn = instance['pre_' + methodName];
|
|
107
|
+
if (typeof fn === 'function')
|
|
108
|
+
resourceSchema['pre_' + methodName] = fn.bind(instance);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
resourceSchema.resolvers[methodName] = { forbidden: true };
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
115
|
}
|
|
@@ -148,8 +156,21 @@ class SchemaGenerator {
|
|
|
148
156
|
await generator.addResource(resource);
|
|
149
157
|
}
|
|
150
158
|
}
|
|
151
|
-
const types = Object.keys(generator._dataTypes)
|
|
152
|
-
.map(name => generator._dataTypes[name])
|
|
159
|
+
const types = Object.keys(generator._dataTypes)
|
|
160
|
+
.map(name => generator._dataTypes[name])
|
|
161
|
+
.sort((a, b) => {
|
|
162
|
+
if (a.kind !== b.kind) {
|
|
163
|
+
if (a.kind === 'SimpleType')
|
|
164
|
+
return -1;
|
|
165
|
+
if (b.kind === 'SimpleType')
|
|
166
|
+
return 1;
|
|
167
|
+
if (a.kind === 'ComplexType')
|
|
168
|
+
return -1;
|
|
169
|
+
if (b.kind === 'ComplexType')
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
return (a.name < b.name ? -1 : 1);
|
|
173
|
+
});
|
|
153
174
|
const resources = Object.keys(generator._resources).sort()
|
|
154
175
|
.map(name => generator._resources[name]);
|
|
155
176
|
return {
|
package/cjs/index.js
CHANGED
|
@@ -6,7 +6,7 @@ tslib_1.__exportStar(require("./constants.js"), exports);
|
|
|
6
6
|
tslib_1.__exportStar(require("./types.js"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./enums/index.js"), exports);
|
|
8
8
|
tslib_1.__exportStar(require("./exception/index.js"), exports);
|
|
9
|
-
tslib_1.__exportStar(require("./decorators/entity-resource.decorator.js"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./decorators/api-entity-resource.decorator.js"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./interfaces/execution-context.interface.js"), exports);
|
|
11
11
|
tslib_1.__exportStar(require("./interfaces/query.interface.js"), exports);
|
|
12
12
|
tslib_1.__exportStar(require("./interfaces/resource-container.interface.js"), exports);
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/*
|
|
4
|
+
export type ResourceReadOperationMetadata = StrictOmit<OpraSchema.ResourceReadOperation, 'handler'>;
|
|
5
|
+
export type ResourceSearchOperationMetadata = StrictOmit<OpraSchema.ResourceSearchOperation, 'handler'>;
|
|
6
|
+
export type ResourceCreateOperationMetadata = StrictOmit<OpraSchema.ResourceCreateOperation, 'handler'>;
|
|
7
|
+
export type ResourceUpdateOperationMetadata = StrictOmit<OpraSchema.ResourceUpdateOperation, 'handler'>;
|
|
8
|
+
export type ResourcePatchOperationMetadata = StrictOmit<OpraSchema.ResourcePatchOperation, 'handler'>;
|
|
9
|
+
export type ResourceDeleteOperationMetadata = StrictOmit<OpraSchema.ResourceDeleteOperation, 'handler'>;
|
|
10
|
+
export type ResourceExecuteOperationMetadata = StrictOmit<OpraSchema.ResourceExecuteOperation, 'handler'>;
|
|
11
|
+
*/
|
|
@@ -25,7 +25,24 @@ var OpraQuery;
|
|
|
25
25
|
return out;
|
|
26
26
|
}
|
|
27
27
|
OpraQuery.forCreate = forCreate;
|
|
28
|
-
function
|
|
28
|
+
function forGetMetadata(resourcePath, options) {
|
|
29
|
+
// if (options?.pick)
|
|
30
|
+
// options.pick = normalizePick(resource, options.pick);
|
|
31
|
+
// if (options?.omit)
|
|
32
|
+
// options.omit = normalizePick(resource, options.omit);
|
|
33
|
+
// if (options?.include)
|
|
34
|
+
// options.include = normalizePick(resource, options.include);
|
|
35
|
+
const out = {
|
|
36
|
+
queryType: 'metadata',
|
|
37
|
+
scope: 'instance',
|
|
38
|
+
resourcePath,
|
|
39
|
+
operation: 'read',
|
|
40
|
+
};
|
|
41
|
+
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
OpraQuery.forGetMetadata = forGetMetadata;
|
|
45
|
+
function forGetEntity(resource, key, options) {
|
|
29
46
|
if (options?.pick)
|
|
30
47
|
options.pick = normalizePick(resource, options.pick);
|
|
31
48
|
if (options?.omit)
|
|
@@ -43,7 +60,7 @@ var OpraQuery;
|
|
|
43
60
|
Object.assign(out, lodash_1.default.omit(options, Object.keys(out)));
|
|
44
61
|
return out;
|
|
45
62
|
}
|
|
46
|
-
OpraQuery.
|
|
63
|
+
OpraQuery.forGetEntity = forGetEntity;
|
|
47
64
|
function forSearch(resource, options) {
|
|
48
65
|
if (options?.pick)
|
|
49
66
|
options.pick = normalizePick(resource, options.pick);
|
|
@@ -2,14 +2,245 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.JsonDataService = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
5
6
|
const rule_judgment_1 = tslib_1.__importDefault(require("rule-judgment"));
|
|
6
|
-
const
|
|
7
|
+
const url_1 = require("@opra/url");
|
|
8
|
+
const index_js_1 = require("../exception/index.js");
|
|
7
9
|
// Fix invalid importing (with ESM) of rule-judgment package
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
+
const createFilterFn = typeof rule_judgment_1.default === 'function'
|
|
11
|
+
? rule_judgment_1.default
|
|
12
|
+
: rule_judgment_1.default.default;
|
|
13
|
+
class JsonDataService {
|
|
14
|
+
resourceName;
|
|
10
15
|
data;
|
|
16
|
+
primaryKey;
|
|
11
17
|
constructor(args) {
|
|
12
|
-
|
|
18
|
+
this.resourceName = args.resourceName;
|
|
19
|
+
this.data = args.data;
|
|
20
|
+
this.primaryKey = args.primaryKey;
|
|
21
|
+
}
|
|
22
|
+
processRequest(ctx) {
|
|
23
|
+
const prepared = JsonDataService.prepare(ctx.query);
|
|
24
|
+
const fn = this[prepared.method];
|
|
25
|
+
if (!fn)
|
|
26
|
+
throw new TypeError(`Unimplemented method (${prepared.method})`);
|
|
27
|
+
return fn.apply(this, prepared.args);
|
|
28
|
+
}
|
|
29
|
+
get(keyValue, options) {
|
|
30
|
+
const primaryKey = this.primaryKey;
|
|
31
|
+
let v = this.data.find(x => '' + x[primaryKey] === '' + keyValue);
|
|
32
|
+
v = JsonDataService.filterProperties(v, options?.pick, options?.omit, options?.include);
|
|
33
|
+
return v;
|
|
34
|
+
}
|
|
35
|
+
count(options) {
|
|
36
|
+
return this.search(options).length;
|
|
37
|
+
}
|
|
38
|
+
search(options) {
|
|
39
|
+
let out;
|
|
40
|
+
if (options?.filter) {
|
|
41
|
+
const filter = JsonDataService.convertFilter(options.filter);
|
|
42
|
+
const filterFn = createFilterFn(filter);
|
|
43
|
+
out = this.data.filter(filterFn);
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
out = this.data;
|
|
47
|
+
return out.map(v => JsonDataService.filterProperties(v, options?.pick, options?.omit, options?.include));
|
|
48
|
+
}
|
|
49
|
+
create(data, options) {
|
|
50
|
+
if (this.get(data[this.primaryKey]))
|
|
51
|
+
throw new index_js_1.ResourceConflictError(this.resourceName, this.primaryKey);
|
|
52
|
+
this.data.push(data);
|
|
53
|
+
return JsonDataService.filterProperties(data, options?.pick, options?.omit, options?.include);
|
|
54
|
+
}
|
|
55
|
+
update(keyValue, data, options) {
|
|
56
|
+
const primaryKey = this.primaryKey;
|
|
57
|
+
const i = this.data.findIndex(x => '' + x[primaryKey] === '' + keyValue);
|
|
58
|
+
if (i >= 0) {
|
|
59
|
+
data = Object.assign(this.data[i], data);
|
|
60
|
+
return JsonDataService.filterProperties(data, options?.pick, options?.omit, options?.include);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
updateMany(data, options) {
|
|
64
|
+
const items = this.search({ filter: options?.filter });
|
|
65
|
+
for (let i = 0; i < items.length; i++) {
|
|
66
|
+
Object.assign(items[i], data);
|
|
67
|
+
}
|
|
68
|
+
return items.length;
|
|
69
|
+
}
|
|
70
|
+
delete(keyValue) {
|
|
71
|
+
const primaryKey = this.primaryKey;
|
|
72
|
+
const i = this.data.findIndex(x => '' + x[primaryKey] === '' + keyValue);
|
|
73
|
+
if (i >= 0) {
|
|
74
|
+
this.data = this.data.slice(i, 1);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
deleteMany(options) {
|
|
80
|
+
const items = this.search({ filter: options?.filter });
|
|
81
|
+
this.data = this.data.filter(x => !items.includes(x));
|
|
82
|
+
return items.length;
|
|
83
|
+
}
|
|
84
|
+
static filterProperties(obj, pick, omit, include) {
|
|
85
|
+
if (!obj)
|
|
86
|
+
return;
|
|
87
|
+
return obj;
|
|
88
|
+
}
|
|
89
|
+
static prepare(query) {
|
|
90
|
+
switch (query.queryType) {
|
|
91
|
+
case 'create': {
|
|
92
|
+
const options = lodash_1.default.omitBy({
|
|
93
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
94
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
95
|
+
include: query.include?.length ? query.include : undefined,
|
|
96
|
+
}, lodash_1.default.isNil);
|
|
97
|
+
const { data } = query;
|
|
98
|
+
return {
|
|
99
|
+
method: query.queryType,
|
|
100
|
+
values: data,
|
|
101
|
+
options,
|
|
102
|
+
args: [data, options]
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
case 'get': {
|
|
106
|
+
const options = lodash_1.default.omitBy({
|
|
107
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
108
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
109
|
+
include: query.include?.length ? query.include : undefined,
|
|
110
|
+
}, lodash_1.default.isNil);
|
|
111
|
+
const keyValue = query.keyValue;
|
|
112
|
+
return {
|
|
113
|
+
method: query.queryType,
|
|
114
|
+
keyValue,
|
|
115
|
+
options,
|
|
116
|
+
args: [keyValue, options]
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
case 'search': {
|
|
120
|
+
const options = lodash_1.default.omitBy({
|
|
121
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
122
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
123
|
+
include: query.include?.length ? query.include : undefined,
|
|
124
|
+
sort: query.sort?.length ? query.sort : undefined,
|
|
125
|
+
limit: query.limit,
|
|
126
|
+
offset: query.skip,
|
|
127
|
+
distinct: query.distinct,
|
|
128
|
+
total: query.count,
|
|
129
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
130
|
+
}, lodash_1.default.isNil);
|
|
131
|
+
return {
|
|
132
|
+
method: query.queryType,
|
|
133
|
+
options,
|
|
134
|
+
args: [options]
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case 'update': {
|
|
138
|
+
const options = lodash_1.default.omitBy({
|
|
139
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
140
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
141
|
+
include: query.include?.length ? query.include : undefined,
|
|
142
|
+
}, lodash_1.default.isNil);
|
|
143
|
+
const { data } = query;
|
|
144
|
+
const keyValue = query.keyValue;
|
|
145
|
+
return {
|
|
146
|
+
method: query.queryType,
|
|
147
|
+
keyValue: query.keyValue,
|
|
148
|
+
values: data,
|
|
149
|
+
options,
|
|
150
|
+
args: [keyValue, data, options]
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
case 'updateMany': {
|
|
154
|
+
const options = lodash_1.default.omitBy({
|
|
155
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
156
|
+
}, lodash_1.default.isNil);
|
|
157
|
+
const { data } = query;
|
|
158
|
+
return {
|
|
159
|
+
method: query.queryType,
|
|
160
|
+
options,
|
|
161
|
+
args: [data, options]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
case 'delete': {
|
|
165
|
+
const options = {};
|
|
166
|
+
const keyValue = query.keyValue;
|
|
167
|
+
return {
|
|
168
|
+
method: query.queryType,
|
|
169
|
+
keyValue,
|
|
170
|
+
options,
|
|
171
|
+
args: [keyValue, options]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
case 'deleteMany': {
|
|
175
|
+
const options = lodash_1.default.omitBy({
|
|
176
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
177
|
+
}, lodash_1.default.isNil);
|
|
178
|
+
return {
|
|
179
|
+
method: query.queryType,
|
|
180
|
+
options,
|
|
181
|
+
args: [options]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
default:
|
|
185
|
+
throw new Error(`Unimplemented query type "${query.queryType}"`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
static convertFilter(str) {
|
|
189
|
+
const ast = typeof str === 'string'
|
|
190
|
+
? (0, url_1.$parse)(str)
|
|
191
|
+
: str;
|
|
192
|
+
if (!ast || !(ast instanceof url_1.Expression))
|
|
193
|
+
return ast;
|
|
194
|
+
if (ast instanceof url_1.ComparisonExpression) {
|
|
195
|
+
const left = JsonDataService.convertFilter(ast.left);
|
|
196
|
+
const right = JsonDataService.convertFilter(ast.right);
|
|
197
|
+
switch (ast.op) {
|
|
198
|
+
case '=':
|
|
199
|
+
return { $eq: { [left]: right } };
|
|
200
|
+
case '!=':
|
|
201
|
+
return { $ne: { [left]: right } };
|
|
202
|
+
case '>':
|
|
203
|
+
return { $gt: { [left]: right } };
|
|
204
|
+
case '>=':
|
|
205
|
+
return { $gte: { [left]: right } };
|
|
206
|
+
case '<':
|
|
207
|
+
return { $lt: { [left]: right } };
|
|
208
|
+
case '<=':
|
|
209
|
+
return { $lte: { [left]: right } };
|
|
210
|
+
case 'in':
|
|
211
|
+
return { $in: { [left]: right } };
|
|
212
|
+
case '!in':
|
|
213
|
+
return { $nin: { [left]: right } };
|
|
214
|
+
default:
|
|
215
|
+
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (ast instanceof url_1.QualifiedIdentifier) {
|
|
219
|
+
return ast.value;
|
|
220
|
+
}
|
|
221
|
+
if (ast instanceof url_1.NumberLiteral ||
|
|
222
|
+
ast instanceof url_1.StringLiteral ||
|
|
223
|
+
ast instanceof url_1.BooleanLiteral ||
|
|
224
|
+
ast instanceof url_1.NullLiteral ||
|
|
225
|
+
ast instanceof url_1.DateLiteral ||
|
|
226
|
+
ast instanceof url_1.TimeLiteral) {
|
|
227
|
+
return ast.value;
|
|
228
|
+
}
|
|
229
|
+
if (ast instanceof url_1.ArrayExpression) {
|
|
230
|
+
return ast.items.map(JsonDataService.convertFilter);
|
|
231
|
+
}
|
|
232
|
+
if (ast instanceof url_1.LogicalExpression) {
|
|
233
|
+
if (ast.op === 'or')
|
|
234
|
+
return { $or: ast.items.map(JsonDataService.convertFilter) };
|
|
235
|
+
return { $and: ast.items.map(JsonDataService.convertFilter) };
|
|
236
|
+
}
|
|
237
|
+
if (ast instanceof url_1.ArrayExpression) {
|
|
238
|
+
return ast.items.map(JsonDataService.convertFilter);
|
|
239
|
+
}
|
|
240
|
+
if (ast instanceof url_1.ParenthesesExpression) {
|
|
241
|
+
return JsonDataService.convertFilter(ast.expression);
|
|
242
|
+
}
|
|
243
|
+
throw new Error(`${ast.type} is not implemented yet`);
|
|
13
244
|
}
|
|
14
245
|
}
|
|
15
246
|
exports.JsonDataService = JsonDataService;
|
package/cjs/utils/create-i18n.js
CHANGED
|
@@ -8,8 +8,8 @@ const get_caller_file_util_js_1 = require("./get-caller-file.util.js");
|
|
|
8
8
|
async function createI18n(options) {
|
|
9
9
|
const opts = {
|
|
10
10
|
...options,
|
|
11
|
-
resourceDirs: undefined
|
|
12
11
|
};
|
|
12
|
+
delete opts.resourceDirs;
|
|
13
13
|
const instance = i18n_1.I18n.createInstance(opts);
|
|
14
14
|
await instance.init();
|
|
15
15
|
await instance.loadResourceDir(path_1.default.resolve((0, get_caller_file_util_js_1.getCallerFile)(), '../../../i18n'));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCallerFile = void 0;
|
|
4
|
+
const PATH_PATTERN = /^(?:file:\/\/)?(.+)$/;
|
|
4
5
|
function getCallerFile(position = 1) {
|
|
5
6
|
if (position >= Error.stackTraceLimit) {
|
|
6
7
|
throw new TypeError('getCallerFile(position) requires position be less then Error.stackTraceLimit but position was: `' +
|
|
@@ -13,7 +14,11 @@ function getCallerFile(position = 1) {
|
|
|
13
14
|
if (stack !== null && typeof stack === 'object') {
|
|
14
15
|
// stack[0] holds this file
|
|
15
16
|
// stack[1] holds where this function was called
|
|
16
|
-
|
|
17
|
+
const s = stack[position] ?
|
|
18
|
+
stack[position].getFileName() : undefined;
|
|
19
|
+
const m = s ? PATH_PATTERN.exec(s) : undefined;
|
|
20
|
+
return m ? m[1] : '';
|
|
17
21
|
}
|
|
22
|
+
return '';
|
|
18
23
|
}
|
|
19
24
|
exports.getCallerFile = getCallerFile;
|
package/esm/constants.d.ts
CHANGED
package/esm/constants.js
CHANGED
package/esm/decorators/{entity-resource.decorator.d.ts → api-entity-resource.decorator.d.ts}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
import { EntityResourceMetadata } from '../interfaces/opra-schema.metadata.js';
|
|
2
|
+
import { EntityResourceMetadata } from '../interfaces/metadata/opra-schema.metadata.js';
|
|
3
3
|
import { TypeThunkAsync } from '../types.js';
|
|
4
4
|
export declare type EntityResourceOptions = Pick<EntityResourceMetadata, 'name' | 'description'> & {};
|
|
5
5
|
export declare function ApiEntityResource(entityFunc: TypeThunkAsync, options?: EntityResourceOptions): (target: Function) => void;
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ApiException, ErrorResponse } from '../api-exception.js';
|
|
2
|
+
/**
|
|
3
|
+
* 406 Not Acceptable
|
|
4
|
+
* This response is sent when the web server, after performing server-driven content negotiation,
|
|
5
|
+
* doesn't find any content that conforms to the criteria given by the user agent.
|
|
6
|
+
*/
|
|
7
|
+
export declare class NotAcceptableError extends ApiException {
|
|
8
|
+
constructor(response?: string | ErrorResponse | Error, cause?: Error);
|
|
9
|
+
protected _initResponse(response: Partial<ErrorResponse>): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { translate } from '@opra/i18n';
|
|
2
|
+
import { HttpStatus } from '../../enums/index.js';
|
|
3
|
+
import { ApiException } from '../api-exception.js';
|
|
4
|
+
/**
|
|
5
|
+
* 406 Not Acceptable
|
|
6
|
+
* This response is sent when the web server, after performing server-driven content negotiation,
|
|
7
|
+
* doesn't find any content that conforms to the criteria given by the user agent.
|
|
8
|
+
*/
|
|
9
|
+
export class NotAcceptableError extends ApiException {
|
|
10
|
+
constructor(response, cause) {
|
|
11
|
+
super(response, cause);
|
|
12
|
+
this.status = HttpStatus.NOT_ACCEPTABLE;
|
|
13
|
+
}
|
|
14
|
+
_initResponse(response) {
|
|
15
|
+
super._initResponse({
|
|
16
|
+
message: translate('error:NOT_ACCEPTABLE', 'Not Acceptable'),
|
|
17
|
+
severity: 'error',
|
|
18
|
+
code: 'NOT_ACCEPTABLE',
|
|
19
|
+
...response
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
package/esm/exception/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ export * from './http-errors/failed-dependency.error.js';
|
|
|
4
4
|
export * from './http-errors/forbidden.error.js';
|
|
5
5
|
export * from './http-errors/internal-server.error.js';
|
|
6
6
|
export * from './http-errors/method-not-allowed.error.js';
|
|
7
|
+
export * from './http-errors/not-acceptable.error.js';
|
|
7
8
|
export * from './http-errors/not-found.error.js';
|
|
8
9
|
export * from './http-errors/unauthorized.error.js';
|
|
9
10
|
export * from './http-errors/unprocessable-entity.error.js';
|
|
10
11
|
export * from './resource-errors/resource-conflict.error.js';
|
|
12
|
+
export * from './resource-errors/resource-not-found.error.js';
|
package/esm/exception/index.js
CHANGED
|
@@ -4,7 +4,9 @@ export * from './http-errors/failed-dependency.error.js';
|
|
|
4
4
|
export * from './http-errors/forbidden.error.js';
|
|
5
5
|
export * from './http-errors/internal-server.error.js';
|
|
6
6
|
export * from './http-errors/method-not-allowed.error.js';
|
|
7
|
+
export * from './http-errors/not-acceptable.error.js';
|
|
7
8
|
export * from './http-errors/not-found.error.js';
|
|
8
9
|
export * from './http-errors/unauthorized.error.js';
|
|
9
10
|
export * from './http-errors/unprocessable-entity.error.js';
|
|
10
11
|
export * from './resource-errors/resource-conflict.error.js';
|
|
12
|
+
export * from './resource-errors/resource-not-found.error.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { translate } from '@opra/i18n';
|
|
2
|
+
import { HttpStatus } from '../../enums/index.js';
|
|
3
|
+
import { ApiException } from '../api-exception.js';
|
|
4
|
+
export class ResourceNotFoundError extends ApiException {
|
|
5
|
+
constructor(resource, keyValue, cause) {
|
|
6
|
+
super({
|
|
7
|
+
message: translate(`error:RESOURCE_NOT_FOUND`, { resource: resource + '@' + keyValue }),
|
|
8
|
+
severity: 'error',
|
|
9
|
+
code: 'RESOURCE_NOT_FOUND',
|
|
10
|
+
subject: resource,
|
|
11
|
+
key: keyValue
|
|
12
|
+
}, cause);
|
|
13
|
+
this.status = HttpStatus.NOT_FOUND;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -8,11 +8,6 @@ export declare namespace OpraAdapter {
|
|
|
8
8
|
executionContext: IExecutionContext;
|
|
9
9
|
isBatch: boolean;
|
|
10
10
|
}) => object | Promise<object>;
|
|
11
|
-
type RequestFinishEvent = (args: {
|
|
12
|
-
executionContext: IExecutionContext;
|
|
13
|
-
userContext?: any;
|
|
14
|
-
failed: boolean;
|
|
15
|
-
}) => Promise<void>;
|
|
16
11
|
interface Options {
|
|
17
12
|
i18n?: I18n | I18nOptions | (() => Promise<I18n>);
|
|
18
13
|
userContext?: UserContextResolver;
|
|
@@ -57,5 +52,6 @@ export declare abstract class OpraAdapter<TExecutionContext extends IExecutionCo
|
|
|
57
52
|
protected abstract sendError(executionContext: TExecutionContext, error: ApiException): Promise<void>;
|
|
58
53
|
protected abstract isBatch(executionContext: TExecutionContext): boolean;
|
|
59
54
|
protected handler(executionContext: TExecutionContext): Promise<void>;
|
|
55
|
+
protected _metadataExecute(ctx: QueryContext): Promise<void>;
|
|
60
56
|
protected static initI18n(options?: OpraAdapter.Options): Promise<I18n>;
|
|
61
57
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
2
|
import { I18n } from '@opra/i18n';
|
|
3
|
-
import { FailedDependencyError } from '../../exception/index.js';
|
|
3
|
+
import { BadRequestError, FailedDependencyError } from '../../exception/index.js';
|
|
4
4
|
import { wrapError } from '../../exception/wrap-error.js';
|
|
5
5
|
import { createI18n } from '../../utils/create-i18n.js';
|
|
6
6
|
export class OpraAdapter {
|
|
@@ -38,8 +38,12 @@ export class OpraAdapter {
|
|
|
38
38
|
continue;
|
|
39
39
|
}
|
|
40
40
|
try {
|
|
41
|
-
const resource = context.query.resource;
|
|
42
41
|
const promise = (async () => {
|
|
42
|
+
if (context.query.queryType === 'metadata') {
|
|
43
|
+
await this._metadataExecute(context);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const resource = context.query.resource;
|
|
43
47
|
await resource.prepare(context);
|
|
44
48
|
if (this.userContextResolver && !userContext)
|
|
45
49
|
userContext = this.userContextResolver({
|
|
@@ -88,6 +92,32 @@ export class OpraAdapter {
|
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
}
|
|
95
|
+
async _metadataExecute(ctx) {
|
|
96
|
+
const query = ctx.query;
|
|
97
|
+
let out;
|
|
98
|
+
if (query.resourcePath.length > 2)
|
|
99
|
+
throw new BadRequestError();
|
|
100
|
+
if (query.resourcePath?.length) {
|
|
101
|
+
if (query.resourcePath[0] === 'resources') {
|
|
102
|
+
const resource = this.service.getResource(query.resourcePath[1]);
|
|
103
|
+
out = resource.getMetadata();
|
|
104
|
+
query.resourcePath[1] = resource.name;
|
|
105
|
+
}
|
|
106
|
+
else if (query.resourcePath[0] === 'types') {
|
|
107
|
+
const dataType = this.service.getDataType(query.resourcePath[1]);
|
|
108
|
+
out = dataType.getMetadata();
|
|
109
|
+
query.resourcePath[1] = dataType.name;
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
throw new BadRequestError();
|
|
113
|
+
ctx.response.value = {
|
|
114
|
+
'@opra:metadata': '/$metadata/' + query.resourcePath.join('/'),
|
|
115
|
+
...out
|
|
116
|
+
};
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
ctx.response.value = this.service.getMetadata();
|
|
120
|
+
}
|
|
91
121
|
static async initI18n(options) {
|
|
92
122
|
if (options?.i18n instanceof I18n)
|
|
93
123
|
return options.i18n;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpraURL } from '@opra/url';
|
|
2
2
|
import { ApiException } from '../../exception/index.js';
|
|
3
3
|
import { IHttpExecutionContext } from '../../interfaces/execution-context.interface.js';
|
|
4
|
-
import { OpraQuery } from '../../interfaces/query.interface.js';
|
|
4
|
+
import { OpraMetadataQuery, OpraQuery } from '../../interfaces/query.interface.js';
|
|
5
5
|
import { HeadersObject } from '../../utils/headers.js';
|
|
6
6
|
import { QueryContext } from '../query-context.js';
|
|
7
7
|
import { OpraAdapter } from './adapter.js';
|
|
@@ -18,6 +18,7 @@ interface PreparedOutput {
|
|
|
18
18
|
export declare class OpraHttpAdapter<TExecutionContext extends IHttpExecutionContext> extends OpraAdapter<IHttpExecutionContext> {
|
|
19
19
|
protected prepareRequests(executionContext: TExecutionContext): QueryContext[];
|
|
20
20
|
prepareRequest(executionContext: IHttpExecutionContext, url: OpraURL, method: string, headers: HeadersObject, body?: any): QueryContext;
|
|
21
|
+
buildMetadataQuery(url: OpraURL): OpraMetadataQuery;
|
|
21
22
|
buildQuery(url: OpraURL, method: string, body?: any): OpraQuery | undefined;
|
|
22
23
|
protected sendResponse(executionContext: TExecutionContext, queryContexts: QueryContext[]): Promise<void>;
|
|
23
24
|
protected isBatch(executionContext: TExecutionContext): boolean;
|