@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
@@ -3,153 +3,313 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.JsonDataService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
6
- const rule_judgment_1 = tslib_1.__importDefault(require("rule-judgment"));
6
+ const putil_merge_1 = tslib_1.__importDefault(require("putil-merge"));
7
+ const core_1 = require("@nano-sql/core");
8
+ const exception_1 = require("@opra/exception");
9
+ const schema_1 = require("@opra/schema");
7
10
  const url_1 = require("@opra/url");
8
- const index_js_1 = require("../exception/index.js");
9
- // Fix invalid importing (with ESM) of rule-judgment package
10
- const createFilterFn = typeof rule_judgment_1.default === 'function'
11
- ? rule_judgment_1.default
12
- : rule_judgment_1.default.default;
11
+ const path_to_tree_js_1 = require("../utils/path-to-tree.js");
12
+ let dbId = 1;
13
13
  class JsonDataService {
14
- resourceName;
15
- data;
16
- primaryKey;
17
- constructor(args) {
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);
14
+ resource;
15
+ _status = '';
16
+ _initError;
17
+ _dbName;
18
+ _initData;
19
+ defaultLimit;
20
+ constructor(resource, options) {
21
+ this.resource = resource;
22
+ this.defaultLimit = options?.defaultLimit ?? 10;
23
+ this._initData = options?.data;
24
+ }
25
+ get dataType() {
26
+ return this.resource.dataType;
27
+ }
28
+ get primaryKey() {
29
+ return this.resource.dataType.primaryKey;
30
+ }
31
+ get resourceName() {
32
+ return this.resource.name;
33
+ }
34
+ async close() {
35
+ await this._waitInitializing();
36
+ if (this._status === 'initialized') {
37
+ this._status = 'initializing';
38
+ try {
39
+ await (0, core_1.nSQL)().disconnect(this._dbName);
40
+ }
41
+ finally {
42
+ this._status = '';
43
+ }
44
+ }
45
+ }
46
+ async processRequest(ctx) {
47
+ const prepared = this._prepare(ctx.query);
24
48
  const fn = this[prepared.method];
25
49
  if (!fn)
26
50
  throw new TypeError(`Unimplemented method (${prepared.method})`);
51
+ // @ts-ignore
27
52
  return fn.apply(this, prepared.args);
28
53
  }
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);
54
+ async get(keyValue, options) {
55
+ await this._init();
56
+ const select = this._convertSelect({
57
+ pick: options?.pick,
58
+ omit: options?.omit,
59
+ include: options?.include,
60
+ });
61
+ (0, core_1.nSQL)().useDatabase(this._dbName);
62
+ const rows = await (0, core_1.nSQL)(this.resourceName)
63
+ .query('select', select)
64
+ .where([this.primaryKey, '=', keyValue])
65
+ .exec();
66
+ return unFlatten(rows[0]);
67
+ }
68
+ async count(options) {
69
+ await this._init();
70
+ (0, core_1.nSQL)().useDatabase(this._dbName);
71
+ const rows = await (0, core_1.nSQL)(this.resourceName)
72
+ .query('select', ['COUNT(*) as count'])
73
+ .where(options?.filter || [])
74
+ .exec();
75
+ return (rows[0]?.count) || 0;
76
+ }
77
+ async search(options) {
78
+ await this._init();
79
+ const select = this._convertSelect({
80
+ pick: options?.pick,
81
+ omit: options?.omit,
82
+ include: options?.include,
83
+ });
84
+ const filter = this._convertFilter(options?.filter);
85
+ (0, core_1.nSQL)().useDatabase(this._dbName);
86
+ const query = (0, core_1.nSQL)(this.resourceName)
87
+ .query('select', select)
88
+ .limit(options?.limit || 10)
89
+ .offset(options?.skip || 0)
90
+ .orderBy(options?.sort || [])
91
+ .where(filter || []);
92
+ return (await query.exec()).map(x => unFlatten(x));
93
+ }
94
+ async create(data, options) {
95
+ if (!data[this.primaryKey])
96
+ throw new exception_1.BadRequestError({
97
+ message: 'You must provide primary key value'
98
+ });
99
+ await this._init();
100
+ const keyValue = data[this.primaryKey];
101
+ (0, core_1.nSQL)().useDatabase(this._dbName);
102
+ const rows = await (0, core_1.nSQL)(this._initData).query('select', [this.primaryKey])
103
+ .where([this.primaryKey, '=', keyValue])
104
+ .exec();
105
+ if (rows.length)
106
+ throw new exception_1.ResourceConflictError(this.resourceName, this.primaryKey);
107
+ await (0, core_1.nSQL)(this._initData).query('upsert', data)
108
+ .exec();
109
+ return await this.get(keyValue, options);
110
+ }
111
+ async update(keyValue, data, options) {
112
+ await this._init();
113
+ (0, core_1.nSQL)().useDatabase(this._dbName);
114
+ await (0, core_1.nSQL)(this._initData)
115
+ .query('conform rows', (row) => {
116
+ const out = (0, putil_merge_1.default)({}, row, { deep: true, clone: true });
117
+ (0, putil_merge_1.default)(out, data, { deep: true });
118
+ return out;
119
+ })
120
+ .where([this.primaryKey, '=', keyValue])
121
+ .exec();
122
+ await (0, core_1.nSQL)(this._initData).query("rebuild indexes").exec();
123
+ return this.get(keyValue, options);
124
+ }
125
+ async updateMany(data, options) {
126
+ await this._init();
127
+ const filter = this._convertFilter(options?.filter);
128
+ await this._init();
129
+ (0, core_1.nSQL)().useDatabase(this._dbName);
130
+ let affected = 0;
131
+ await (0, core_1.nSQL)(this._initData)
132
+ .query('conform rows', (row) => {
133
+ const out = (0, putil_merge_1.default)({}, row, { deep: true, clone: true });
134
+ (0, putil_merge_1.default)(out, data, { deep: true });
135
+ affected++;
136
+ return out;
137
+ })
138
+ .where(filter)
139
+ .exec();
140
+ await (0, core_1.nSQL)(this._initData).query("rebuild indexes").exec();
141
+ return affected;
142
+ }
143
+ async delete(keyValue) {
144
+ await this._init();
145
+ (0, core_1.nSQL)().useDatabase(this._dbName);
146
+ const result = await (0, core_1.nSQL)(this._initData)
147
+ .query('delete')
148
+ .where([this.primaryKey, '=', keyValue])
149
+ .exec();
150
+ return !!result.length;
151
+ }
152
+ async deleteMany(options) {
153
+ await this._init();
154
+ const filter = this._convertFilter(options?.filter);
155
+ (0, core_1.nSQL)().useDatabase(this._dbName);
156
+ const result = await (0, core_1.nSQL)(this._initData)
157
+ .query('delete')
158
+ .where(filter)
159
+ .exec();
160
+ return result.length;
161
+ }
162
+ async _waitInitializing() {
163
+ if (this._status === 'initializing') {
164
+ return new Promise((resolve, reject) => {
165
+ const reTry = () => setTimeout(() => {
166
+ if (this._status === '')
167
+ return resolve(this._init());
168
+ if (this._status === 'error')
169
+ return reject(this._initError);
170
+ if (this._status === 'initialized')
171
+ return resolve();
172
+ reTry();
173
+ }, 50).unref();
174
+ reTry();
175
+ });
61
176
  }
62
177
  }
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);
178
+ async _init() {
179
+ await this._waitInitializing();
180
+ if (this._status === 'initialized')
181
+ return;
182
+ this._status = 'initializing';
183
+ this._dbName = 'JsonDataService_DB_' + (dbId++);
184
+ try {
185
+ const model = {
186
+ name: this.resourceName,
187
+ model: {
188
+ '*:any': {}
189
+ },
190
+ indexes: {},
191
+ primaryKey: this.primaryKey
192
+ };
193
+ // Add indexes for sort fields
194
+ const searchMethod = this.resource.metadata.methods.search;
195
+ if (searchMethod) {
196
+ if (searchMethod.sortFields) {
197
+ searchMethod.sortFields.forEach(fieldName => {
198
+ const f = this.dataType.getField(fieldName);
199
+ const fieldType = this.resource.owner.getDataType(f.type || 'string');
200
+ model.indexes[fieldName + ':' + dataTypeToSQLType(fieldType, !!f.isArray)] = {};
201
+ });
202
+ }
203
+ if (searchMethod.filters) {
204
+ searchMethod.filters.forEach(filter => {
205
+ const f = this.dataType.getField(filter.field);
206
+ const fieldType = this.resource.owner.getDataType(f.type || 'string');
207
+ model.indexes[filter.field + ':' + dataTypeToSQLType(fieldType, !!f.isArray)] = {};
208
+ });
209
+ }
210
+ }
211
+ await (0, core_1.nSQL)().createDatabase({
212
+ id: this._dbName,
213
+ version: 3,
214
+ tables: [model]
215
+ });
216
+ this._status = 'initialized';
217
+ if (this._initData) {
218
+ (0, core_1.nSQL)().useDatabase(this._dbName);
219
+ await (0, core_1.nSQL)(this.resourceName)
220
+ .query('upsert', this._initData)
221
+ .exec();
222
+ delete this._initData;
223
+ }
67
224
  }
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;
225
+ catch (e) {
226
+ this._initError = e;
227
+ this._status = 'error';
76
228
  }
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
229
  }
95
- static prepare(query) {
96
- switch (query.queryType) {
97
- case 'create': {
230
+ _prepare(query) {
231
+ if (query.resource instanceof schema_1.EntityResource) {
232
+ if (query.dataType !== this.dataType)
233
+ throw new TypeError(`Query data type (${query.dataType.name}) ` +
234
+ `differs from JsonDataService data type (${this.dataType.name})`);
235
+ }
236
+ switch (query.method) {
237
+ case 'count': {
98
238
  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,
239
+ filter: this._convertFilter(query.filter)
102
240
  }, lodash_1.default.isNil);
103
- const { data } = query;
104
241
  return {
105
- method: query.queryType,
106
- values: data,
242
+ method: query.method,
107
243
  options,
108
- args: [data, options]
244
+ args: [options]
109
245
  };
110
246
  }
111
- case 'get': {
247
+ case 'create': {
112
248
  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,
249
+ pick: query.pick,
250
+ omit: query.omit,
251
+ include: query.include
116
252
  }, lodash_1.default.isNil);
117
- const keyValue = query.keyValue;
253
+ const { data } = query;
118
254
  return {
119
- method: query.queryType,
120
- keyValue,
255
+ method: query.method,
256
+ values: data,
121
257
  options,
122
- args: [keyValue, options]
258
+ args: [data, options]
123
259
  };
124
260
  }
261
+ case 'get': {
262
+ if (query.kind === 'GetInstanceQuery') {
263
+ const options = lodash_1.default.omitBy({
264
+ pick: query.pick,
265
+ omit: query.omit,
266
+ include: query.include
267
+ }, lodash_1.default.isNil);
268
+ const keyValue = query.keyValue;
269
+ return {
270
+ method: query.method,
271
+ keyValue,
272
+ options,
273
+ args: [keyValue, options]
274
+ };
275
+ }
276
+ if (query.kind === 'GetFieldQuery') {
277
+ // todo
278
+ }
279
+ break;
280
+ }
125
281
  case 'search': {
282
+ if (query.distinct)
283
+ throw new exception_1.MethodNotAllowedError({
284
+ message: '$distinct parameter is not supported by JsonDataService'
285
+ });
126
286
  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,
287
+ pick: query.pick,
288
+ omit: query.omit,
289
+ include: query.include,
290
+ filter: this._convertFilter(query.filter),
130
291
  sort: query.sort?.length ? query.sort : undefined,
292
+ skip: query.skip,
131
293
  limit: query.limit,
132
294
  offset: query.skip,
133
- distinct: query.distinct,
134
- total: query.count,
135
- filter: JsonDataService.convertFilter(query.filter)
295
+ count: query.count,
136
296
  }, lodash_1.default.isNil);
137
297
  return {
138
- method: query.queryType,
298
+ method: query.method,
139
299
  options,
140
300
  args: [options]
141
301
  };
142
302
  }
143
303
  case 'update': {
144
304
  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,
305
+ pick: query.pick,
306
+ omit: query.omit,
307
+ include: query.include
148
308
  }, lodash_1.default.isNil);
149
309
  const { data } = query;
150
310
  const keyValue = query.keyValue;
151
311
  return {
152
- method: query.queryType,
312
+ method: query.method,
153
313
  keyValue: query.keyValue,
154
314
  values: data,
155
315
  options,
@@ -158,11 +318,11 @@ class JsonDataService {
158
318
  }
159
319
  case 'updateMany': {
160
320
  const options = lodash_1.default.omitBy({
161
- filter: JsonDataService.convertFilter(query.filter)
321
+ filter: this._convertFilter(query.filter)
162
322
  }, lodash_1.default.isNil);
163
323
  const { data } = query;
164
324
  return {
165
- method: query.queryType,
325
+ method: query.method,
166
326
  options,
167
327
  args: [data, options]
168
328
  };
@@ -171,7 +331,7 @@ class JsonDataService {
171
331
  const options = {};
172
332
  const keyValue = query.keyValue;
173
333
  return {
174
- method: query.queryType,
334
+ method: query.method,
175
335
  keyValue,
176
336
  options,
177
337
  args: [keyValue, options]
@@ -179,44 +339,70 @@ class JsonDataService {
179
339
  }
180
340
  case 'deleteMany': {
181
341
  const options = lodash_1.default.omitBy({
182
- filter: JsonDataService.convertFilter(query.filter)
342
+ filter: this._convertFilter(query.filter)
183
343
  }, lodash_1.default.isNil);
184
344
  return {
185
- method: query.queryType,
345
+ method: query.method,
186
346
  options,
187
347
  args: [options]
188
348
  };
189
349
  }
190
- default:
191
- throw new Error(`Unimplemented query type "${query.queryType}"`);
192
350
  }
351
+ throw new Error(`Unimplemented query type "${query.method}"`);
352
+ }
353
+ _convertSelect(args) {
354
+ const result = [];
355
+ const document = this.dataType.owner;
356
+ const processDataType = (dt, path, pick, omit, include) => {
357
+ let kl;
358
+ for (const [k, f] of dt.fields) {
359
+ kl = k.toLowerCase();
360
+ if (omit?.[kl] === true)
361
+ continue;
362
+ if ((((!pick && !f.exclusive) || pick?.[kl])) || include?.[kl]) {
363
+ const fieldType = document.getDataType(f.type);
364
+ const subPath = (path ? path + '.' : '') + f.name;
365
+ if (fieldType instanceof schema_1.ComplexType) {
366
+ processDataType(fieldType, subPath, typeof pick?.[kl] === 'object' ? pick?.[kl] : undefined, typeof omit?.[kl] === 'object' ? omit?.[kl] : undefined, typeof include?.[kl] === 'object' ? include?.[kl] : undefined);
367
+ continue;
368
+ }
369
+ result.push(subPath);
370
+ }
371
+ }
372
+ };
373
+ processDataType(this.dataType, '', (args.pick ? (0, path_to_tree_js_1.pathToTree)(args.pick, true) : undefined), (args.omit ? (0, path_to_tree_js_1.pathToTree)(args.omit, true) : undefined), (args.include ? (0, path_to_tree_js_1.pathToTree)(args.include, true) : undefined));
374
+ return result;
193
375
  }
194
- static convertFilter(str) {
376
+ _convertFilter(str) {
195
377
  const ast = typeof str === 'string'
196
378
  ? (0, url_1.$parse)(str)
197
379
  : str;
198
380
  if (!ast || !(ast instanceof url_1.Expression))
199
381
  return ast;
200
382
  if (ast instanceof url_1.ComparisonExpression) {
201
- const left = JsonDataService.convertFilter(ast.left);
202
- const right = JsonDataService.convertFilter(ast.right);
383
+ const left = this._convertFilter(ast.left);
384
+ const right = this._convertFilter(ast.right);
203
385
  switch (ast.op) {
204
386
  case '=':
205
- return { $eq: { [left]: right } };
387
+ return [left, '=', right];
206
388
  case '!=':
207
- return { $ne: { [left]: right } };
389
+ return [left, '!=', right];
208
390
  case '>':
209
- return { $gt: { [left]: right } };
391
+ return [left, '>', right];
210
392
  case '>=':
211
- return { $gte: { [left]: right } };
393
+ return [left, '>=', right];
212
394
  case '<':
213
- return { $lt: { [left]: right } };
395
+ return [left, '<', right];
214
396
  case '<=':
215
- return { $lte: { [left]: right } };
397
+ return [left, '<=', right];
398
+ case 'like':
399
+ return [left, 'LIKE', right];
400
+ case '!like':
401
+ return [left, 'NOT LIKE', right];
216
402
  case 'in':
217
- return { $in: { [left]: right } };
403
+ return [left, 'IN', Array.isArray(right) ? right : [right]];
218
404
  case '!in':
219
- return { $nin: { [left]: right } };
405
+ return [left, 'NOT IN', Array.isArray(right) ? right : [right]];
220
406
  default:
221
407
  throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
222
408
  }
@@ -233,20 +419,70 @@ class JsonDataService {
233
419
  return ast.value;
234
420
  }
235
421
  if (ast instanceof url_1.ArrayExpression) {
236
- return ast.items.map(JsonDataService.convertFilter);
422
+ return ast.items.map(item => this._convertFilter(item));
237
423
  }
238
424
  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) };
425
+ return ast.items.map(item => this._convertFilter(item))
426
+ .reduce((a, v) => {
427
+ if (a.length)
428
+ a.push(ast.op.toUpperCase());
429
+ a.push(v);
430
+ return a;
431
+ }, []);
242
432
  }
243
433
  if (ast instanceof url_1.ArrayExpression) {
244
- return ast.items.map(JsonDataService.convertFilter);
434
+ return ast.items.map(item => this._convertFilter(item));
245
435
  }
246
436
  if (ast instanceof url_1.ParenthesesExpression) {
247
- return JsonDataService.convertFilter(ast.expression);
437
+ return this._convertFilter(ast.expression);
248
438
  }
249
- throw new Error(`${ast.type} is not implemented yet`);
439
+ throw new Error(`${ast.kind} is not implemented yet`);
250
440
  }
251
441
  }
252
442
  exports.JsonDataService = JsonDataService;
443
+ function unFlatten(input) {
444
+ if (!input)
445
+ return;
446
+ const target = {};
447
+ for (const k of Object.keys(input)) {
448
+ if (k.includes('.')) {
449
+ const keys = k.split('.');
450
+ let o = target;
451
+ for (let i = 0; i < keys.length - 1; i++) {
452
+ o = o[keys[i]] = o[keys[i]] || {};
453
+ }
454
+ o[keys[keys.length - 1]] = input[k];
455
+ }
456
+ else
457
+ target[k] = input[k];
458
+ }
459
+ return target;
460
+ }
461
+ function dataTypeToSQLType(dataType, isArray) {
462
+ let out = 'any';
463
+ if (dataType.kind !== 'SimpleType')
464
+ out = 'object';
465
+ else {
466
+ switch (dataType.name) {
467
+ case 'booolean':
468
+ case 'number':
469
+ case 'string':
470
+ out = dataType.name;
471
+ break;
472
+ case 'integer':
473
+ out = 'int';
474
+ break;
475
+ case 'date':
476
+ case 'date-time':
477
+ out = 'date';
478
+ break;
479
+ case 'time':
480
+ out = 'string';
481
+ break;
482
+ case 'uuid':
483
+ out = 'uuid';
484
+ break;
485
+ }
486
+ }
487
+ return out + (isArray ? '[]' : '');
488
+ }
@@ -2,21 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pathToTree = void 0;
4
4
  const dotPattern = /^([^.]+)\.(.*)$/;
5
- function pathToTree(arr) {
5
+ function pathToTree(arr, lowerCaseKeys) {
6
6
  if (!arr.length)
7
7
  return;
8
- return _stringPathToObjectTree(arr, {});
8
+ return _pathToTree(arr, {}, lowerCaseKeys);
9
9
  }
10
10
  exports.pathToTree = pathToTree;
11
- function _stringPathToObjectTree(arr, target) {
12
- for (const k of arr) {
11
+ function _pathToTree(arr, target, lowerCaseKeys) {
12
+ for (let k of arr) {
13
+ if (lowerCaseKeys)
14
+ k = k.toLowerCase();
13
15
  const m = dotPattern.exec(k);
14
16
  if (m) {
15
17
  const key = m[1];
16
18
  if (target[key] === true)
17
19
  continue;
18
20
  const sub = target[key] = typeof target[key] === 'object' ? target[key] : {};
19
- _stringPathToObjectTree([m[2]], sub);
21
+ _pathToTree([m[2]], sub);
20
22
  }
21
23
  else {
22
24
  target[k] = true;
@@ -2,8 +2,9 @@
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-OPRA-Version",
6
- X_Opra_Schema = "X-OPRA-Schema",
5
+ X_Opra_Version = "X-Opra-Version",
6
+ X_Opra_Schema = "X-Opra-Schema",
7
+ X_Opra_Count = "X-Opra-Count",
7
8
  /**
8
9
  * Defines the authentication method that should be used to access a resource.
9
10
  */
@@ -5,8 +5,9 @@
5
5
  export var HttpHeaders;
6
6
  (function (HttpHeaders) {
7
7
  /* *** Custom Headers *** */
8
- HttpHeaders["X_Opra_Version"] = "X-OPRA-Version";
9
- HttpHeaders["X_Opra_Schema"] = "X-OPRA-Schema";
8
+ HttpHeaders["X_Opra_Version"] = "X-Opra-Version";
9
+ HttpHeaders["X_Opra_Schema"] = "X-Opra-Schema";
10
+ HttpHeaders["X_Opra_Count"] = "X-Opra-Count";
10
11
  /* *** Authentication *** */
11
12
  /**
12
13
  * Defines the authentication method that should be used to access a resource.