@opra/core 0.5.0 → 0.6.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/adapter/adapter.js +103 -122
- package/cjs/adapter/classes/execution-context.host.js +17 -0
- package/cjs/adapter/classes/express-request-wrapper.host.js +37 -0
- package/cjs/adapter/classes/express-response-wrapper.host.js +56 -0
- package/cjs/adapter/classes/http-execution-context.host.js +31 -0
- package/cjs/adapter/{metadata-resource.js → classes/metadata.resource.js} +3 -3
- package/cjs/adapter/express-adapter.js +6 -104
- package/cjs/adapter/http-adapter.js +270 -68
- package/cjs/adapter/request-contexts/batch-request-context.js +12 -0
- package/cjs/adapter/{query-context.js → request-contexts/request-context.js} +8 -12
- package/cjs/adapter/request-contexts/single-request-context.js +15 -0
- package/cjs/index.js +2 -1
- package/cjs/interfaces/i18n-options.interface.js +2 -0
- package/cjs/services/json-collection-service.js +36 -39
- package/cjs/services/json-singleton-service.js +9 -10
- package/cjs/utils/create-i18n.js +2 -2
- package/esm/adapter/adapter.d.ts +13 -44
- package/esm/adapter/adapter.js +89 -108
- package/esm/adapter/classes/execution-context.host.d.ts +10 -0
- package/esm/adapter/classes/execution-context.host.js +13 -0
- package/esm/adapter/classes/express-request-wrapper.host.d.ts +19 -0
- package/esm/adapter/classes/express-request-wrapper.host.js +33 -0
- package/esm/adapter/classes/express-response-wrapper.host.d.ts +22 -0
- package/esm/adapter/classes/express-response-wrapper.host.js +52 -0
- package/esm/adapter/classes/http-execution-context.host.d.ts +13 -0
- package/esm/adapter/classes/http-execution-context.host.js +27 -0
- package/esm/adapter/classes/metadata.resource.d.ts +8 -0
- package/esm/adapter/{metadata-resource.js → classes/metadata.resource.js} +2 -2
- package/esm/adapter/express-adapter.d.ts +1 -1
- package/esm/adapter/express-adapter.js +5 -103
- package/esm/adapter/http-adapter.d.ts +23 -12
- package/esm/adapter/http-adapter.js +248 -46
- package/esm/adapter/request-contexts/batch-request-context.d.ts +7 -0
- package/esm/adapter/request-contexts/batch-request-context.js +8 -0
- package/esm/adapter/request-contexts/request-context.d.ts +22 -0
- package/esm/adapter/{query-context.js → request-contexts/request-context.js} +6 -10
- package/esm/adapter/request-contexts/single-request-context.d.ts +10 -0
- package/esm/adapter/request-contexts/single-request-context.js +11 -0
- package/esm/index.d.ts +2 -1
- package/esm/index.js +2 -1
- package/esm/interfaces/execution-context.interface.d.ts +19 -11
- package/esm/interfaces/i18n-options.interface.d.ts +28 -0
- package/esm/interfaces/i18n-options.interface.js +1 -0
- package/esm/interfaces/resource.interface.d.ts +1 -1
- package/esm/services/json-collection-service.d.ts +3 -4
- package/esm/services/json-collection-service.js +17 -20
- package/esm/services/json-singleton-service.d.ts +3 -3
- package/esm/services/json-singleton-service.js +8 -8
- package/esm/utils/create-i18n.d.ts +3 -3
- package/esm/utils/create-i18n.js +1 -1
- package/package.json +7 -8
- package/cjs/utils/path-to-tree.js +0 -28
- package/esm/adapter/metadata-resource.d.ts +0 -8
- package/esm/adapter/query-context.d.ts +0 -24
- package/esm/utils/path-to-tree.d.ts +0 -4
- package/esm/utils/path-to-tree.js +0 -24
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.JsonCollectionService = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const lodash_1 =
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
6
|
const putil_merge_1 = tslib_1.__importDefault(require("putil-merge"));
|
|
7
7
|
const core_1 = require("@nano-sql/core");
|
|
8
|
-
const
|
|
9
|
-
const schema_1 = require("@opra/schema");
|
|
10
|
-
const url_1 = require("@opra/url");
|
|
11
|
-
const path_to_tree_js_1 = require("../utils/path-to-tree.js");
|
|
8
|
+
const common_1 = require("@opra/common");
|
|
12
9
|
let dbId = 1;
|
|
13
10
|
const indexingTypes = ['int', 'float', 'number', 'date', 'string'];
|
|
14
11
|
class JsonCollectionService {
|
|
@@ -101,7 +98,7 @@ class JsonCollectionService {
|
|
|
101
98
|
}
|
|
102
99
|
async create(data, options) {
|
|
103
100
|
if (!data[this.primaryKey])
|
|
104
|
-
throw new
|
|
101
|
+
throw new common_1.BadRequestError({
|
|
105
102
|
message: 'You must provide primary key value'
|
|
106
103
|
});
|
|
107
104
|
await this._init();
|
|
@@ -111,7 +108,7 @@ class JsonCollectionService {
|
|
|
111
108
|
.where([this.primaryKey, '=', keyValue])
|
|
112
109
|
.exec();
|
|
113
110
|
if (rows.length)
|
|
114
|
-
throw new
|
|
111
|
+
throw new common_1.ResourceConflictError(this.resourceName, this.primaryKey);
|
|
115
112
|
await (0, core_1.nSQL)(this.resourceName).query('upsert', data)
|
|
116
113
|
.exec();
|
|
117
114
|
return await this.get(keyValue, options);
|
|
@@ -245,16 +242,16 @@ class JsonCollectionService {
|
|
|
245
242
|
}
|
|
246
243
|
}
|
|
247
244
|
_prepare(query) {
|
|
248
|
-
if (query.resource instanceof
|
|
245
|
+
if (query.resource instanceof common_1.CollectionResourceInfo) {
|
|
249
246
|
if (query.dataType !== this.dataType)
|
|
250
247
|
throw new TypeError(`Query data type (${query.dataType.name}) ` +
|
|
251
248
|
`differs from JsonCollectionService data type (${this.dataType.name})`);
|
|
252
249
|
}
|
|
253
250
|
switch (query.method) {
|
|
254
251
|
case 'count': {
|
|
255
|
-
const options = lodash_1.
|
|
252
|
+
const options = (0, lodash_1.omitBy)({
|
|
256
253
|
filter: this._convertFilter(query.filter)
|
|
257
|
-
}, lodash_1.
|
|
254
|
+
}, lodash_1.isNil);
|
|
258
255
|
return {
|
|
259
256
|
method: query.method,
|
|
260
257
|
options,
|
|
@@ -262,11 +259,11 @@ class JsonCollectionService {
|
|
|
262
259
|
};
|
|
263
260
|
}
|
|
264
261
|
case 'create': {
|
|
265
|
-
const options = lodash_1.
|
|
262
|
+
const options = (0, lodash_1.omitBy)({
|
|
266
263
|
pick: query.pick,
|
|
267
264
|
omit: query.omit,
|
|
268
265
|
include: query.include
|
|
269
|
-
}, lodash_1.
|
|
266
|
+
}, lodash_1.isNil);
|
|
270
267
|
const { data } = query;
|
|
271
268
|
return {
|
|
272
269
|
method: query.method,
|
|
@@ -277,11 +274,11 @@ class JsonCollectionService {
|
|
|
277
274
|
}
|
|
278
275
|
case 'get': {
|
|
279
276
|
if (query.kind === 'CollectionGetQuery') {
|
|
280
|
-
const options = lodash_1.
|
|
277
|
+
const options = (0, lodash_1.omitBy)({
|
|
281
278
|
pick: query.pick,
|
|
282
279
|
omit: query.omit,
|
|
283
280
|
include: query.include
|
|
284
|
-
}, lodash_1.
|
|
281
|
+
}, lodash_1.isNil);
|
|
285
282
|
const keyValue = query.keyValue;
|
|
286
283
|
return {
|
|
287
284
|
method: query.method,
|
|
@@ -297,10 +294,10 @@ class JsonCollectionService {
|
|
|
297
294
|
}
|
|
298
295
|
case 'search': {
|
|
299
296
|
if (query.distinct)
|
|
300
|
-
throw new
|
|
297
|
+
throw new common_1.MethodNotAllowedError({
|
|
301
298
|
message: '$distinct parameter is not supported by JsonDataService'
|
|
302
299
|
});
|
|
303
|
-
const options = lodash_1.
|
|
300
|
+
const options = (0, lodash_1.omitBy)({
|
|
304
301
|
pick: query.pick,
|
|
305
302
|
omit: query.omit,
|
|
306
303
|
include: query.include,
|
|
@@ -310,7 +307,7 @@ class JsonCollectionService {
|
|
|
310
307
|
limit: query.limit,
|
|
311
308
|
offset: query.skip,
|
|
312
309
|
count: query.count,
|
|
313
|
-
}, lodash_1.
|
|
310
|
+
}, lodash_1.isNil);
|
|
314
311
|
return {
|
|
315
312
|
method: query.method,
|
|
316
313
|
options,
|
|
@@ -318,11 +315,11 @@ class JsonCollectionService {
|
|
|
318
315
|
};
|
|
319
316
|
}
|
|
320
317
|
case 'update': {
|
|
321
|
-
const options = lodash_1.
|
|
318
|
+
const options = (0, lodash_1.omitBy)({
|
|
322
319
|
pick: query.pick,
|
|
323
320
|
omit: query.omit,
|
|
324
321
|
include: query.include
|
|
325
|
-
}, lodash_1.
|
|
322
|
+
}, lodash_1.isNil);
|
|
326
323
|
const { data } = query;
|
|
327
324
|
const keyValue = query.keyValue;
|
|
328
325
|
return {
|
|
@@ -334,9 +331,9 @@ class JsonCollectionService {
|
|
|
334
331
|
};
|
|
335
332
|
}
|
|
336
333
|
case 'updateMany': {
|
|
337
|
-
const options = lodash_1.
|
|
334
|
+
const options = (0, lodash_1.omitBy)({
|
|
338
335
|
filter: this._convertFilter(query.filter)
|
|
339
|
-
}, lodash_1.
|
|
336
|
+
}, lodash_1.isNil);
|
|
340
337
|
const { data } = query;
|
|
341
338
|
return {
|
|
342
339
|
method: query.method,
|
|
@@ -355,9 +352,9 @@ class JsonCollectionService {
|
|
|
355
352
|
};
|
|
356
353
|
}
|
|
357
354
|
case 'deleteMany': {
|
|
358
|
-
const options = lodash_1.
|
|
355
|
+
const options = (0, lodash_1.omitBy)({
|
|
359
356
|
filter: this._convertFilter(query.filter)
|
|
360
|
-
}, lodash_1.
|
|
357
|
+
}, lodash_1.isNil);
|
|
361
358
|
return {
|
|
362
359
|
method: query.method,
|
|
363
360
|
options,
|
|
@@ -379,7 +376,7 @@ class JsonCollectionService {
|
|
|
379
376
|
if ((((!pick && !f.exclusive) || pick?.[kl])) || include?.[kl]) {
|
|
380
377
|
const fieldType = document.getDataType(f.type);
|
|
381
378
|
const subPath = (path ? path + '.' : '') + f.name;
|
|
382
|
-
if (fieldType instanceof
|
|
379
|
+
if (fieldType instanceof common_1.ComplexType) {
|
|
383
380
|
processDataType(fieldType, subPath, typeof pick?.[kl] === 'object' ? pick?.[kl] : undefined, typeof omit?.[kl] === 'object' ? omit?.[kl] : undefined, typeof include?.[kl] === 'object' ? include?.[kl] : undefined);
|
|
384
381
|
continue;
|
|
385
382
|
}
|
|
@@ -387,16 +384,16 @@ class JsonCollectionService {
|
|
|
387
384
|
}
|
|
388
385
|
}
|
|
389
386
|
};
|
|
390
|
-
processDataType(this.dataType, '', (args.pick ? (0,
|
|
387
|
+
processDataType(this.dataType, '', (args.pick ? (0, common_1.pathToTree)(args.pick, true) : undefined), (args.omit ? (0, common_1.pathToTree)(args.omit, true) : undefined), (args.include ? (0, common_1.pathToTree)(args.include, true) : undefined));
|
|
391
388
|
return result;
|
|
392
389
|
}
|
|
393
390
|
_convertFilter(str) {
|
|
394
391
|
const ast = typeof str === 'string'
|
|
395
|
-
? (0,
|
|
392
|
+
? (0, common_1.parseFilter)(str)
|
|
396
393
|
: str;
|
|
397
|
-
if (!ast || !(ast instanceof
|
|
394
|
+
if (!ast || !(ast instanceof common_1.Expression))
|
|
398
395
|
return ast;
|
|
399
|
-
if (ast instanceof
|
|
396
|
+
if (ast instanceof common_1.ComparisonExpression) {
|
|
400
397
|
const left = this._convertFilter(ast.left);
|
|
401
398
|
const right = this._convertFilter(ast.right);
|
|
402
399
|
switch (ast.op) {
|
|
@@ -424,21 +421,21 @@ class JsonCollectionService {
|
|
|
424
421
|
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
425
422
|
}
|
|
426
423
|
}
|
|
427
|
-
if (ast instanceof
|
|
424
|
+
if (ast instanceof common_1.QualifiedIdentifier) {
|
|
428
425
|
return ast.value;
|
|
429
426
|
}
|
|
430
|
-
if (ast instanceof
|
|
431
|
-
ast instanceof
|
|
432
|
-
ast instanceof
|
|
433
|
-
ast instanceof
|
|
434
|
-
ast instanceof
|
|
435
|
-
ast instanceof
|
|
427
|
+
if (ast instanceof common_1.NumberLiteral ||
|
|
428
|
+
ast instanceof common_1.StringLiteral ||
|
|
429
|
+
ast instanceof common_1.BooleanLiteral ||
|
|
430
|
+
ast instanceof common_1.NullLiteral ||
|
|
431
|
+
ast instanceof common_1.DateLiteral ||
|
|
432
|
+
ast instanceof common_1.TimeLiteral) {
|
|
436
433
|
return ast.value;
|
|
437
434
|
}
|
|
438
|
-
if (ast instanceof
|
|
435
|
+
if (ast instanceof common_1.ArrayExpression) {
|
|
439
436
|
return ast.items.map(item => this._convertFilter(item));
|
|
440
437
|
}
|
|
441
|
-
if (ast instanceof
|
|
438
|
+
if (ast instanceof common_1.LogicalExpression) {
|
|
442
439
|
return ast.items.map(item => this._convertFilter(item))
|
|
443
440
|
.reduce((a, v) => {
|
|
444
441
|
if (a.length)
|
|
@@ -447,10 +444,10 @@ class JsonCollectionService {
|
|
|
447
444
|
return a;
|
|
448
445
|
}, []);
|
|
449
446
|
}
|
|
450
|
-
if (ast instanceof
|
|
447
|
+
if (ast instanceof common_1.ArrayExpression) {
|
|
451
448
|
return ast.items.map(item => this._convertFilter(item));
|
|
452
449
|
}
|
|
453
|
-
if (ast instanceof
|
|
450
|
+
if (ast instanceof common_1.ParenthesesExpression) {
|
|
454
451
|
return this._convertFilter(ast.expression);
|
|
455
452
|
}
|
|
456
453
|
throw new Error(`${ast.kind} is not implemented yet`);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.JsonSingletonService = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const schema_1 = require("@opra/schema");
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
const common_1 = require("@opra/common");
|
|
7
6
|
class JsonSingletonService {
|
|
8
7
|
dataType;
|
|
9
8
|
_data;
|
|
@@ -24,18 +23,18 @@ class JsonSingletonService {
|
|
|
24
23
|
return this._data;
|
|
25
24
|
}
|
|
26
25
|
_prepare(query) {
|
|
27
|
-
if (query.resource instanceof
|
|
26
|
+
if (query.resource instanceof common_1.SingletonResourceInfo) {
|
|
28
27
|
if (query.dataType !== this.dataType)
|
|
29
28
|
throw new TypeError(`Query data type (${query.dataType.name}) ` +
|
|
30
29
|
`differs from JsonCollectionService data type (${this.dataType.name})`);
|
|
31
30
|
}
|
|
32
31
|
switch (query.method) {
|
|
33
32
|
case 'create': {
|
|
34
|
-
const options = lodash_1.
|
|
33
|
+
const options = (0, lodash_1.omitBy)({
|
|
35
34
|
pick: query.pick,
|
|
36
35
|
omit: query.omit,
|
|
37
36
|
include: query.include
|
|
38
|
-
}, lodash_1.
|
|
37
|
+
}, lodash_1.isNil);
|
|
39
38
|
const { data } = query;
|
|
40
39
|
return {
|
|
41
40
|
method: query.method,
|
|
@@ -46,11 +45,11 @@ class JsonSingletonService {
|
|
|
46
45
|
}
|
|
47
46
|
case 'get': {
|
|
48
47
|
if (query.kind === 'CollectionGetQuery') {
|
|
49
|
-
const options = lodash_1.
|
|
48
|
+
const options = (0, lodash_1.omitBy)({
|
|
50
49
|
pick: query.pick,
|
|
51
50
|
omit: query.omit,
|
|
52
51
|
include: query.include
|
|
53
|
-
}, lodash_1.
|
|
52
|
+
}, lodash_1.isNil);
|
|
54
53
|
const keyValue = query.keyValue;
|
|
55
54
|
return {
|
|
56
55
|
method: query.method,
|
|
@@ -65,11 +64,11 @@ class JsonSingletonService {
|
|
|
65
64
|
break;
|
|
66
65
|
}
|
|
67
66
|
case 'update': {
|
|
68
|
-
const options = lodash_1.
|
|
67
|
+
const options = (0, lodash_1.omitBy)({
|
|
69
68
|
pick: query.pick,
|
|
70
69
|
omit: query.omit,
|
|
71
70
|
include: query.include
|
|
72
|
-
}, lodash_1.
|
|
71
|
+
}, lodash_1.isNil);
|
|
73
72
|
const { data } = query;
|
|
74
73
|
const keyValue = query.keyValue;
|
|
75
74
|
return {
|
package/cjs/utils/create-i18n.js
CHANGED
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createI18n = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
6
|
-
const
|
|
6
|
+
const common_1 = require("@opra/common");
|
|
7
7
|
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
11
|
};
|
|
12
12
|
delete opts.resourceDirs;
|
|
13
|
-
const instance =
|
|
13
|
+
const instance = common_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'));
|
|
16
16
|
if (options?.resourceDirs)
|
package/esm/adapter/adapter.d.ts
CHANGED
|
@@ -1,62 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { OpraException } from '@opra/
|
|
3
|
-
import { FallbackLng, I18n, LanguageResource } from '@opra/i18n';
|
|
4
|
-
import { CollectionGetQuery, CollectionResourceInfo, ComplexType, DataType, FieldGetQuery, OpraDocument, ResourceInfo, SingletonGetQuery, SingletonResourceInfo } from '@opra/schema';
|
|
1
|
+
import { Task } from 'power-tasks';
|
|
2
|
+
import { CollectionGetQuery, CollectionResourceInfo, ComplexType, DataType, FieldGetQuery, I18n, OpraDocument, OpraException, ResourceInfo, ResponsiveMap, SingletonGetQuery, SingletonResourceInfo } from '@opra/common';
|
|
5
3
|
import { IExecutionContext } from '../interfaces/execution-context.interface.js';
|
|
6
|
-
import {
|
|
4
|
+
import { I18nOptions } from '../interfaces/i18n-options.interface.js';
|
|
5
|
+
import { RequestContext } from './request-contexts/request-context.js';
|
|
6
|
+
import { SingleRequestContext } from './request-contexts/single-request-context.js';
|
|
7
7
|
export declare namespace OpraAdapter {
|
|
8
|
-
type UserContextResolver = (
|
|
9
|
-
executionContext: IExecutionContext;
|
|
10
|
-
isBatch: boolean;
|
|
11
|
-
}) => object | Promise<object>;
|
|
8
|
+
type UserContextResolver = (executionContext: IExecutionContext) => object | Promise<object>;
|
|
12
9
|
interface Options {
|
|
13
10
|
i18n?: I18n | I18nOptions | (() => Promise<I18n>);
|
|
14
11
|
userContext?: UserContextResolver;
|
|
15
12
|
}
|
|
16
|
-
interface I18nOptions {
|
|
17
|
-
/**
|
|
18
|
-
* Language to use
|
|
19
|
-
* @default undefined
|
|
20
|
-
*/
|
|
21
|
-
lng?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Language to use if translations in user language are not available.
|
|
24
|
-
* @default 'dev'
|
|
25
|
-
*/
|
|
26
|
-
fallbackLng?: false | FallbackLng;
|
|
27
|
-
/**
|
|
28
|
-
* Default namespace used if not passed to translation function
|
|
29
|
-
* @default 'translation'
|
|
30
|
-
*/
|
|
31
|
-
defaultNS?: string;
|
|
32
|
-
/**
|
|
33
|
-
* Resources to initialize with
|
|
34
|
-
* @default undefined
|
|
35
|
-
*/
|
|
36
|
-
resources?: LanguageResource;
|
|
37
|
-
/**
|
|
38
|
-
* Resource directories to initialize with (if not using loading or not appending using addResourceBundle)
|
|
39
|
-
* @default undefined
|
|
40
|
-
*/
|
|
41
|
-
resourceDirs?: string[];
|
|
42
|
-
}
|
|
43
13
|
}
|
|
44
14
|
export declare abstract class OpraAdapter<TExecutionContext extends IExecutionContext> {
|
|
45
15
|
readonly document: OpraDocument;
|
|
46
|
-
protected i18n: I18n;
|
|
47
16
|
protected userContextResolver?: OpraAdapter.UserContextResolver;
|
|
48
17
|
protected _internalResources: ResponsiveMap<string, ResourceInfo>;
|
|
18
|
+
i18n: I18n;
|
|
49
19
|
constructor(document: OpraDocument);
|
|
50
|
-
protected abstract
|
|
51
|
-
protected abstract sendResponse(executionContext: TExecutionContext,
|
|
20
|
+
protected abstract parse(executionContext: TExecutionContext): Promise<RequestContext>;
|
|
21
|
+
protected abstract sendResponse(executionContext: TExecutionContext, requestContext: RequestContext): Promise<void>;
|
|
52
22
|
protected abstract sendError(executionContext: TExecutionContext, error: OpraException): Promise<void>;
|
|
53
|
-
protected abstract isBatch(executionContext: TExecutionContext): boolean;
|
|
54
23
|
protected handler(executionContext: TExecutionContext): Promise<void>;
|
|
55
|
-
protected
|
|
56
|
-
protected _resourceExecute(document: OpraDocument, resource: ResourceInfo, context: QueryContext): Promise<void>;
|
|
24
|
+
protected _requestContextToTask(executionContext: TExecutionContext, requestContext: RequestContext): Task;
|
|
57
25
|
protected _init(options?: OpraAdapter.Options): Promise<void>;
|
|
58
|
-
protected
|
|
59
|
-
protected
|
|
26
|
+
protected _executeResourceQuery(document: OpraDocument, resource: ResourceInfo, context: SingleRequestContext): Promise<void>;
|
|
27
|
+
protected _executeCollectionResource(document: OpraDocument, resource: CollectionResourceInfo, context: SingleRequestContext): Promise<any>;
|
|
28
|
+
protected _executeSingletonResource(document: OpraDocument, resource: SingletonResourceInfo, context: SingleRequestContext): Promise<any>;
|
|
60
29
|
protected _pathWalkThrough(query: CollectionGetQuery | SingletonGetQuery | FieldGetQuery, dataType: ComplexType, value: any, parentPath: string): Promise<{
|
|
61
30
|
value?: any;
|
|
62
31
|
dataType?: DataType;
|
package/esm/adapter/adapter.js
CHANGED
|
@@ -1,81 +1,29 @@
|
|
|
1
|
+
import { Task } from 'power-tasks';
|
|
1
2
|
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
|
-
import { HttpHeaders, ResponsiveMap } from '@opra/common';
|
|
3
|
-
import { FailedDependencyError, ForbiddenError, ResourceNotFoundError, wrapException } from '@opra/exception';
|
|
4
|
-
import { I18n, translate } from '@opra/i18n';
|
|
5
|
-
import { CollectionCountQuery, CollectionResourceInfo, ComplexType, SingletonResourceInfo } from '@opra/schema';
|
|
3
|
+
import { CollectionCountQuery, CollectionResourceInfo, CollectionSearchQuery, ComplexType, FailedDependencyError, ForbiddenError, HttpHeaders, I18n, InternalServerError, ResourceNotFoundError, ResponsiveMap, SingletonResourceInfo, translate, wrapException } from '@opra/common';
|
|
6
4
|
import { createI18n } from '../utils/create-i18n.js';
|
|
7
|
-
import { MetadataResource } from './metadata
|
|
5
|
+
import { MetadataResource } from './classes/metadata.resource.js';
|
|
6
|
+
import { BatchRequestContext } from './request-contexts/batch-request-context.js';
|
|
7
|
+
import { SingleRequestContext } from './request-contexts/single-request-context.js';
|
|
8
|
+
const noOp = () => void 0;
|
|
8
9
|
export class OpraAdapter {
|
|
9
10
|
document;
|
|
10
|
-
i18n;
|
|
11
11
|
userContextResolver;
|
|
12
|
-
// protected _metadataResource: SingletonResourceInfo;
|
|
13
12
|
_internalResources = new ResponsiveMap();
|
|
13
|
+
i18n;
|
|
14
14
|
constructor(document) {
|
|
15
15
|
this.document = document;
|
|
16
16
|
}
|
|
17
17
|
async handler(executionContext) {
|
|
18
|
-
let
|
|
19
|
-
let userContext;
|
|
18
|
+
let requestContext;
|
|
20
19
|
let failed = false;
|
|
21
20
|
try {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
exclusive = exclusive || context.query.operation !== 'read';
|
|
29
|
-
// Wait previous read requests before executing update request
|
|
30
|
-
if (exclusive && promises) {
|
|
31
|
-
await Promise.allSettled(promises);
|
|
32
|
-
promises = undefined;
|
|
33
|
-
}
|
|
34
|
-
// If previous request in bucket had an error and executed an update
|
|
35
|
-
// we do not execute next requests
|
|
36
|
-
if (stop) {
|
|
37
|
-
context.errors.push(new FailedDependencyError());
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
const promise = (async () => {
|
|
42
|
-
// if (context.query.method === 'metadata') {
|
|
43
|
-
// await this._getSchemaExecute(context); //todo
|
|
44
|
-
// return;
|
|
45
|
-
// }
|
|
46
|
-
const resource = context.query.resource;
|
|
47
|
-
await this._resourcePrepare(resource, context);
|
|
48
|
-
if (this.userContextResolver && !userContext)
|
|
49
|
-
userContext = this.userContextResolver({
|
|
50
|
-
executionContext,
|
|
51
|
-
isBatch: this.isBatch(executionContext)
|
|
52
|
-
});
|
|
53
|
-
context.userContext = userContext;
|
|
54
|
-
await this._resourceExecute(this.document, resource, context);
|
|
55
|
-
})().catch(e => {
|
|
56
|
-
context.errors.push(e);
|
|
57
|
-
});
|
|
58
|
-
if (exclusive)
|
|
59
|
-
await promise;
|
|
60
|
-
else {
|
|
61
|
-
promises = promises || [];
|
|
62
|
-
promises.push(promise);
|
|
63
|
-
}
|
|
64
|
-
// todo execute sub property queries
|
|
65
|
-
}
|
|
66
|
-
catch (e) {
|
|
67
|
-
context.errors.unshift(e);
|
|
68
|
-
}
|
|
69
|
-
if (context.errors.length) {
|
|
70
|
-
// noinspection SuspiciousTypeOfGuard
|
|
71
|
-
context.errors = context.errors.map(e => wrapException(e));
|
|
72
|
-
if (exclusive)
|
|
73
|
-
stop = stop || !!context.errors.find(e => !(e.issue.severity === 'warning' || e.issue.severity === 'info'));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (promises)
|
|
77
|
-
await Promise.allSettled(promises);
|
|
78
|
-
await this.sendResponse(executionContext, queryContexts);
|
|
21
|
+
if (this.userContextResolver)
|
|
22
|
+
executionContext.userContext = this.userContextResolver(executionContext);
|
|
23
|
+
requestContext = await this.parse(executionContext);
|
|
24
|
+
const task = this._requestContextToTask(executionContext, requestContext);
|
|
25
|
+
await task.toPromise().catch(noOp);
|
|
26
|
+
await this.sendResponse(executionContext, requestContext);
|
|
79
27
|
}
|
|
80
28
|
catch (e) {
|
|
81
29
|
failed = true;
|
|
@@ -86,47 +34,49 @@ export class OpraAdapter {
|
|
|
86
34
|
if (executionContext instanceof AsyncEventEmitter) {
|
|
87
35
|
await executionContext
|
|
88
36
|
.emitAsyncSerial('finish', {
|
|
89
|
-
|
|
37
|
+
context: executionContext,
|
|
90
38
|
failed
|
|
91
39
|
}).catch();
|
|
92
40
|
}
|
|
93
41
|
}
|
|
94
42
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
await fn(context);
|
|
43
|
+
_requestContextToTask(executionContext, requestContext) {
|
|
44
|
+
if (requestContext instanceof BatchRequestContext) {
|
|
45
|
+
const children = requestContext.queries.map(q => this._requestContextToTask(executionContext, q));
|
|
46
|
+
return new Task(children, { bail: true });
|
|
100
47
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
};
|
|
115
|
-
Object.setPrototypeOf(ctx, context);
|
|
116
|
-
promises.push(this._collectionResourceExecute(document, resource, ctx));
|
|
48
|
+
else if (requestContext instanceof SingleRequestContext) {
|
|
49
|
+
const { query } = requestContext;
|
|
50
|
+
const task = new Task(async () => {
|
|
51
|
+
if (query.resource) {
|
|
52
|
+
const { resource } = query;
|
|
53
|
+
// call pre_xxx method
|
|
54
|
+
const fn = resource.metadata['pre_' + query.method];
|
|
55
|
+
if (fn && typeof fn === 'function') {
|
|
56
|
+
await fn(requestContext);
|
|
57
|
+
}
|
|
58
|
+
await this._executeResourceQuery(this.document, resource, requestContext);
|
|
59
|
+
// todo execute sub property queries
|
|
60
|
+
return;
|
|
117
61
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
62
|
+
throw new InternalServerError('Not implemented yet');
|
|
63
|
+
}, {
|
|
64
|
+
id: requestContext.contentId,
|
|
65
|
+
exclusive: query.operation !== 'read'
|
|
66
|
+
});
|
|
67
|
+
task.on('finish', () => {
|
|
68
|
+
if (task.error) {
|
|
69
|
+
if (task.failedDependencies)
|
|
70
|
+
requestContext.errors.push(new FailedDependencyError());
|
|
71
|
+
else
|
|
72
|
+
requestContext.errors.push(wrapException(task.error));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return task;
|
|
128
77
|
}
|
|
129
|
-
|
|
78
|
+
/* istanbul ignore next */
|
|
79
|
+
throw new TypeError('Invalid request context instance');
|
|
130
80
|
}
|
|
131
81
|
async _init(options) {
|
|
132
82
|
if (options?.i18n instanceof I18n)
|
|
@@ -158,7 +108,39 @@ export class OpraAdapter {
|
|
|
158
108
|
}
|
|
159
109
|
}
|
|
160
110
|
}
|
|
161
|
-
async
|
|
111
|
+
async _executeResourceQuery(document, resource, context) {
|
|
112
|
+
if (resource instanceof CollectionResourceInfo) {
|
|
113
|
+
const { query } = context;
|
|
114
|
+
if (query instanceof CollectionSearchQuery) {
|
|
115
|
+
const promises = [];
|
|
116
|
+
let search;
|
|
117
|
+
promises.push(this._executeCollectionResource(document, resource, context)
|
|
118
|
+
.then(v => search = v));
|
|
119
|
+
if (query.count && resource.metadata.count) {
|
|
120
|
+
const ctx = {
|
|
121
|
+
query: new CollectionCountQuery(query.resource, { filter: query.filter }),
|
|
122
|
+
resultPath: ''
|
|
123
|
+
};
|
|
124
|
+
Object.setPrototypeOf(ctx, context);
|
|
125
|
+
promises.push(this._executeCollectionResource(document, resource, ctx)
|
|
126
|
+
.then(r => {
|
|
127
|
+
context.responseHeaders[HttpHeaders.X_Opra_Count] = r;
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
await Promise.all(promises);
|
|
131
|
+
context.response = search;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
context.response = await this._executeCollectionResource(document, resource, context);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
else if (resource instanceof SingletonResourceInfo) {
|
|
138
|
+
context.response = await this._executeSingletonResource(document, resource, context);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
throw new Error(`Executing "${resource.kind}" has not been implemented yet`);
|
|
142
|
+
}
|
|
143
|
+
async _executeCollectionResource(document, resource, context) {
|
|
162
144
|
const method = context.query.method;
|
|
163
145
|
const resolverInfo = resource.metadata[method];
|
|
164
146
|
if (!(resolverInfo && resolverInfo.handler))
|
|
@@ -175,13 +157,12 @@ export class OpraAdapter {
|
|
|
175
157
|
result = Array.isArray(result) ? result[0] : result;
|
|
176
158
|
if (result)
|
|
177
159
|
context.status = 201;
|
|
178
|
-
context.responseHeaders
|
|
160
|
+
context.responseHeaders[HttpHeaders.X_Opra_DataType] = resource.dataType.name;
|
|
179
161
|
return result;
|
|
180
162
|
}
|
|
181
163
|
case 'count': {
|
|
182
164
|
const query = context.query;
|
|
183
165
|
result = await resolverInfo.handler(context, query);
|
|
184
|
-
context.responseHeaders.set(HttpHeaders.X_Opra_Count, result);
|
|
185
166
|
return result;
|
|
186
167
|
}
|
|
187
168
|
case 'get': {
|
|
@@ -194,14 +175,14 @@ export class OpraAdapter {
|
|
|
194
175
|
if (v.value === undefined)
|
|
195
176
|
throw new ResourceNotFoundError(v.path);
|
|
196
177
|
if (v.dataType)
|
|
197
|
-
context.responseHeaders
|
|
178
|
+
context.responseHeaders[HttpHeaders.X_Opra_DataType] = v.dataType.name;
|
|
198
179
|
return v.value;
|
|
199
180
|
}
|
|
200
181
|
case 'search': {
|
|
201
182
|
const query = context.query;
|
|
202
183
|
result = await resolverInfo.handler(context, query);
|
|
203
184
|
const items = Array.isArray(result) ? result : (context.response ? [result] : []);
|
|
204
|
-
context.responseHeaders
|
|
185
|
+
context.responseHeaders[HttpHeaders.X_Opra_DataType] = resource.dataType.name;
|
|
205
186
|
return items;
|
|
206
187
|
}
|
|
207
188
|
case 'update': {
|
|
@@ -210,7 +191,7 @@ export class OpraAdapter {
|
|
|
210
191
|
result = Array.isArray(result) ? result[0] : result;
|
|
211
192
|
if (!result)
|
|
212
193
|
throw new ResourceNotFoundError(resource.name, query.keyValue);
|
|
213
|
-
context.responseHeaders
|
|
194
|
+
context.responseHeaders[HttpHeaders.X_Opra_DataType] = resource.dataType.name;
|
|
214
195
|
return result;
|
|
215
196
|
}
|
|
216
197
|
case 'delete':
|
|
@@ -247,7 +228,7 @@ export class OpraAdapter {
|
|
|
247
228
|
}
|
|
248
229
|
}
|
|
249
230
|
}
|
|
250
|
-
async
|
|
231
|
+
async _executeSingletonResource(document, resource, context) {
|
|
251
232
|
const method = context.query.method;
|
|
252
233
|
const resolverInfo = resource.metadata[method];
|
|
253
234
|
if (!(resolverInfo && resolverInfo.handler))
|
|
@@ -268,7 +249,7 @@ export class OpraAdapter {
|
|
|
268
249
|
if (v.value === undefined)
|
|
269
250
|
throw new ResourceNotFoundError(v.path);
|
|
270
251
|
if (v.dataType)
|
|
271
|
-
context.responseHeaders
|
|
252
|
+
context.responseHeaders[HttpHeaders.X_Opra_DataType] = v.dataType.name;
|
|
272
253
|
return v.value;
|
|
273
254
|
}
|
|
274
255
|
}
|
|
@@ -286,7 +267,7 @@ export class OpraAdapter {
|
|
|
286
267
|
}
|
|
287
268
|
if (method === 'create')
|
|
288
269
|
context.status = 201;
|
|
289
|
-
context.responseHeaders
|
|
270
|
+
context.responseHeaders[HttpHeaders.X_Opra_DataType] = resource.dataType.name;
|
|
290
271
|
return result;
|
|
291
272
|
}
|
|
292
273
|
async _pathWalkThrough(query, dataType, value, parentPath) {
|