@opra/core 0.1.0 → 0.2.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.
Files changed (81) hide show
  1. package/cjs/enums/http-headers.enum.js +3 -2
  2. package/cjs/implementation/adapter-utils/entity-resource-execute.util.js +36 -34
  3. package/cjs/implementation/adapter-utils/resource-prepare.util.js +1 -1
  4. package/cjs/implementation/adapter.js +14 -19
  5. package/cjs/implementation/express-adapter.js +3 -0
  6. package/cjs/implementation/headers-map.js +18 -0
  7. package/cjs/implementation/http-adapter.js +65 -79
  8. package/cjs/implementation/query-context.js +12 -19
  9. package/cjs/index.js +0 -2
  10. package/cjs/services/json-data-service.js +367 -131
  11. package/cjs/utils/path-to-tree.js +7 -5
  12. package/esm/enums/http-headers.enum.d.ts +3 -2
  13. package/esm/enums/http-headers.enum.js +3 -2
  14. package/esm/implementation/adapter-utils/entity-resource-execute.util.js +35 -33
  15. package/esm/implementation/adapter-utils/resource-execute.util.d.ts +2 -2
  16. package/esm/implementation/adapter-utils/resource-prepare.util.d.ts +2 -2
  17. package/esm/implementation/adapter-utils/resource-prepare.util.js +1 -1
  18. package/esm/implementation/adapter.d.ts +2 -2
  19. package/esm/implementation/adapter.js +12 -17
  20. package/esm/implementation/express-adapter.js +2 -0
  21. package/esm/implementation/headers-map.d.ts +5 -0
  22. package/esm/implementation/headers-map.js +14 -0
  23. package/esm/implementation/http-adapter.d.ts +6 -6
  24. package/esm/implementation/http-adapter.js +61 -75
  25. package/esm/implementation/query-context.d.ts +9 -15
  26. package/esm/implementation/query-context.js +11 -17
  27. package/esm/index.d.ts +0 -2
  28. package/esm/index.js +0 -2
  29. package/esm/interfaces/entity-service.interface.d.ts +8 -6
  30. package/esm/services/json-data-service.d.ts +56 -39
  31. package/esm/services/json-data-service.js +365 -129
  32. package/esm/types.d.ts +0 -3
  33. package/esm/utils/path-to-tree.d.ts +1 -1
  34. package/esm/utils/path-to-tree.js +7 -5
  35. package/i18n/en/error.json +5 -5
  36. package/package.json +11 -8
  37. package/cjs/exception/api-exception.js +0 -68
  38. package/cjs/exception/http-errors/bad-request.error.js +0 -26
  39. package/cjs/exception/http-errors/failed-dependency.error.js +0 -25
  40. package/cjs/exception/http-errors/forbidden.error.js +0 -27
  41. package/cjs/exception/http-errors/internal-server.error.js +0 -27
  42. package/cjs/exception/http-errors/method-not-allowed.error.js +0 -26
  43. package/cjs/exception/http-errors/not-acceptable.error.js +0 -26
  44. package/cjs/exception/http-errors/not-found.error.js +0 -29
  45. package/cjs/exception/http-errors/unauthorized.error.js +0 -26
  46. package/cjs/exception/http-errors/unprocessable-entity.error.js +0 -25
  47. package/cjs/exception/index.js +0 -15
  48. package/cjs/exception/resource-errors/resource-conflict.error.js +0 -19
  49. package/cjs/exception/resource-errors/resource-not-found.error.js +0 -19
  50. package/cjs/exception/wrap-error.js +0 -17
  51. package/cjs/interfaces/query.interface.js +0 -207
  52. package/esm/exception/api-exception.d.ts +0 -40
  53. package/esm/exception/api-exception.js +0 -64
  54. package/esm/exception/http-errors/bad-request.error.d.ts +0 -10
  55. package/esm/exception/http-errors/bad-request.error.js +0 -22
  56. package/esm/exception/http-errors/failed-dependency.error.d.ts +0 -9
  57. package/esm/exception/http-errors/failed-dependency.error.js +0 -21
  58. package/esm/exception/http-errors/forbidden.error.d.ts +0 -11
  59. package/esm/exception/http-errors/forbidden.error.js +0 -23
  60. package/esm/exception/http-errors/internal-server.error.d.ts +0 -9
  61. package/esm/exception/http-errors/internal-server.error.js +0 -22
  62. package/esm/exception/http-errors/method-not-allowed.error.d.ts +0 -10
  63. package/esm/exception/http-errors/method-not-allowed.error.js +0 -22
  64. package/esm/exception/http-errors/not-acceptable.error.d.ts +0 -10
  65. package/esm/exception/http-errors/not-acceptable.error.js +0 -22
  66. package/esm/exception/http-errors/not-found.error.d.ts +0 -13
  67. package/esm/exception/http-errors/not-found.error.js +0 -25
  68. package/esm/exception/http-errors/unauthorized.error.d.ts +0 -10
  69. package/esm/exception/http-errors/unauthorized.error.js +0 -22
  70. package/esm/exception/http-errors/unprocessable-entity.error.d.ts +0 -9
  71. package/esm/exception/http-errors/unprocessable-entity.error.js +0 -21
  72. package/esm/exception/index.d.ts +0 -12
  73. package/esm/exception/index.js +0 -12
  74. package/esm/exception/resource-errors/resource-conflict.error.d.ts +0 -4
  75. package/esm/exception/resource-errors/resource-conflict.error.js +0 -15
  76. package/esm/exception/resource-errors/resource-not-found.error.d.ts +0 -4
  77. package/esm/exception/resource-errors/resource-not-found.error.js +0 -15
  78. package/esm/exception/wrap-error.d.ts +0 -2
  79. package/esm/exception/wrap-error.js +0 -13
  80. package/esm/interfaces/query.interface.d.ts +0 -115
  81. package/esm/interfaces/query.interface.js +0 -203
@@ -8,8 +8,9 @@ exports.HttpHeaders = void 0;
8
8
  var HttpHeaders;
9
9
  (function (HttpHeaders) {
10
10
  /* *** Custom Headers *** */
11
- HttpHeaders["X_Opra_Version"] = "X-OPRA-Version";
12
- HttpHeaders["X_Opra_Schema"] = "X-OPRA-Schema";
11
+ HttpHeaders["X_Opra_Version"] = "X-Opra-Version";
12
+ HttpHeaders["X_Opra_Schema"] = "X-Opra-Schema";
13
+ HttpHeaders["X_Opra_Count"] = "X-Opra-Count";
13
14
  /* *** Authentication *** */
14
15
  /**
15
16
  * Defines the authentication method that should be used to access a resource.
@@ -1,68 +1,71 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.entityResourceExecute = void 0;
4
+ const exception_1 = require("@opra/exception");
4
5
  const i18n_1 = require("@opra/i18n");
5
6
  const schema_1 = require("@opra/schema");
6
7
  const index_js_1 = require("../../enums/index.js");
7
- const index_js_2 = require("../../exception/index.js");
8
- const query_interface_js_1 = require("../../interfaces/query.interface.js");
9
8
  async function entityResourceExecute(service, resource, context) {
10
9
  const { query } = context;
11
- if (query_interface_js_1.OpraQuery.isSearchQuery(query)) {
10
+ if (query.kind === 'SearchCollectionQuery') {
12
11
  const promises = [];
13
12
  let search;
14
- let count;
15
- promises.push(executeFn(service, resource, context, query.queryType)
13
+ promises.push(executeFn(service, resource, context)
16
14
  .then(v => search = v));
17
- if (query.count) {
18
- promises.push(executeFn(service, resource, context, 'count')
19
- .then(v => count = v));
15
+ if (query.count && resource.metadata.methods.count) {
16
+ const ctx = {
17
+ query: new schema_1.OpraCountCollectionQuery(query.resource, { filter: query.filter }),
18
+ resultPath: ''
19
+ };
20
+ Object.setPrototypeOf(ctx, context);
21
+ promises.push(executeFn(service, resource, ctx));
20
22
  }
21
23
  await Promise.all(promises);
22
- context.response.value = {
23
- ...search,
24
- ...count
25
- };
24
+ context.response = search;
26
25
  return;
27
26
  }
28
- context.response.value = await executeFn(service, resource, context, query.queryType);
27
+ context.response = await executeFn(service, resource, context);
29
28
  }
30
29
  exports.entityResourceExecute = entityResourceExecute;
31
- async function executeFn(service, resource, context, queryType) {
32
- const resolverInfo = resource.metadata.methods?.[queryType];
33
- if (!resolverInfo.handler)
34
- throw new index_js_2.ForbiddenError({
35
- message: (0, i18n_1.translate)('RESOLVER_FORBIDDEN', { queryType }),
30
+ async function executeFn(service, resource, context) {
31
+ const method = context.query.method;
32
+ const resolverInfo = resource.metadata.methods?.[method];
33
+ if (!(resolverInfo && resolverInfo.handler))
34
+ throw new exception_1.ForbiddenError({
35
+ message: (0, i18n_1.translate)('RESOLVER_FORBIDDEN', { method }, `The resource endpoint does not accept '{{method}}' operations`),
36
36
  severity: 'error',
37
37
  code: 'RESOLVER_FORBIDDEN'
38
38
  });
39
39
  let result = await resolverInfo.handler(context);
40
- switch (queryType) {
40
+ switch (method) {
41
41
  case 'search':
42
- context.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, '/$schema/types/' + resource.dataType.name);
43
- return {
44
- items: Array.isArray(result) ? result : (context.response.value ? [result] : [])
45
- };
42
+ const items = Array.isArray(result) ? result : (context.response ? [result] : []);
43
+ context.responseHeaders.set(index_js_1.HttpHeaders.X_Opra_Schema, resource.dataType.name);
44
+ return items;
46
45
  case 'get':
47
46
  case 'update':
48
47
  if (!result) {
49
48
  const query = context.query;
50
- throw new index_js_2.ResourceNotFoundError(resource.name, query.keyValue);
49
+ throw new exception_1.ResourceNotFoundError(resource.name, query.keyValue);
51
50
  }
52
51
  break;
53
52
  case 'count':
54
- return { count: result || 0 };
53
+ context.responseHeaders.set(index_js_1.HttpHeaders.X_Opra_Count, result);
54
+ return;
55
55
  case 'delete':
56
56
  case 'deleteMany':
57
57
  case 'updateMany':
58
- let affectedRecords;
58
+ let affected;
59
59
  if (typeof result === 'number')
60
- affectedRecords = result;
60
+ affected = result;
61
61
  if (typeof result === 'boolean')
62
- affectedRecords = result ? 1 : 0;
62
+ affected = result ? 1 : 0;
63
63
  if (typeof result === 'object')
64
- affectedRecords = result.affectedRows || result.affectedRecords;
65
- return { affectedRecords };
64
+ affected = result.affectedRows || result.affected;
65
+ return {
66
+ operation: context.query.method,
67
+ affected
68
+ };
66
69
  }
67
70
  if (!result)
68
71
  return;
@@ -76,9 +79,8 @@ async function executeFn(service, resource, context, queryType) {
76
79
  result = result && typeof result === 'object' && result[field];
77
80
  }
78
81
  }
79
- if (queryType === 'create')
80
- context.response.status = 201;
81
- if (dataType)
82
- context.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, '/$schema/types/' + dataType.name);
82
+ if (method === 'create')
83
+ context.status = 201;
84
+ context.responseHeaders.set(index_js_1.HttpHeaders.X_Opra_Schema, resource.dataType.name);
83
85
  return result;
84
86
  }
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resourcePrepare = void 0;
4
4
  async function resourcePrepare(resource, context) {
5
5
  const { query } = context;
6
- const fn = resource.metadata['pre_' + query.queryType];
6
+ const fn = resource.metadata['pre_' + query.method];
7
7
  if (fn && typeof fn === 'function') {
8
8
  await fn(context);
9
9
  }
@@ -2,10 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpraAdapter = void 0;
4
4
  const strict_typed_events_1 = require("strict-typed-events");
5
+ const exception_1 = require("@opra/exception");
5
6
  const i18n_1 = require("@opra/i18n");
6
- const index_js_1 = require("../enums/index.js");
7
- const index_js_2 = require("../exception/index.js");
8
- const wrap_error_js_1 = require("../exception/wrap-error.js");
9
7
  const create_i18n_js_1 = require("../utils/create-i18n.js");
10
8
  const resource_execute_util_js_1 = require("./adapter-utils/resource-execute.util.js");
11
9
  const resource_prepare_util_js_1 = require("./adapter-utils/resource-prepare.util.js");
@@ -40,12 +38,12 @@ class OpraAdapter {
40
38
  // If previous request in bucket had an error and executed an update
41
39
  // we do not execute next requests
42
40
  if (stop) {
43
- context.response.errors.push(new index_js_2.FailedDependencyError());
41
+ context.errors.push(new exception_1.FailedDependencyError());
44
42
  continue;
45
43
  }
46
44
  try {
47
45
  const promise = (async () => {
48
- if (context.query.queryType === 'schema') {
46
+ if (context.query.method === 'metadata') {
49
47
  await this._getSchemaExecute(context);
50
48
  return;
51
49
  }
@@ -59,7 +57,7 @@ class OpraAdapter {
59
57
  context.userContext = userContext;
60
58
  await (0, resource_execute_util_js_1.resourceExecute)(this.service, resource, context);
61
59
  })().catch(e => {
62
- context.response.errors.push(e);
60
+ context.errors.push(e);
63
61
  });
64
62
  if (exclusive)
65
63
  await promise;
@@ -70,13 +68,13 @@ class OpraAdapter {
70
68
  // todo execute sub property queries
71
69
  }
72
70
  catch (e) {
73
- context.response.errors.unshift(e);
71
+ context.errors.unshift(e);
74
72
  }
75
- if (context.response.errors.length) {
73
+ if (context.errors.length) {
76
74
  // noinspection SuspiciousTypeOfGuard
77
- context.response.errors = context.response.errors.map(e => (0, wrap_error_js_1.wrapError)(e));
75
+ context.errors = context.errors.map(e => (0, exception_1.wrapException)(e));
78
76
  if (exclusive)
79
- stop = stop || !!context.response.errors.find(e => !(e.response.severity === 'warning' || e.response.severity === 'info'));
77
+ stop = stop || !!context.errors.find(e => !(e.issue.severity === 'warning' || e.issue.severity === 'info'));
80
78
  }
81
79
  }
82
80
  if (promises)
@@ -85,7 +83,7 @@ class OpraAdapter {
85
83
  }
86
84
  catch (e) {
87
85
  failed = true;
88
- const error = (0, wrap_error_js_1.wrapError)(e);
86
+ const error = (0, exception_1.wrapException)(e);
89
87
  await this.sendError(executionContext, error);
90
88
  }
91
89
  finally {
@@ -101,28 +99,25 @@ class OpraAdapter {
101
99
  async _getSchemaExecute(ctx) {
102
100
  const query = ctx.query;
103
101
  let out;
104
- if (query.resourcePath.length > 2)
105
- throw new index_js_2.BadRequestError();
102
+ if (query.resourcePath && query.resourcePath.length > 2)
103
+ throw new exception_1.BadRequestError();
106
104
  if (query.resourcePath?.length) {
107
105
  if (query.resourcePath[0] === 'resources') {
108
106
  const resource = this.service.getResource(query.resourcePath[1]);
109
107
  out = resource.getSchema(true);
110
108
  query.resourcePath[1] = resource.name;
111
- ctx.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + resource.kind);
112
109
  }
113
110
  else if (query.resourcePath[0] === 'types') {
114
111
  const dataType = this.service.getDataType(query.resourcePath[1]);
115
112
  out = dataType.getSchema(true);
116
113
  query.resourcePath[1] = dataType.name;
117
- ctx.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + dataType.kind);
118
114
  }
119
115
  else
120
- throw new index_js_2.BadRequestError();
121
- ctx.response.value = out;
116
+ throw new exception_1.BadRequestError();
117
+ ctx.response = out;
122
118
  return;
123
119
  }
124
- ctx.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema');
125
- ctx.response.value = this.service.getSchema(true);
120
+ ctx.response = this.service.getSchema(true);
126
121
  }
127
122
  static async initI18n(options) {
128
123
  if (options?.i18n instanceof i18n_1.I18n)
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpraExpressAdapter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const body_parser_1 = tslib_1.__importDefault(require("body-parser"));
4
6
  const strict_typed_events_1 = require("strict-typed-events");
5
7
  const url_1 = require("@opra/url");
6
8
  const http_adapter_js_1 = require("./http-adapter.js");
@@ -12,6 +14,7 @@ class OpraExpressAdapter extends http_adapter_js_1.OpraHttpAdapter {
12
14
  i18n
13
15
  });
14
16
  const prefix = '/' + (0, url_1.normalizePath)(options?.prefix, true);
17
+ app.use(prefix, body_parser_1.default.json());
15
18
  app.use(prefix, (request, response, next) => {
16
19
  (async () => {
17
20
  const executionContext = new ExpressExecutionContext(request, response);
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HeadersMap = void 0;
4
+ const schema_1 = require("@opra/schema");
5
+ const index_js_1 = require("../enums/index.js");
6
+ class HeadersMap extends schema_1.ResponsiveMap {
7
+ constructor(data) {
8
+ super(data, Array.from(Object.values(index_js_1.HttpHeaders)));
9
+ }
10
+ toObject() {
11
+ return Array.from(this.keys()).sort()
12
+ .reduce((a, k) => {
13
+ a[k] = this.get(k);
14
+ return a;
15
+ }, {});
16
+ }
17
+ }
18
+ exports.HeadersMap = HeadersMap;
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpraHttpAdapter = void 0;
4
+ const exception_1 = require("@opra/exception");
4
5
  const schema_1 = require("@opra/schema");
5
6
  const url_1 = require("@opra/url");
6
7
  const index_js_1 = require("../enums/index.js");
7
- const index_js_2 = require("../exception/index.js");
8
- const wrap_error_js_1 = require("../exception/wrap-error.js");
9
- const query_interface_js_1 = require("../interfaces/query.interface.js");
10
8
  const adapter_js_1 = require("./adapter.js");
9
+ const headers_map_js_1 = require("./headers-map.js");
11
10
  const query_context_js_1 = require("./query-context.js");
12
11
  class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
13
12
  prepareRequests(executionContext) {
@@ -18,37 +17,37 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
18
17
  }
19
18
  const url = new url_1.OpraURL(req.getUrl());
20
19
  return [
21
- this.prepareRequest(executionContext, url, req.getMethod(), new schema_1.ResponsiveMap(req.getHeaders()), req.getBody())
20
+ this.prepareRequest(executionContext, url, req.getMethod(), new headers_map_js_1.HeadersMap(req.getHeaders()), req.getBody())
22
21
  ];
23
22
  }
24
23
  prepareRequest(executionContext, url, method, headers, body) {
25
24
  if (!url.path.size)
26
- throw new index_js_2.BadRequestError();
25
+ throw new exception_1.BadRequestError();
27
26
  if (method !== 'GET' && url.path.size > 1)
28
- throw new index_js_2.BadRequestError();
27
+ throw new exception_1.BadRequestError();
29
28
  const query = this.buildQuery(url, method, body);
30
29
  if (!query)
31
- throw new index_js_2.MethodNotAllowedError({
30
+ throw new exception_1.MethodNotAllowedError({
32
31
  message: `Method "${method}" is not allowed by target endpoint`
33
32
  });
34
33
  return new query_context_js_1.QueryContext({
35
34
  service: this.service,
36
35
  executionContext,
37
36
  query,
38
- headers,
37
+ headers: new headers_map_js_1.HeadersMap(),
39
38
  params: url.searchParams,
40
39
  continueOnError: query.operation === 'read'
41
40
  });
42
41
  }
43
- buildGetSchemaQuery(url) {
42
+ buildGGetMetadataQuery(url) {
44
43
  const pathLen = url.path.size;
45
44
  const resourcePath = [];
46
45
  let pathIndex = 0;
47
46
  while (pathIndex < pathLen) {
48
47
  const p = url.path.get(pathIndex++);
49
48
  if (p.key)
50
- throw new index_js_2.BadRequestError();
51
- if (p.resource !== '$schema') {
49
+ throw new exception_1.BadRequestError();
50
+ if (p.resource !== '$metadata') {
52
51
  if (pathIndex === 1)
53
52
  resourcePath.push('resources');
54
53
  resourcePath.push(p.resource);
@@ -58,8 +57,9 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
58
57
  pick: url.searchParams.get('$pick'),
59
58
  omit: url.searchParams.get('$omit'),
60
59
  include: url.searchParams.get('$include'),
60
+ resourcePath
61
61
  };
62
- return query_interface_js_1.OpraQuery.forGetSchema(resourcePath, opts);
62
+ return new schema_1.OpraGetMetadataQuery(opts);
63
63
  }
64
64
  buildQuery(url, method, body) {
65
65
  let container = this.service;
@@ -68,10 +68,10 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
68
68
  // Check if requesting metadata
69
69
  for (let i = 0; i < pathLen; i++) {
70
70
  const p = url.path.get(i);
71
- if (p.resource === '$schema') {
71
+ if (p.resource === '$metadata') {
72
72
  if (method !== 'GET')
73
73
  return;
74
- return this.buildGetSchemaQuery(url);
74
+ return this.buildGGetMetadataQuery(url);
75
75
  }
76
76
  }
77
77
  let pathIndex = 0;
@@ -92,7 +92,7 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
92
92
  switch (method) {
93
93
  case 'GET': {
94
94
  if (scope === 'collection') {
95
- query = query_interface_js_1.OpraQuery.forSearch(resource, {
95
+ query = new schema_1.OpraSearchCollectionQuery(resource, {
96
96
  filter: url.searchParams.get('$filter'),
97
97
  limit: url.searchParams.get('$limit'),
98
98
  skip: url.searchParams.get('$skip'),
@@ -105,51 +105,39 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
105
105
  });
106
106
  }
107
107
  else {
108
- query = query_interface_js_1.OpraQuery.forGetEntity(resource, p.key, {
108
+ query = new schema_1.OpraGetInstanceQuery(resource, p.key, {
109
109
  pick: url.searchParams.get('$pick'),
110
110
  omit: url.searchParams.get('$omit'),
111
111
  include: url.searchParams.get('$include')
112
112
  });
113
113
  // Move through properties
114
- let nested;
115
- let path = resource.name;
114
+ let dataType = resource.dataType;
115
+ const curPath = [];
116
+ let parent = query;
116
117
  while (pathIndex < pathLen) {
117
- const dataType = nested
118
- ? this.service.getDataType(nested.property.type || 'string')
119
- : query.resource.dataType;
120
118
  if (!(dataType instanceof schema_1.ComplexType))
121
- throw new Error(`"${path}" is not a ComplexType and has no fields.`);
119
+ throw new TypeError(`"${resource.name}.${curPath.join()}" is not a ComplexType and has no fields.`);
122
120
  p = url.path.get(pathIndex++);
123
- path += '.' + p.resource;
124
- const prop = dataType.fields.get(p.resource);
125
- if (!prop)
126
- throw new index_js_2.NotFoundError({ message: `Invalid or unknown resource path (${path})` });
127
- const q = query_interface_js_1.OpraQuery.forGetProperty(prop);
128
- if (nested) {
129
- nested.nested = q;
130
- }
131
- else {
132
- query.nested = q;
133
- }
134
- nested = q;
121
+ curPath.push(p.resource);
122
+ const field = dataType.getField(p.resource);
123
+ parent.nested = new schema_1.OpraGetFieldQuery(parent, field.name);
124
+ parent = parent.nested;
125
+ dataType = parent.dataType;
135
126
  }
136
127
  }
137
128
  break;
138
129
  }
139
130
  case 'DELETE': {
140
- if (scope === 'collection') {
141
- query = query_interface_js_1.OpraQuery.forDeleteMany(resource, {
131
+ query = scope === 'collection'
132
+ ? new schema_1.OpraDeleteCollectionQuery(resource, {
142
133
  filter: url.searchParams.get('$filter'),
143
- });
144
- }
145
- else {
146
- query = query_interface_js_1.OpraQuery.forDelete(resource, p.key);
147
- }
134
+ })
135
+ : new schema_1.OpraDeleteInstanceQuery(resource, p.key);
148
136
  break;
149
137
  }
150
138
  case 'POST': {
151
139
  if (scope === 'collection') {
152
- query = query_interface_js_1.OpraQuery.forCreate(resource, body, {
140
+ query = new schema_1.OpraCreateInstanceQuery(resource, body, {
153
141
  pick: url.searchParams.get('$pick'),
154
142
  omit: url.searchParams.get('$omit'),
155
143
  include: url.searchParams.get('$include')
@@ -158,28 +146,27 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
158
146
  break;
159
147
  }
160
148
  case 'PATCH': {
161
- if (scope === 'collection') {
162
- query = query_interface_js_1.OpraQuery.forUpdateMany(resource, body, {
149
+ query = scope === 'collection'
150
+ ? new schema_1.OpraUpdateCollectionQuery(resource, body, {
163
151
  filter: url.searchParams.get('$filter')
164
- });
165
- }
166
- else {
167
- query = query_interface_js_1.OpraQuery.forUpdate(resource, p.key, body, {
152
+ })
153
+ : new schema_1.OpraUpdateInstanceQuery(resource, p.key, body, {
168
154
  pick: url.searchParams.get('$pick'),
169
155
  omit: url.searchParams.get('$omit'),
170
156
  include: url.searchParams.get('$include')
171
157
  });
172
- }
173
158
  break;
174
159
  }
175
160
  }
176
161
  return query;
177
162
  }
178
163
  }
179
- throw new index_js_2.InternalServerError();
164
+ throw new exception_1.InternalServerError();
180
165
  }
181
166
  catch (e) {
182
- throw index_js_2.BadRequestError.wrap(e);
167
+ if (e instanceof exception_1.OpraException)
168
+ throw e;
169
+ throw new exception_1.BadRequestError(e);
183
170
  }
184
171
  }
185
172
  async sendResponse(executionContext, queryContexts) {
@@ -192,19 +179,12 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
192
179
  // this.writeError([], new InternalServerError({message: 'Not implemented yet'}));
193
180
  return;
194
181
  }
195
- if (!outputPackets.length) {
196
- const err = new index_js_2.NotFoundError();
197
- outputPackets.push({
198
- status: err.status,
199
- body: {
200
- errors: [err.response]
201
- }
202
- });
203
- }
182
+ if (!outputPackets.length)
183
+ return this.sendError(executionContext, new exception_1.NotFoundError());
204
184
  const out = outputPackets[0];
205
185
  const resp = executionContext.getResponseWrapper();
206
186
  resp.setStatus(out.status);
207
- resp.setHeader(index_js_1.HttpHeaders.Content_Type, 'application/json');
187
+ resp.setHeader(index_js_1.HttpHeaders.Content_Type, 'application/opra+json');
208
188
  resp.setHeader(index_js_1.HttpHeaders.Cache_Control, 'no-cache');
209
189
  resp.setHeader(index_js_1.HttpHeaders.Pragma, 'no-cache');
210
190
  resp.setHeader(index_js_1.HttpHeaders.Expires, '-1');
@@ -222,34 +202,35 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
222
202
  }
223
203
  createOutput(ctx) {
224
204
  const { query } = ctx;
225
- let status = ctx.response.status;
226
- let body = ctx.response.value || {};
227
- const errors = ctx.response.errors?.map(e => (0, wrap_error_js_1.wrapError)(e));
205
+ let body;
206
+ let status = ctx.status || 0;
207
+ const errors = ctx.errors.map(e => (0, exception_1.wrapException)(e));
228
208
  if (errors && errors.length) {
229
- if (!status || status < 400) {
230
- status = 0;
231
- for (const e of errors) {
232
- status = Math.max(status, e.status || status);
233
- }
209
+ // Sort errors from fatal to info
210
+ errors.sort((a, b) => {
211
+ const i = exception_1.IssueSeverity.Keys.indexOf(a.issue.severity) - exception_1.IssueSeverity.Keys.indexOf(b.issue.severity);
212
+ if (i === 0)
213
+ return b.status - a.status;
214
+ return i;
215
+ });
216
+ if (!status || status < index_js_1.HttpStatus.BAD_REQUEST) {
217
+ status = errors[0].status;
234
218
  if (status < index_js_1.HttpStatus.BAD_REQUEST)
235
219
  status = index_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
236
220
  }
237
- body.errors = errors.map(e => e.response);
221
+ body = {
222
+ operation: ctx.query.method,
223
+ errors: errors.map(e => e.issue)
224
+ };
238
225
  }
239
226
  else {
240
- delete body.errors;
227
+ body = ctx.response;
241
228
  status = status || (query.operation === 'create' ? index_js_1.HttpStatus.CREATED : index_js_1.HttpStatus.OK);
242
229
  }
243
- // Convert headers map to object
244
- const headers = Array.from(ctx.response.headers.keys()).map(k => k.toLowerCase()).sort()
245
- .reduce((a, k) => {
246
- a[k] = ctx.response.headers.get(k);
247
- return a;
248
- }, {});
249
230
  body = this.i18n.deep(body);
250
231
  return {
251
232
  status,
252
- headers,
233
+ headers: ctx.responseHeaders.toObject(),
253
234
  body
254
235
  };
255
236
  }
@@ -261,7 +242,12 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
261
242
  resp.setHeader(index_js_1.HttpHeaders.Pragma, 'no-cache');
262
243
  resp.setHeader(index_js_1.HttpHeaders.Expires, '-1');
263
244
  resp.setHeader(index_js_1.HttpHeaders.X_Opra_Version, schema_1.OpraSchema.Version);
264
- resp.send(JSON.stringify(error.response));
245
+ const issue = this.i18n.deep(error.issue);
246
+ const body = {
247
+ operation: 'unknown',
248
+ errors: [issue]
249
+ };
250
+ resp.send(JSON.stringify(body));
265
251
  }
266
252
  }
267
253
  exports.OpraHttpAdapter = OpraHttpAdapter;
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryResponse = exports.QueryContext = void 0;
4
- const schema_1 = require("@opra/schema");
3
+ exports.QueryContext = void 0;
5
4
  const url_1 = require("@opra/url");
6
- const index_js_1 = require("../enums/index.js");
5
+ const headers_map_js_1 = require("./headers-map.js");
7
6
  class QueryContext {
8
7
  service;
9
8
  executionContext;
@@ -12,14 +11,21 @@ class QueryContext {
12
11
  headers;
13
12
  parentValue;
14
13
  resultPath;
14
+ responseHeaders;
15
15
  response;
16
+ errors = [];
17
+ status;
16
18
  userContext;
17
19
  continueOnError;
18
20
  constructor(args) {
19
- Object.assign(this, args);
20
- this.response = new QueryResponse();
21
+ // Object.assign(this, args);
22
+ this.service = args.service;
23
+ this.executionContext = args.executionContext;
24
+ this.query = args.query;
25
+ // this.response = new QueryResponse();
21
26
  this.params = this.params || new url_1.OpraURLSearchParams();
22
- this.headers = this.headers || new schema_1.ResponsiveMap();
27
+ this.headers = new headers_map_js_1.HeadersMap(args.headers);
28
+ this.responseHeaders = new headers_map_js_1.HeadersMap();
23
29
  this.resultPath = this.resultPath || '';
24
30
  }
25
31
  get type() {
@@ -32,16 +38,3 @@ class QueryContext {
32
38
  }
33
39
  }
34
40
  exports.QueryContext = QueryContext;
35
- class QueryResponse {
36
- headers;
37
- errors = [];
38
- status;
39
- value;
40
- total;
41
- constructor(args) {
42
- if (args)
43
- Object.assign(this, args);
44
- this.headers = new schema_1.ResponsiveMap(undefined, Array.from(Object.values(index_js_1.HttpHeaders)));
45
- }
46
- }
47
- exports.QueryResponse = QueryResponse;
package/cjs/index.js CHANGED
@@ -4,9 +4,7 @@ const tslib_1 = require("tslib");
4
4
  require("reflect-metadata");
5
5
  tslib_1.__exportStar(require("./types.js"), exports);
6
6
  tslib_1.__exportStar(require("./enums/index.js"), exports);
7
- tslib_1.__exportStar(require("./exception/index.js"), exports);
8
7
  tslib_1.__exportStar(require("./interfaces/execution-context.interface.js"), exports);
9
- tslib_1.__exportStar(require("./interfaces/query.interface.js"), exports);
10
8
  tslib_1.__exportStar(require("./interfaces/entity-service.interface.js"), exports);
11
9
  tslib_1.__exportStar(require("./implementation/query-context.js"), exports);
12
10
  tslib_1.__exportStar(require("./implementation/adapter.js"), exports);