@opra/core 0.10.0 → 0.12.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 +43 -17
- package/cjs/adapter/http-adapter.js +18 -18
- package/cjs/index.js +0 -1
- package/cjs/interfaces/logger.interface.js +2 -0
- package/cjs/services/json-singleton-service.js +9 -7
- package/esm/adapter/adapter.d.ts +4 -0
- package/esm/adapter/adapter.js +44 -18
- package/esm/adapter/http-adapter.js +19 -19
- package/esm/adapter/request-contexts/batch-request-context.d.ts +1 -1
- package/esm/adapter/request-contexts/request-context.d.ts +3 -3
- package/esm/adapter/request-contexts/single-request-context.d.ts +1 -1
- package/esm/enums/issue-severity.enum.d.ts +1 -1
- package/esm/index.d.ts +0 -1
- package/esm/index.js +0 -1
- package/esm/interfaces/execution-context.interface.d.ts +1 -1
- package/esm/interfaces/logger.interface.d.ts +7 -0
- package/esm/interfaces/logger.interface.js +1 -0
- package/esm/interfaces/resource.interface.d.ts +1 -0
- package/esm/services/json-singleton-service.js +2 -1
- package/package.json +20 -19
- package/cjs/services/json-collection-service.js +0 -497
- package/esm/services/json-collection-service.d.ts +0 -83
- package/esm/services/json-collection-service.js +0 -492
package/esm/index.d.ts
CHANGED
|
@@ -8,5 +8,4 @@ export * from './adapter/adapter.js';
|
|
|
8
8
|
export * from './adapter/http-adapter.js';
|
|
9
9
|
export * from './adapter/express-adapter.js';
|
|
10
10
|
export * from './services/data-service.js';
|
|
11
|
-
export * from './services/json-collection-service.js';
|
|
12
11
|
export * from './services/json-singleton-service.js';
|
package/esm/index.js
CHANGED
|
@@ -8,5 +8,4 @@ export * from './adapter/adapter.js';
|
|
|
8
8
|
export * from './adapter/http-adapter.js';
|
|
9
9
|
export * from './adapter/express-adapter.js';
|
|
10
10
|
export * from './services/data-service.js';
|
|
11
|
-
export * from './services/json-collection-service.js';
|
|
12
11
|
export * from './services/json-singleton-service.js';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http';
|
|
4
4
|
import { Readable, Writable } from 'stream';
|
|
5
|
-
export
|
|
5
|
+
export type ContextType = 'http' | 'ws' | 'rpc';
|
|
6
6
|
export declare namespace IExecutionContext {
|
|
7
7
|
type OnFinishArgs = {
|
|
8
8
|
userContext: any;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface ILogger {
|
|
2
|
+
log(message: any, ...optionalParams: any[]): any;
|
|
3
|
+
error(message: any, ...optionalParams: any[]): any;
|
|
4
|
+
warn(message: any, ...optionalParams: any[]): any;
|
|
5
|
+
debug?(message: any, ...optionalParams: any[]): any;
|
|
6
|
+
verbose?(message: any, ...optionalParams: any[]): any;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,6 +3,7 @@ import { ResourceInfo } from '@opra/common';
|
|
|
3
3
|
import { PartialOutput } from '../types.js';
|
|
4
4
|
export interface IResource {
|
|
5
5
|
init?(resource: ResourceInfo): void | Promise<void>;
|
|
6
|
+
shutDown?(): void | Promise<void>;
|
|
6
7
|
}
|
|
7
8
|
export interface ICollectionResource<T, TOutput = PartialOutput<T>> extends IResource {
|
|
8
9
|
create?(...args: any[]): TOutput | Promise<TOutput>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Opra schema package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,32 +19,33 @@
|
|
|
19
19
|
"_copy_pkg_files": "cp README.md package.json ../../LICENSE ../../build/core && cp ../../package.cjs.json ../../build/core/cjs/package.json",
|
|
20
20
|
"_copyi18n": "cp -R i18n ../../build/core/i18n",
|
|
21
21
|
"lint": "eslint . --max-warnings=0",
|
|
22
|
-
"test": "jest",
|
|
23
|
-
"cover": "jest --collect-coverage",
|
|
22
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules npx jest",
|
|
23
|
+
"cover": "NODE_OPTIONS=--experimental-vm-modules npx jest --collect-coverage",
|
|
24
24
|
"clean": "npm run clean:src && npm run clean:dist && npm run clean:cover",
|
|
25
|
-
"clean:src": "ts-cleanup -s src --all",
|
|
25
|
+
"clean:src": "ts-cleanup -s src --all && ts-cleanup -s test --all",
|
|
26
26
|
"clean:dist": "rimraf ../../build/core",
|
|
27
27
|
"clean:cover": "rimraf ../../coverage/core"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"ts-gems": "^2.3.0"
|
|
30
|
+
"@opra/common": "^0.12.0",
|
|
31
|
+
"lodash.isnil": "^4.0.0",
|
|
32
|
+
"lodash.omitby": "^4.6.0",
|
|
33
|
+
"power-tasks": "^1.6.4",
|
|
34
|
+
"putil-isplainobject": "^1.1.5",
|
|
35
|
+
"putil-merge": "^3.10.1",
|
|
36
|
+
"putil-varhelpers": "^1.6.5",
|
|
37
|
+
"strict-typed-events": "^2.3.1"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"body-parser": ">= 1.0.0",
|
|
41
|
+
"express": "^4.x.x || ^5.x.x"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
44
|
"@faker-js/faker": "^7.6.0",
|
|
46
45
|
"@types/dicer": "^0.2.2",
|
|
47
|
-
"@types/express": "^4.17.
|
|
46
|
+
"@types/express": "^4.17.16",
|
|
47
|
+
"cors": "^2.8.5",
|
|
48
|
+
"ts-gems": "^2.3.0"
|
|
48
49
|
},
|
|
49
50
|
"type": "module",
|
|
50
51
|
"types": "esm/index.d.ts",
|
|
@@ -79,4 +80,4 @@
|
|
|
79
80
|
"http",
|
|
80
81
|
"web"
|
|
81
82
|
]
|
|
82
|
-
}
|
|
83
|
+
}
|
|
@@ -1,497 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JsonCollectionService = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const lodash_1 = require("lodash");
|
|
6
|
-
const putil_merge_1 = tslib_1.__importDefault(require("putil-merge"));
|
|
7
|
-
const core_1 = require("@nano-sql/core");
|
|
8
|
-
const common_1 = require("@opra/common");
|
|
9
|
-
let dbId = 1;
|
|
10
|
-
const indexingTypes = ['int', 'float', 'number', 'date', 'string'];
|
|
11
|
-
class JsonCollectionService {
|
|
12
|
-
constructor(resource, options) {
|
|
13
|
-
this.resource = resource;
|
|
14
|
-
this._status = '';
|
|
15
|
-
if (this.resource.keyFields.length > 1)
|
|
16
|
-
throw new TypeError('JsonDataService currently doesn\'t support multiple primary keys');
|
|
17
|
-
this.defaultLimit = options?.defaultLimit ?? 10;
|
|
18
|
-
this._initData = options?.data;
|
|
19
|
-
}
|
|
20
|
-
get dataType() {
|
|
21
|
-
return this.resource.dataType;
|
|
22
|
-
}
|
|
23
|
-
get primaryKey() {
|
|
24
|
-
return this.resource.keyFields[0];
|
|
25
|
-
}
|
|
26
|
-
get resourceName() {
|
|
27
|
-
return this.resource.name;
|
|
28
|
-
}
|
|
29
|
-
async close() {
|
|
30
|
-
await this._waitInitializing();
|
|
31
|
-
if (this._status === 'initialized') {
|
|
32
|
-
this._status = 'initializing';
|
|
33
|
-
try {
|
|
34
|
-
await (0, core_1.nSQL)().disconnect(this._dbName);
|
|
35
|
-
}
|
|
36
|
-
finally {
|
|
37
|
-
this._status = '';
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
async processRequest(ctx) {
|
|
42
|
-
const prepared = this._prepare(ctx.query);
|
|
43
|
-
const fn = this[prepared.method];
|
|
44
|
-
if (!fn)
|
|
45
|
-
throw new TypeError(`Unimplemented method (${prepared.method})`);
|
|
46
|
-
// @ts-ignore
|
|
47
|
-
return fn.apply(this, prepared.args);
|
|
48
|
-
}
|
|
49
|
-
async get(keyValue, options) {
|
|
50
|
-
await this._init();
|
|
51
|
-
const select = this._convertSelect({
|
|
52
|
-
pick: options?.pick,
|
|
53
|
-
omit: options?.omit,
|
|
54
|
-
include: options?.include,
|
|
55
|
-
});
|
|
56
|
-
(0, core_1.nSQL)().useDatabase(this._dbName);
|
|
57
|
-
try {
|
|
58
|
-
const rows = await (0, core_1.nSQL)(this.resourceName)
|
|
59
|
-
.query('select', select)
|
|
60
|
-
.where([this.primaryKey, '=', keyValue])
|
|
61
|
-
.exec();
|
|
62
|
-
return unFlatten(rows[0]);
|
|
63
|
-
}
|
|
64
|
-
catch (e) {
|
|
65
|
-
throw e;
|
|
66
|
-
}
|
|
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 common_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.resourceName).query('select', [this.primaryKey])
|
|
103
|
-
.where([this.primaryKey, '=', keyValue])
|
|
104
|
-
.exec();
|
|
105
|
-
if (rows.length)
|
|
106
|
-
throw new common_1.ResourceConflictError(this.resourceName, this.primaryKey);
|
|
107
|
-
await (0, core_1.nSQL)(this.resourceName).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.resourceName)
|
|
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 nSQL(this.resourceName).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
|
-
(0, core_1.nSQL)().useDatabase(this._dbName);
|
|
129
|
-
let affected = 0;
|
|
130
|
-
await (0, core_1.nSQL)(this.resourceName)
|
|
131
|
-
.query('conform rows', (row) => {
|
|
132
|
-
const out = (0, putil_merge_1.default)({}, row, { deep: true, clone: true });
|
|
133
|
-
(0, putil_merge_1.default)(out, data, { deep: true });
|
|
134
|
-
affected++;
|
|
135
|
-
return out;
|
|
136
|
-
})
|
|
137
|
-
.where(filter)
|
|
138
|
-
.exec();
|
|
139
|
-
// await nSQL(this.resourceName).query("rebuild indexes").exec();
|
|
140
|
-
return affected;
|
|
141
|
-
}
|
|
142
|
-
async delete(keyValue) {
|
|
143
|
-
await this._init();
|
|
144
|
-
(0, core_1.nSQL)().useDatabase(this._dbName);
|
|
145
|
-
const result = await (0, core_1.nSQL)(this.resourceName)
|
|
146
|
-
.query('delete')
|
|
147
|
-
.where([this.primaryKey, '=', keyValue])
|
|
148
|
-
.exec();
|
|
149
|
-
return !!result.length;
|
|
150
|
-
}
|
|
151
|
-
async deleteMany(options) {
|
|
152
|
-
await this._init();
|
|
153
|
-
const filter = this._convertFilter(options?.filter);
|
|
154
|
-
(0, core_1.nSQL)().useDatabase(this._dbName);
|
|
155
|
-
const result = await (0, core_1.nSQL)(this.resourceName)
|
|
156
|
-
.query('delete')
|
|
157
|
-
.where(filter)
|
|
158
|
-
.exec();
|
|
159
|
-
return result.length;
|
|
160
|
-
}
|
|
161
|
-
async _waitInitializing() {
|
|
162
|
-
if (this._status === 'initializing') {
|
|
163
|
-
return new Promise((resolve, reject) => {
|
|
164
|
-
const reTry = () => setTimeout(() => {
|
|
165
|
-
if (this._status === '')
|
|
166
|
-
return resolve(this._init());
|
|
167
|
-
if (this._status === 'error')
|
|
168
|
-
return reject(this._initError);
|
|
169
|
-
if (this._status === 'initialized')
|
|
170
|
-
return resolve();
|
|
171
|
-
reTry();
|
|
172
|
-
}, 50).unref();
|
|
173
|
-
reTry();
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
async _init() {
|
|
178
|
-
await this._waitInitializing();
|
|
179
|
-
if (this._status === 'initialized')
|
|
180
|
-
return;
|
|
181
|
-
this._status = 'initializing';
|
|
182
|
-
this._dbName = 'JsonDataService_DB_' + (dbId++);
|
|
183
|
-
try {
|
|
184
|
-
const table = {
|
|
185
|
-
name: this.resourceName,
|
|
186
|
-
model: {},
|
|
187
|
-
indexes: {}
|
|
188
|
-
};
|
|
189
|
-
for (const [k, f] of this.resource.dataType.fields.entries()) {
|
|
190
|
-
const fieldType = this.resource.document.getDataType(f.type || 'string');
|
|
191
|
-
const o = table.model[k + ':' + dataTypeToSQLType(fieldType, !!f.isArray)] = {};
|
|
192
|
-
if (k === this.primaryKey)
|
|
193
|
-
o.pk = true;
|
|
194
|
-
}
|
|
195
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
196
|
-
const indexes = table.indexes;
|
|
197
|
-
// Add indexes for sort fields
|
|
198
|
-
const searchResolver = this.resource.metadata.search;
|
|
199
|
-
if (searchResolver) {
|
|
200
|
-
if (searchResolver.sortFields) {
|
|
201
|
-
searchResolver.sortFields.forEach(fieldName => {
|
|
202
|
-
const f = this.dataType.getField(fieldName);
|
|
203
|
-
const fieldType = this.resource.document.getDataType(f.type || 'string');
|
|
204
|
-
const t = dataTypeToSQLType(fieldType, !!f.isArray);
|
|
205
|
-
if (indexingTypes.includes(t))
|
|
206
|
-
indexes[fieldName + ':' + t] = {};
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
if (searchResolver.filters) {
|
|
210
|
-
searchResolver.filters.forEach(filter => {
|
|
211
|
-
const f = this.dataType.getField(filter.field);
|
|
212
|
-
const fieldType = this.resource.document.getDataType(f.type || 'string');
|
|
213
|
-
const t = dataTypeToSQLType(fieldType, !!f.isArray);
|
|
214
|
-
if (indexingTypes.includes(t))
|
|
215
|
-
indexes[filter.field + ':' + t] = {};
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
await (0, core_1.nSQL)().createDatabase({
|
|
220
|
-
id: this._dbName,
|
|
221
|
-
version: 3,
|
|
222
|
-
tables: [table]
|
|
223
|
-
});
|
|
224
|
-
this._status = 'initialized';
|
|
225
|
-
if (this._initData) {
|
|
226
|
-
(0, core_1.nSQL)().useDatabase(this._dbName);
|
|
227
|
-
await (0, core_1.nSQL)(this.resourceName)
|
|
228
|
-
.query('upsert', this._initData)
|
|
229
|
-
.exec();
|
|
230
|
-
delete this._initData;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
catch (e) {
|
|
234
|
-
this._initError = e;
|
|
235
|
-
this._status = 'error';
|
|
236
|
-
throw e;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
_prepare(query) {
|
|
240
|
-
if (query.resource instanceof common_1.CollectionResourceInfo) {
|
|
241
|
-
if (query.dataType !== this.dataType)
|
|
242
|
-
throw new TypeError(`Query data type (${query.dataType.name}) ` +
|
|
243
|
-
`differs from JsonCollectionService data type (${this.dataType.name})`);
|
|
244
|
-
}
|
|
245
|
-
switch (query.method) {
|
|
246
|
-
case 'count': {
|
|
247
|
-
const options = (0, lodash_1.omitBy)({
|
|
248
|
-
filter: this._convertFilter(query.filter)
|
|
249
|
-
}, lodash_1.isNil);
|
|
250
|
-
return {
|
|
251
|
-
method: query.method,
|
|
252
|
-
options,
|
|
253
|
-
args: [options]
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
case 'create': {
|
|
257
|
-
const options = (0, lodash_1.omitBy)({
|
|
258
|
-
pick: query.pick,
|
|
259
|
-
omit: query.omit,
|
|
260
|
-
include: query.include
|
|
261
|
-
}, lodash_1.isNil);
|
|
262
|
-
const { data } = query;
|
|
263
|
-
return {
|
|
264
|
-
method: query.method,
|
|
265
|
-
values: data,
|
|
266
|
-
options,
|
|
267
|
-
args: [data, options]
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
case 'get': {
|
|
271
|
-
if (query.kind === 'CollectionGetQuery') {
|
|
272
|
-
const options = (0, lodash_1.omitBy)({
|
|
273
|
-
pick: query.pick,
|
|
274
|
-
omit: query.omit,
|
|
275
|
-
include: query.include
|
|
276
|
-
}, lodash_1.isNil);
|
|
277
|
-
const keyValue = query.keyValue;
|
|
278
|
-
return {
|
|
279
|
-
method: query.method,
|
|
280
|
-
keyValue,
|
|
281
|
-
options,
|
|
282
|
-
args: [keyValue, options]
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
if (query.kind === 'FieldGetQuery') {
|
|
286
|
-
// todo
|
|
287
|
-
}
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
case 'search': {
|
|
291
|
-
if (query.distinct)
|
|
292
|
-
throw new common_1.MethodNotAllowedError({
|
|
293
|
-
message: '$distinct parameter is not supported by JsonDataService'
|
|
294
|
-
});
|
|
295
|
-
const options = (0, lodash_1.omitBy)({
|
|
296
|
-
pick: query.pick,
|
|
297
|
-
omit: query.omit,
|
|
298
|
-
include: query.include,
|
|
299
|
-
filter: this._convertFilter(query.filter),
|
|
300
|
-
sort: query.sort?.length ? query.sort : undefined,
|
|
301
|
-
skip: query.skip,
|
|
302
|
-
limit: query.limit,
|
|
303
|
-
offset: query.skip,
|
|
304
|
-
count: query.count,
|
|
305
|
-
}, lodash_1.isNil);
|
|
306
|
-
return {
|
|
307
|
-
method: query.method,
|
|
308
|
-
options,
|
|
309
|
-
args: [options]
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
case 'update': {
|
|
313
|
-
const options = (0, lodash_1.omitBy)({
|
|
314
|
-
pick: query.pick,
|
|
315
|
-
omit: query.omit,
|
|
316
|
-
include: query.include
|
|
317
|
-
}, lodash_1.isNil);
|
|
318
|
-
const { data } = query;
|
|
319
|
-
const keyValue = query.keyValue;
|
|
320
|
-
return {
|
|
321
|
-
method: query.method,
|
|
322
|
-
keyValue: query.keyValue,
|
|
323
|
-
values: data,
|
|
324
|
-
options,
|
|
325
|
-
args: [keyValue, data, options]
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
case 'updateMany': {
|
|
329
|
-
const options = (0, lodash_1.omitBy)({
|
|
330
|
-
filter: this._convertFilter(query.filter)
|
|
331
|
-
}, lodash_1.isNil);
|
|
332
|
-
const { data } = query;
|
|
333
|
-
return {
|
|
334
|
-
method: query.method,
|
|
335
|
-
options,
|
|
336
|
-
args: [data, options]
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
case 'delete': {
|
|
340
|
-
const options = {};
|
|
341
|
-
const keyValue = query.keyValue;
|
|
342
|
-
return {
|
|
343
|
-
method: query.method,
|
|
344
|
-
keyValue,
|
|
345
|
-
options,
|
|
346
|
-
args: [keyValue, options]
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
case 'deleteMany': {
|
|
350
|
-
const options = (0, lodash_1.omitBy)({
|
|
351
|
-
filter: this._convertFilter(query.filter)
|
|
352
|
-
}, lodash_1.isNil);
|
|
353
|
-
return {
|
|
354
|
-
method: query.method,
|
|
355
|
-
options,
|
|
356
|
-
args: [options]
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
throw new Error(`Unimplemented query type "${query.method}"`);
|
|
361
|
-
}
|
|
362
|
-
_convertSelect(args) {
|
|
363
|
-
const result = [];
|
|
364
|
-
const document = this.dataType.document;
|
|
365
|
-
const processDataType = (dt, path, pick, omit, include) => {
|
|
366
|
-
let kl;
|
|
367
|
-
for (const [k, f] of dt.fields) {
|
|
368
|
-
kl = k.toLowerCase();
|
|
369
|
-
if (omit?.[kl] === true)
|
|
370
|
-
continue;
|
|
371
|
-
if ((((!pick && !f.exclusive) || pick?.[kl])) || include?.[kl]) {
|
|
372
|
-
const fieldType = document.getDataType(f.type);
|
|
373
|
-
const subPath = (path ? path + '.' : '') + f.name;
|
|
374
|
-
if (fieldType instanceof common_1.ComplexType) {
|
|
375
|
-
processDataType(fieldType, subPath, typeof pick?.[kl] === 'object' ? pick?.[kl] : undefined, typeof omit?.[kl] === 'object' ? omit?.[kl] : undefined, typeof include?.[kl] === 'object' ? include?.[kl] : undefined);
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
result.push(subPath);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
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));
|
|
383
|
-
return result;
|
|
384
|
-
}
|
|
385
|
-
_convertFilter(str) {
|
|
386
|
-
const ast = typeof str === 'string'
|
|
387
|
-
? (0, common_1.parseFilter)(str)
|
|
388
|
-
: str;
|
|
389
|
-
if (!ast || !(ast instanceof common_1.Expression))
|
|
390
|
-
return ast;
|
|
391
|
-
if (ast instanceof common_1.ComparisonExpression) {
|
|
392
|
-
const left = this._convertFilter(ast.left);
|
|
393
|
-
const right = this._convertFilter(ast.right);
|
|
394
|
-
switch (ast.op) {
|
|
395
|
-
case '=':
|
|
396
|
-
return [left, '=', right];
|
|
397
|
-
case '!=':
|
|
398
|
-
return [left, '!=', right];
|
|
399
|
-
case '>':
|
|
400
|
-
return [left, '>', right];
|
|
401
|
-
case '>=':
|
|
402
|
-
return [left, '>=', right];
|
|
403
|
-
case '<':
|
|
404
|
-
return [left, '<', right];
|
|
405
|
-
case '<=':
|
|
406
|
-
return [left, '<=', right];
|
|
407
|
-
case 'like':
|
|
408
|
-
return [left, 'LIKE', right];
|
|
409
|
-
case '!like':
|
|
410
|
-
return [left, 'NOT LIKE', right];
|
|
411
|
-
case 'in':
|
|
412
|
-
return [left, 'IN', Array.isArray(right) ? right : [right]];
|
|
413
|
-
case '!in':
|
|
414
|
-
return [left, 'NOT IN', Array.isArray(right) ? right : [right]];
|
|
415
|
-
default:
|
|
416
|
-
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if (ast instanceof common_1.QualifiedIdentifier) {
|
|
420
|
-
return ast.value;
|
|
421
|
-
}
|
|
422
|
-
if (ast instanceof common_1.NumberLiteral ||
|
|
423
|
-
ast instanceof common_1.StringLiteral ||
|
|
424
|
-
ast instanceof common_1.BooleanLiteral ||
|
|
425
|
-
ast instanceof common_1.NullLiteral ||
|
|
426
|
-
ast instanceof common_1.DateLiteral ||
|
|
427
|
-
ast instanceof common_1.TimeLiteral) {
|
|
428
|
-
return ast.value;
|
|
429
|
-
}
|
|
430
|
-
if (ast instanceof common_1.ArrayExpression) {
|
|
431
|
-
return ast.items.map(item => this._convertFilter(item));
|
|
432
|
-
}
|
|
433
|
-
if (ast instanceof common_1.LogicalExpression) {
|
|
434
|
-
return ast.items.map(item => this._convertFilter(item))
|
|
435
|
-
.reduce((a, v) => {
|
|
436
|
-
if (a.length)
|
|
437
|
-
a.push(ast.op.toUpperCase());
|
|
438
|
-
a.push(v);
|
|
439
|
-
return a;
|
|
440
|
-
}, []);
|
|
441
|
-
}
|
|
442
|
-
if (ast instanceof common_1.ArrayExpression) {
|
|
443
|
-
return ast.items.map(item => this._convertFilter(item));
|
|
444
|
-
}
|
|
445
|
-
if (ast instanceof common_1.ParenthesesExpression) {
|
|
446
|
-
return this._convertFilter(ast.expression);
|
|
447
|
-
}
|
|
448
|
-
throw new Error(`${ast.kind} is not implemented yet`);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
exports.JsonCollectionService = JsonCollectionService;
|
|
452
|
-
function unFlatten(input) {
|
|
453
|
-
if (!input)
|
|
454
|
-
return;
|
|
455
|
-
const target = {};
|
|
456
|
-
for (const k of Object.keys(input)) {
|
|
457
|
-
if (k.includes('.')) {
|
|
458
|
-
const keys = k.split('.');
|
|
459
|
-
let o = target;
|
|
460
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
461
|
-
o = o[keys[i]] = o[keys[i]] || {};
|
|
462
|
-
}
|
|
463
|
-
o[keys[keys.length - 1]] = input[k];
|
|
464
|
-
}
|
|
465
|
-
else
|
|
466
|
-
target[k] = input[k];
|
|
467
|
-
}
|
|
468
|
-
return target;
|
|
469
|
-
}
|
|
470
|
-
function dataTypeToSQLType(dataType, isArray) {
|
|
471
|
-
let out = 'any';
|
|
472
|
-
if (dataType.kind !== 'SimpleType')
|
|
473
|
-
out = 'object';
|
|
474
|
-
else {
|
|
475
|
-
switch (dataType.name) {
|
|
476
|
-
case 'boolean':
|
|
477
|
-
case 'number':
|
|
478
|
-
case 'string':
|
|
479
|
-
out = dataType.name;
|
|
480
|
-
break;
|
|
481
|
-
case 'integer':
|
|
482
|
-
out = 'int';
|
|
483
|
-
break;
|
|
484
|
-
// case 'date': //there is bug in nano-sql.
|
|
485
|
-
// case 'date-time':
|
|
486
|
-
// out = 'date';
|
|
487
|
-
// break;
|
|
488
|
-
case 'time':
|
|
489
|
-
out = 'string';
|
|
490
|
-
break;
|
|
491
|
-
case 'uuid':
|
|
492
|
-
out = 'uuid';
|
|
493
|
-
break;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return out + (isArray ? '[]' : '');
|
|
497
|
-
}
|