@opra/core 0.1.1 → 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.
- package/cjs/enums/http-headers.enum.js +3 -2
- package/cjs/implementation/adapter-utils/entity-resource-execute.util.js +36 -34
- package/cjs/implementation/adapter-utils/resource-prepare.util.js +1 -1
- package/cjs/implementation/adapter.js +14 -19
- package/cjs/implementation/express-adapter.js +3 -0
- package/cjs/implementation/headers-map.js +18 -0
- package/cjs/implementation/http-adapter.js +65 -79
- package/cjs/implementation/query-context.js +12 -19
- package/cjs/index.js +0 -2
- package/cjs/services/json-data-service.js +367 -131
- package/cjs/utils/path-to-tree.js +7 -5
- package/esm/enums/http-headers.enum.d.ts +3 -2
- package/esm/enums/http-headers.enum.js +3 -2
- package/esm/implementation/adapter-utils/entity-resource-execute.util.js +35 -33
- package/esm/implementation/adapter-utils/resource-execute.util.d.ts +2 -2
- package/esm/implementation/adapter-utils/resource-prepare.util.d.ts +2 -2
- package/esm/implementation/adapter-utils/resource-prepare.util.js +1 -1
- package/esm/implementation/adapter.d.ts +2 -2
- package/esm/implementation/adapter.js +12 -17
- package/esm/implementation/express-adapter.js +2 -0
- package/esm/implementation/headers-map.d.ts +5 -0
- package/esm/implementation/headers-map.js +14 -0
- package/esm/implementation/http-adapter.d.ts +6 -6
- package/esm/implementation/http-adapter.js +61 -75
- package/esm/implementation/query-context.d.ts +9 -15
- package/esm/implementation/query-context.js +11 -17
- package/esm/index.d.ts +0 -2
- package/esm/index.js +0 -2
- package/esm/interfaces/entity-service.interface.d.ts +8 -6
- package/esm/services/json-data-service.d.ts +56 -39
- package/esm/services/json-data-service.js +365 -129
- package/esm/types.d.ts +0 -3
- package/esm/utils/path-to-tree.d.ts +1 -1
- package/esm/utils/path-to-tree.js +7 -5
- package/i18n/en/error.json +5 -5
- package/package.json +11 -8
- package/cjs/exception/api-exception.js +0 -68
- package/cjs/exception/http-errors/bad-request.error.js +0 -26
- package/cjs/exception/http-errors/failed-dependency.error.js +0 -25
- package/cjs/exception/http-errors/forbidden.error.js +0 -27
- package/cjs/exception/http-errors/internal-server.error.js +0 -27
- package/cjs/exception/http-errors/method-not-allowed.error.js +0 -26
- package/cjs/exception/http-errors/not-acceptable.error.js +0 -26
- package/cjs/exception/http-errors/not-found.error.js +0 -29
- package/cjs/exception/http-errors/unauthorized.error.js +0 -26
- package/cjs/exception/http-errors/unprocessable-entity.error.js +0 -25
- package/cjs/exception/index.js +0 -15
- package/cjs/exception/resource-errors/resource-conflict.error.js +0 -19
- package/cjs/exception/resource-errors/resource-not-found.error.js +0 -19
- package/cjs/exception/wrap-error.js +0 -17
- package/cjs/interfaces/query.interface.js +0 -207
- package/esm/exception/api-exception.d.ts +0 -40
- package/esm/exception/api-exception.js +0 -64
- package/esm/exception/http-errors/bad-request.error.d.ts +0 -10
- package/esm/exception/http-errors/bad-request.error.js +0 -22
- package/esm/exception/http-errors/failed-dependency.error.d.ts +0 -9
- package/esm/exception/http-errors/failed-dependency.error.js +0 -21
- package/esm/exception/http-errors/forbidden.error.d.ts +0 -11
- package/esm/exception/http-errors/forbidden.error.js +0 -23
- package/esm/exception/http-errors/internal-server.error.d.ts +0 -9
- package/esm/exception/http-errors/internal-server.error.js +0 -22
- package/esm/exception/http-errors/method-not-allowed.error.d.ts +0 -10
- package/esm/exception/http-errors/method-not-allowed.error.js +0 -22
- package/esm/exception/http-errors/not-acceptable.error.d.ts +0 -10
- package/esm/exception/http-errors/not-acceptable.error.js +0 -22
- package/esm/exception/http-errors/not-found.error.d.ts +0 -13
- package/esm/exception/http-errors/not-found.error.js +0 -25
- package/esm/exception/http-errors/unauthorized.error.d.ts +0 -10
- package/esm/exception/http-errors/unauthorized.error.js +0 -22
- package/esm/exception/http-errors/unprocessable-entity.error.d.ts +0 -9
- package/esm/exception/http-errors/unprocessable-entity.error.js +0 -21
- package/esm/exception/index.d.ts +0 -12
- package/esm/exception/index.js +0 -12
- package/esm/exception/resource-errors/resource-conflict.error.d.ts +0 -4
- package/esm/exception/resource-errors/resource-conflict.error.js +0 -15
- package/esm/exception/resource-errors/resource-not-found.error.d.ts +0 -4
- package/esm/exception/resource-errors/resource-not-found.error.js +0 -15
- package/esm/exception/wrap-error.d.ts +0 -2
- package/esm/exception/wrap-error.js +0 -13
- package/esm/interfaces/query.interface.d.ts +0 -115
- 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
|
|
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
|
|
9
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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.
|
|
106
|
-
values: data,
|
|
242
|
+
method: query.method,
|
|
107
243
|
options,
|
|
108
|
-
args: [
|
|
244
|
+
args: [options]
|
|
109
245
|
};
|
|
110
246
|
}
|
|
111
|
-
case '
|
|
247
|
+
case 'create': {
|
|
112
248
|
const options = lodash_1.default.omitBy({
|
|
113
|
-
pick: query.pick
|
|
114
|
-
omit: query.omit
|
|
115
|
-
include: query.include
|
|
249
|
+
pick: query.pick,
|
|
250
|
+
omit: query.omit,
|
|
251
|
+
include: query.include
|
|
116
252
|
}, lodash_1.default.isNil);
|
|
117
|
-
const
|
|
253
|
+
const { data } = query;
|
|
118
254
|
return {
|
|
119
|
-
method: query.
|
|
120
|
-
|
|
255
|
+
method: query.method,
|
|
256
|
+
values: data,
|
|
121
257
|
options,
|
|
122
|
-
args: [
|
|
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
|
|
128
|
-
omit: query.omit
|
|
129
|
-
include: query.include
|
|
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
|
-
|
|
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.
|
|
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
|
|
146
|
-
omit: query.omit
|
|
147
|
-
include: query.include
|
|
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.
|
|
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:
|
|
321
|
+
filter: this._convertFilter(query.filter)
|
|
162
322
|
}, lodash_1.default.isNil);
|
|
163
323
|
const { data } = query;
|
|
164
324
|
return {
|
|
165
|
-
method: query.
|
|
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.
|
|
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:
|
|
342
|
+
filter: this._convertFilter(query.filter)
|
|
183
343
|
}, lodash_1.default.isNil);
|
|
184
344
|
return {
|
|
185
|
-
method: query.
|
|
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
|
-
|
|
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 =
|
|
202
|
-
const 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
|
|
387
|
+
return [left, '=', right];
|
|
206
388
|
case '!=':
|
|
207
|
-
return
|
|
389
|
+
return [left, '!=', right];
|
|
208
390
|
case '>':
|
|
209
|
-
return
|
|
391
|
+
return [left, '>', right];
|
|
210
392
|
case '>=':
|
|
211
|
-
return
|
|
393
|
+
return [left, '>=', right];
|
|
212
394
|
case '<':
|
|
213
|
-
return
|
|
395
|
+
return [left, '<', right];
|
|
214
396
|
case '<=':
|
|
215
|
-
return
|
|
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
|
|
403
|
+
return [left, 'IN', Array.isArray(right) ? right : [right]];
|
|
218
404
|
case '!in':
|
|
219
|
-
return
|
|
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(
|
|
422
|
+
return ast.items.map(item => this._convertFilter(item));
|
|
237
423
|
}
|
|
238
424
|
if (ast instanceof url_1.LogicalExpression) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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(
|
|
434
|
+
return ast.items.map(item => this._convertFilter(item));
|
|
245
435
|
}
|
|
246
436
|
if (ast instanceof url_1.ParenthesesExpression) {
|
|
247
|
-
return
|
|
437
|
+
return this._convertFilter(ast.expression);
|
|
248
438
|
}
|
|
249
|
-
throw new Error(`${ast.
|
|
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
|
|
8
|
+
return _pathToTree(arr, {}, lowerCaseKeys);
|
|
9
9
|
}
|
|
10
10
|
exports.pathToTree = pathToTree;
|
|
11
|
-
function
|
|
12
|
-
for (
|
|
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
|
-
|
|
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-
|
|
6
|
-
X_Opra_Schema = "X-
|
|
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-
|
|
9
|
-
HttpHeaders["X_Opra_Schema"] = "X-
|
|
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.
|