@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
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.OpraQuery = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const schema_1 = require("@opra/schema");
|
|
7
|
+
const path_to_tree_js_1 = require("../utils/path-to-tree.js");
|
|
8
8
|
var OpraQuery;
|
|
9
9
|
(function (OpraQuery) {
|
|
10
10
|
function forCreate(resource, values, options) {
|
|
@@ -25,7 +25,24 @@ var OpraQuery;
|
|
|
25
25
|
return out;
|
|
26
26
|
}
|
|
27
27
|
OpraQuery.forCreate = forCreate;
|
|
28
|
-
function
|
|
28
|
+
function forGetSchema(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: 'schema',
|
|
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.forGetSchema = forGetSchema;
|
|
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);
|
|
@@ -151,19 +168,19 @@ function checkKeyFields(resource, key) {
|
|
|
151
168
|
throw new Error(`"${resource.name}" has no primary key`);
|
|
152
169
|
}
|
|
153
170
|
function normalizePick(resource, fields) {
|
|
154
|
-
const fieldsTree = (0,
|
|
171
|
+
const fieldsTree = (0, path_to_tree_js_1.pathToTree)(fields) || {};
|
|
155
172
|
return _normalizeFieldsList([], resource.service, resource, resource.dataType, fieldsTree, '', {
|
|
156
|
-
|
|
173
|
+
additionalFields: true
|
|
157
174
|
});
|
|
158
175
|
}
|
|
159
176
|
function _normalizeFieldsList(target, service, resource, dataType, node, parentPath = '', options) {
|
|
160
177
|
let curPath = '';
|
|
161
178
|
for (const k of Object.keys(node)) {
|
|
162
179
|
const nodeVal = node[k];
|
|
163
|
-
const prop = dataType?.
|
|
180
|
+
const prop = dataType?.fields.get(k);
|
|
164
181
|
if (!prop) {
|
|
165
182
|
curPath = parentPath ? parentPath + '.' + k : k;
|
|
166
|
-
if (!options?.
|
|
183
|
+
if (!options?.additionalFields || (dataType && !dataType.additionalFields))
|
|
167
184
|
throw new TypeError(`Unknown field path "${resource.name + '.' + curPath}"`);
|
|
168
185
|
if (typeof nodeVal === 'object')
|
|
169
186
|
_normalizeFieldsList(target, service, resource, undefined, nodeVal, curPath, options);
|
|
@@ -174,7 +191,7 @@ function _normalizeFieldsList(target, service, resource, dataType, node, parentP
|
|
|
174
191
|
curPath = parentPath ? parentPath + '.' + prop.name : prop.name;
|
|
175
192
|
const propType = service.getDataType(prop.type || 'string');
|
|
176
193
|
if (typeof nodeVal === 'object') {
|
|
177
|
-
if (!(propType instanceof
|
|
194
|
+
if (!(propType && propType instanceof schema_1.ComplexType))
|
|
178
195
|
throw new TypeError(`"${curPath}" is not a complex type and has no sub fields`);
|
|
179
196
|
if (target.findIndex(x => x === parentPath) >= 0)
|
|
180
197
|
continue;
|
|
@@ -2,14 +2,251 @@
|
|
|
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.filterFields(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.filterFields(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.filterFields(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.filterFields(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 filterFields(obj,
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
86
|
+
pick,
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
88
|
+
omit,
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
90
|
+
include) {
|
|
91
|
+
if (!obj)
|
|
92
|
+
return;
|
|
93
|
+
return obj;
|
|
94
|
+
}
|
|
95
|
+
static prepare(query) {
|
|
96
|
+
switch (query.queryType) {
|
|
97
|
+
case 'create': {
|
|
98
|
+
const options = lodash_1.default.omitBy({
|
|
99
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
100
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
101
|
+
include: query.include?.length ? query.include : undefined,
|
|
102
|
+
}, lodash_1.default.isNil);
|
|
103
|
+
const { data } = query;
|
|
104
|
+
return {
|
|
105
|
+
method: query.queryType,
|
|
106
|
+
values: data,
|
|
107
|
+
options,
|
|
108
|
+
args: [data, options]
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
case 'get': {
|
|
112
|
+
const options = lodash_1.default.omitBy({
|
|
113
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
114
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
115
|
+
include: query.include?.length ? query.include : undefined,
|
|
116
|
+
}, lodash_1.default.isNil);
|
|
117
|
+
const keyValue = query.keyValue;
|
|
118
|
+
return {
|
|
119
|
+
method: query.queryType,
|
|
120
|
+
keyValue,
|
|
121
|
+
options,
|
|
122
|
+
args: [keyValue, options]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
case 'search': {
|
|
126
|
+
const options = lodash_1.default.omitBy({
|
|
127
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
128
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
129
|
+
include: query.include?.length ? query.include : undefined,
|
|
130
|
+
sort: query.sort?.length ? query.sort : undefined,
|
|
131
|
+
limit: query.limit,
|
|
132
|
+
offset: query.skip,
|
|
133
|
+
distinct: query.distinct,
|
|
134
|
+
total: query.count,
|
|
135
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
136
|
+
}, lodash_1.default.isNil);
|
|
137
|
+
return {
|
|
138
|
+
method: query.queryType,
|
|
139
|
+
options,
|
|
140
|
+
args: [options]
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
case 'update': {
|
|
144
|
+
const options = lodash_1.default.omitBy({
|
|
145
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
146
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
147
|
+
include: query.include?.length ? query.include : undefined,
|
|
148
|
+
}, lodash_1.default.isNil);
|
|
149
|
+
const { data } = query;
|
|
150
|
+
const keyValue = query.keyValue;
|
|
151
|
+
return {
|
|
152
|
+
method: query.queryType,
|
|
153
|
+
keyValue: query.keyValue,
|
|
154
|
+
values: data,
|
|
155
|
+
options,
|
|
156
|
+
args: [keyValue, data, options]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
case 'updateMany': {
|
|
160
|
+
const options = lodash_1.default.omitBy({
|
|
161
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
162
|
+
}, lodash_1.default.isNil);
|
|
163
|
+
const { data } = query;
|
|
164
|
+
return {
|
|
165
|
+
method: query.queryType,
|
|
166
|
+
options,
|
|
167
|
+
args: [data, options]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
case 'delete': {
|
|
171
|
+
const options = {};
|
|
172
|
+
const keyValue = query.keyValue;
|
|
173
|
+
return {
|
|
174
|
+
method: query.queryType,
|
|
175
|
+
keyValue,
|
|
176
|
+
options,
|
|
177
|
+
args: [keyValue, options]
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
case 'deleteMany': {
|
|
181
|
+
const options = lodash_1.default.omitBy({
|
|
182
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
183
|
+
}, lodash_1.default.isNil);
|
|
184
|
+
return {
|
|
185
|
+
method: query.queryType,
|
|
186
|
+
options,
|
|
187
|
+
args: [options]
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
default:
|
|
191
|
+
throw new Error(`Unimplemented query type "${query.queryType}"`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
static convertFilter(str) {
|
|
195
|
+
const ast = typeof str === 'string'
|
|
196
|
+
? (0, url_1.$parse)(str)
|
|
197
|
+
: str;
|
|
198
|
+
if (!ast || !(ast instanceof url_1.Expression))
|
|
199
|
+
return ast;
|
|
200
|
+
if (ast instanceof url_1.ComparisonExpression) {
|
|
201
|
+
const left = JsonDataService.convertFilter(ast.left);
|
|
202
|
+
const right = JsonDataService.convertFilter(ast.right);
|
|
203
|
+
switch (ast.op) {
|
|
204
|
+
case '=':
|
|
205
|
+
return { $eq: { [left]: right } };
|
|
206
|
+
case '!=':
|
|
207
|
+
return { $ne: { [left]: right } };
|
|
208
|
+
case '>':
|
|
209
|
+
return { $gt: { [left]: right } };
|
|
210
|
+
case '>=':
|
|
211
|
+
return { $gte: { [left]: right } };
|
|
212
|
+
case '<':
|
|
213
|
+
return { $lt: { [left]: right } };
|
|
214
|
+
case '<=':
|
|
215
|
+
return { $lte: { [left]: right } };
|
|
216
|
+
case 'in':
|
|
217
|
+
return { $in: { [left]: right } };
|
|
218
|
+
case '!in':
|
|
219
|
+
return { $nin: { [left]: right } };
|
|
220
|
+
default:
|
|
221
|
+
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (ast instanceof url_1.QualifiedIdentifier) {
|
|
225
|
+
return ast.value;
|
|
226
|
+
}
|
|
227
|
+
if (ast instanceof url_1.NumberLiteral ||
|
|
228
|
+
ast instanceof url_1.StringLiteral ||
|
|
229
|
+
ast instanceof url_1.BooleanLiteral ||
|
|
230
|
+
ast instanceof url_1.NullLiteral ||
|
|
231
|
+
ast instanceof url_1.DateLiteral ||
|
|
232
|
+
ast instanceof url_1.TimeLiteral) {
|
|
233
|
+
return ast.value;
|
|
234
|
+
}
|
|
235
|
+
if (ast instanceof url_1.ArrayExpression) {
|
|
236
|
+
return ast.items.map(JsonDataService.convertFilter);
|
|
237
|
+
}
|
|
238
|
+
if (ast instanceof url_1.LogicalExpression) {
|
|
239
|
+
if (ast.op === 'or')
|
|
240
|
+
return { $or: ast.items.map(JsonDataService.convertFilter) };
|
|
241
|
+
return { $and: ast.items.map(JsonDataService.convertFilter) };
|
|
242
|
+
}
|
|
243
|
+
if (ast instanceof url_1.ArrayExpression) {
|
|
244
|
+
return ast.items.map(JsonDataService.convertFilter);
|
|
245
|
+
}
|
|
246
|
+
if (ast instanceof url_1.ParenthesesExpression) {
|
|
247
|
+
return JsonDataService.convertFilter(ast.expression);
|
|
248
|
+
}
|
|
249
|
+
throw new Error(`${ast.type} is not implemented yet`);
|
|
13
250
|
}
|
|
14
251
|
}
|
|
15
252
|
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;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.pathToTree = void 0;
|
|
4
4
|
const dotPattern = /^([^.]+)\.(.*)$/;
|
|
5
|
-
function
|
|
5
|
+
function pathToTree(arr) {
|
|
6
6
|
if (!arr.length)
|
|
7
7
|
return;
|
|
8
8
|
return _stringPathToObjectTree(arr, {});
|
|
9
9
|
}
|
|
10
|
-
exports.
|
|
10
|
+
exports.pathToTree = pathToTree;
|
|
11
11
|
function _stringPathToObjectTree(arr, target) {
|
|
12
12
|
for (const k of arr) {
|
|
13
13
|
const m = dotPattern.exec(k);
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#controls
|
|
3
3
|
*/
|
|
4
4
|
export declare enum HttpHeaders {
|
|
5
|
-
X_Opra_Version = "X-
|
|
5
|
+
X_Opra_Version = "X-OPRA-Version",
|
|
6
|
+
X_Opra_Schema = "X-OPRA-Schema",
|
|
6
7
|
/**
|
|
7
8
|
* Defines the authentication method that should be used to access a resource.
|
|
8
9
|
*/
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
export var HttpHeaders;
|
|
6
6
|
(function (HttpHeaders) {
|
|
7
7
|
/* *** Custom Headers *** */
|
|
8
|
-
HttpHeaders["X_Opra_Version"] = "X-
|
|
8
|
+
HttpHeaders["X_Opra_Version"] = "X-OPRA-Version";
|
|
9
|
+
HttpHeaders["X_Opra_Schema"] = "X-OPRA-Schema";
|
|
9
10
|
/* *** Authentication *** */
|
|
10
11
|
/**
|
|
11
12
|
* Defines the authentication method that should be used to access a resource.
|
|
@@ -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
|
+
}
|
|
@@ -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,18 +1,13 @@
|
|
|
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;
|
|
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 _getSchemaExecute(ctx: QueryContext): Promise<void>;
|
|
60
56
|
protected static initI18n(options?: OpraAdapter.Options): Promise<I18n>;
|
|
61
57
|
}
|