oak-db 3.3.10 → 3.3.12
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/lib/MySQL/connector.d.ts +15 -15
- package/lib/MySQL/connector.js +77 -77
- package/lib/MySQL/store.d.ts +30 -4
- package/lib/MySQL/store.js +125 -3
- package/lib/MySQL/translator.d.ts +114 -107
- package/lib/MySQL/translator.js +1207 -969
- package/lib/MySQL/types/Configuration.d.ts +12 -12
- package/lib/MySQL/types/Configuration.js +2 -2
- package/lib/PostgreSQL/connector.d.ts +31 -0
- package/lib/PostgreSQL/connector.js +157 -0
- package/lib/PostgreSQL/store.d.ts +38 -0
- package/lib/PostgreSQL/store.js +329 -0
- package/lib/PostgreSQL/translator.d.ts +83 -0
- package/lib/PostgreSQL/translator.js +1770 -0
- package/lib/PostgreSQL/types/Configuration.d.ts +13 -0
- package/lib/PostgreSQL/types/Configuration.js +2 -0
- package/lib/index.d.ts +4 -2
- package/lib/index.js +5 -4
- package/lib/sqlTranslator.d.ts +68 -55
- package/lib/sqlTranslator.js +72 -39
- package/lib/types/Translator.d.ts +3 -3
- package/lib/types/Translator.js +2 -2
- package/lib/types/configuration.d.ts +7 -0
- package/lib/types/configuration.js +2 -0
- package/lib/types/dbStore.d.ts +8 -0
- package/lib/types/dbStore.js +3 -0
- package/package.json +6 -5
package/lib/MySQL/translator.js
CHANGED
|
@@ -1,969 +1,1207 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MySqlTranslator = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
-
const util_1 = require("util");
|
|
7
|
-
const lodash_1 = require("lodash");
|
|
8
|
-
const types_1 = require("oak-domain/lib/types");
|
|
9
|
-
const sqlTranslator_1 = require("../sqlTranslator");
|
|
10
|
-
const GeoTypes = [
|
|
11
|
-
{
|
|
12
|
-
type: 'point',
|
|
13
|
-
name: "Point"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
type: 'path',
|
|
17
|
-
name: "LineString",
|
|
18
|
-
element: 'point',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: "MultiLineString",
|
|
22
|
-
element: "path",
|
|
23
|
-
multiple: true,
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
type: 'polygon',
|
|
27
|
-
name: "Polygon",
|
|
28
|
-
element: "path"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: "MultiPoint",
|
|
32
|
-
element: "point",
|
|
33
|
-
multiple: true,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: "MultiPolygon",
|
|
37
|
-
element: "polygon",
|
|
38
|
-
multiple: true,
|
|
39
|
-
}
|
|
40
|
-
];
|
|
41
|
-
function transformGeoData(data) {
|
|
42
|
-
if (data instanceof Array) {
|
|
43
|
-
const element = data[0];
|
|
44
|
-
if (element instanceof Array) {
|
|
45
|
-
return ` GeometryCollection(${data.map(ele => transformGeoData(ele)).join(',')})`;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
const geoType = GeoTypes.find(ele => ele.type === element.type);
|
|
49
|
-
if (!geoType) {
|
|
50
|
-
throw new Error(`${element.type} is not supported in MySQL`);
|
|
51
|
-
}
|
|
52
|
-
const multiGeoType = GeoTypes.find(ele => ele.element === geoType.type && ele.multiple);
|
|
53
|
-
return ` ${multiGeoType.name}(${data.map(ele => transformGeoData(ele)).join(',')})`;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
const { type, coordinate } = data;
|
|
58
|
-
const geoType = GeoTypes.find(ele => ele.type === type);
|
|
59
|
-
if (!geoType) {
|
|
60
|
-
throw new Error(`${data.type} is not supported in MySQL`);
|
|
61
|
-
}
|
|
62
|
-
const { element, name } = geoType;
|
|
63
|
-
if (!element) {
|
|
64
|
-
// Point
|
|
65
|
-
return ` ${name}(${coordinate.join(',')})`;
|
|
66
|
-
}
|
|
67
|
-
// Polygon or Linestring
|
|
68
|
-
return ` ${name}(${coordinate.map((ele) => transformGeoData({
|
|
69
|
-
type: element,
|
|
70
|
-
coordinate: ele,
|
|
71
|
-
}))})`;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
75
|
-
getDefaultSelectFilter(alias, option) {
|
|
76
|
-
if (option?.includedDeleted) {
|
|
77
|
-
return '';
|
|
78
|
-
}
|
|
79
|
-
return ` (\`${alias}\`.\`$$deleteAt$$\` is null)`;
|
|
80
|
-
}
|
|
81
|
-
makeUpSchema() {
|
|
82
|
-
for (const entity in this.schema) {
|
|
83
|
-
const { attributes, indexes } = this.schema[entity];
|
|
84
|
-
const geoIndexes = [];
|
|
85
|
-
for (const attr in attributes) {
|
|
86
|
-
if (attributes[attr].type === 'geometry') {
|
|
87
|
-
const geoIndex = indexes?.find((idx) => idx.config?.type === 'spatial' && idx.attributes.find((attrDef) => attrDef.name === attr));
|
|
88
|
-
if (!geoIndex) {
|
|
89
|
-
geoIndexes.push({
|
|
90
|
-
name: `${entity}_geo_${attr}`,
|
|
91
|
-
attributes: [{
|
|
92
|
-
name: attr,
|
|
93
|
-
}],
|
|
94
|
-
config: {
|
|
95
|
-
type: 'spatial',
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (geoIndexes.length > 0) {
|
|
102
|
-
if (indexes) {
|
|
103
|
-
indexes.push(...geoIndexes);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
(0, lodash_1.assign)(this.schema[entity], {
|
|
107
|
-
indexes: geoIndexes,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
constructor(schema) {
|
|
114
|
-
super(schema);
|
|
115
|
-
// MySQL为geometry属性默认创建索引
|
|
116
|
-
this.makeUpSchema();
|
|
117
|
-
}
|
|
118
|
-
static supportedDataTypes = [
|
|
119
|
-
// numeric types
|
|
120
|
-
"bit",
|
|
121
|
-
"int",
|
|
122
|
-
"integer",
|
|
123
|
-
"tinyint",
|
|
124
|
-
"smallint",
|
|
125
|
-
"mediumint",
|
|
126
|
-
"bigint",
|
|
127
|
-
"float",
|
|
128
|
-
"double",
|
|
129
|
-
"double precision",
|
|
130
|
-
"real",
|
|
131
|
-
"decimal",
|
|
132
|
-
"dec",
|
|
133
|
-
"numeric",
|
|
134
|
-
"fixed",
|
|
135
|
-
"bool",
|
|
136
|
-
"boolean",
|
|
137
|
-
// date and time types
|
|
138
|
-
"date",
|
|
139
|
-
"datetime",
|
|
140
|
-
"timestamp",
|
|
141
|
-
"time",
|
|
142
|
-
"year",
|
|
143
|
-
// string types
|
|
144
|
-
"char",
|
|
145
|
-
"nchar",
|
|
146
|
-
"national char",
|
|
147
|
-
"varchar",
|
|
148
|
-
"nvarchar",
|
|
149
|
-
"national varchar",
|
|
150
|
-
"blob",
|
|
151
|
-
"text",
|
|
152
|
-
"tinyblob",
|
|
153
|
-
"tinytext",
|
|
154
|
-
"mediumblob",
|
|
155
|
-
"mediumtext",
|
|
156
|
-
"longblob",
|
|
157
|
-
"longtext",
|
|
158
|
-
"enum",
|
|
159
|
-
"set",
|
|
160
|
-
"binary",
|
|
161
|
-
"varbinary",
|
|
162
|
-
// json data type
|
|
163
|
-
"json",
|
|
164
|
-
// spatial data types
|
|
165
|
-
"geometry",
|
|
166
|
-
"point",
|
|
167
|
-
"linestring",
|
|
168
|
-
"polygon",
|
|
169
|
-
"multipoint",
|
|
170
|
-
"multilinestring",
|
|
171
|
-
"multipolygon",
|
|
172
|
-
"geometrycollection"
|
|
173
|
-
];
|
|
174
|
-
static spatialTypes = [
|
|
175
|
-
"geometry",
|
|
176
|
-
"point",
|
|
177
|
-
"linestring",
|
|
178
|
-
"polygon",
|
|
179
|
-
"multipoint",
|
|
180
|
-
"multilinestring",
|
|
181
|
-
"multipolygon",
|
|
182
|
-
"geometrycollection"
|
|
183
|
-
];
|
|
184
|
-
static withLengthDataTypes = [
|
|
185
|
-
"char",
|
|
186
|
-
"varchar",
|
|
187
|
-
"nvarchar",
|
|
188
|
-
"binary",
|
|
189
|
-
"varbinary"
|
|
190
|
-
];
|
|
191
|
-
static withPrecisionDataTypes = [
|
|
192
|
-
"decimal",
|
|
193
|
-
"dec",
|
|
194
|
-
"numeric",
|
|
195
|
-
"fixed",
|
|
196
|
-
"float",
|
|
197
|
-
"double",
|
|
198
|
-
"double precision",
|
|
199
|
-
"real",
|
|
200
|
-
"time",
|
|
201
|
-
"datetime",
|
|
202
|
-
"timestamp"
|
|
203
|
-
];
|
|
204
|
-
static withScaleDataTypes = [
|
|
205
|
-
"decimal",
|
|
206
|
-
"dec",
|
|
207
|
-
"numeric",
|
|
208
|
-
"fixed",
|
|
209
|
-
"float",
|
|
210
|
-
"double",
|
|
211
|
-
"double precision",
|
|
212
|
-
"real"
|
|
213
|
-
];
|
|
214
|
-
static unsignedAndZerofillTypes = [
|
|
215
|
-
"int",
|
|
216
|
-
"integer",
|
|
217
|
-
"smallint",
|
|
218
|
-
"tinyint",
|
|
219
|
-
"mediumint",
|
|
220
|
-
"bigint",
|
|
221
|
-
"decimal",
|
|
222
|
-
"dec",
|
|
223
|
-
"numeric",
|
|
224
|
-
"fixed",
|
|
225
|
-
"float",
|
|
226
|
-
"double",
|
|
227
|
-
"double precision",
|
|
228
|
-
"real"
|
|
229
|
-
];
|
|
230
|
-
static withWidthDataTypes = [
|
|
231
|
-
'int',
|
|
232
|
-
];
|
|
233
|
-
static dataTypeDefaults = {
|
|
234
|
-
"varchar": { length: 255 },
|
|
235
|
-
"nvarchar": { length: 255 },
|
|
236
|
-
"national varchar": { length: 255 },
|
|
237
|
-
"char": { length: 1 },
|
|
238
|
-
"binary": { length: 1 },
|
|
239
|
-
"varbinary": { length: 255 },
|
|
240
|
-
"decimal": { precision: 10, scale: 0 },
|
|
241
|
-
"dec": { precision: 10, scale: 0 },
|
|
242
|
-
"numeric": { precision: 10, scale: 0 },
|
|
243
|
-
"fixed": { precision: 10, scale: 0 },
|
|
244
|
-
"float": { precision: 12 },
|
|
245
|
-
"double": { precision: 22 },
|
|
246
|
-
"time": { precision: 0 },
|
|
247
|
-
"datetime": { precision: 0 },
|
|
248
|
-
"timestamp": { precision: 0 },
|
|
249
|
-
"bit": { width: 1 },
|
|
250
|
-
"int": { width: 11 },
|
|
251
|
-
"integer": { width: 11 },
|
|
252
|
-
"tinyint": { width: 4 },
|
|
253
|
-
"smallint": { width: 6 },
|
|
254
|
-
"mediumint": { width: 9 },
|
|
255
|
-
"bigint": { width: 20 }
|
|
256
|
-
};
|
|
257
|
-
maxAliasLength = 63;
|
|
258
|
-
populateDataTypeDef(type, params, enumeration) {
|
|
259
|
-
if (['date', 'datetime', 'time', 'sequence'].includes(type)) {
|
|
260
|
-
return 'bigint ';
|
|
261
|
-
}
|
|
262
|
-
if (['object', 'array'].includes(type)) {
|
|
263
|
-
return 'json ';
|
|
264
|
-
}
|
|
265
|
-
if (['image', 'function'].includes(type)) {
|
|
266
|
-
return 'text ';
|
|
267
|
-
}
|
|
268
|
-
if (type === 'ref') {
|
|
269
|
-
return 'char(36)';
|
|
270
|
-
}
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return
|
|
277
|
-
}
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const { length } =
|
|
285
|
-
return `${type}(${length}) `;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
stmt2 += `(${alias}.${attr} = '${o}')`;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
stmt
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
stmt
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
case '
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
let
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
sql += '
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
sql +=
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MySqlTranslator = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const lodash_1 = require("lodash");
|
|
8
|
+
const types_1 = require("oak-domain/lib/types");
|
|
9
|
+
const sqlTranslator_1 = require("../sqlTranslator");
|
|
10
|
+
const GeoTypes = [
|
|
11
|
+
{
|
|
12
|
+
type: 'point',
|
|
13
|
+
name: "Point"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: 'path',
|
|
17
|
+
name: "LineString",
|
|
18
|
+
element: 'point',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "MultiLineString",
|
|
22
|
+
element: "path",
|
|
23
|
+
multiple: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: 'polygon',
|
|
27
|
+
name: "Polygon",
|
|
28
|
+
element: "path"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "MultiPoint",
|
|
32
|
+
element: "point",
|
|
33
|
+
multiple: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "MultiPolygon",
|
|
37
|
+
element: "polygon",
|
|
38
|
+
multiple: true,
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
function transformGeoData(data) {
|
|
42
|
+
if (data instanceof Array) {
|
|
43
|
+
const element = data[0];
|
|
44
|
+
if (element instanceof Array) {
|
|
45
|
+
return ` GeometryCollection(${data.map(ele => transformGeoData(ele)).join(',')})`;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const geoType = GeoTypes.find(ele => ele.type === element.type);
|
|
49
|
+
if (!geoType) {
|
|
50
|
+
throw new Error(`${element.type} is not supported in MySQL`);
|
|
51
|
+
}
|
|
52
|
+
const multiGeoType = GeoTypes.find(ele => ele.element === geoType.type && ele.multiple);
|
|
53
|
+
return ` ${multiGeoType.name}(${data.map(ele => transformGeoData(ele)).join(',')})`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const { type, coordinate } = data;
|
|
58
|
+
const geoType = GeoTypes.find(ele => ele.type === type);
|
|
59
|
+
if (!geoType) {
|
|
60
|
+
throw new Error(`${data.type} is not supported in MySQL`);
|
|
61
|
+
}
|
|
62
|
+
const { element, name } = geoType;
|
|
63
|
+
if (!element) {
|
|
64
|
+
// Point
|
|
65
|
+
return ` ${name}(${coordinate.join(',')})`;
|
|
66
|
+
}
|
|
67
|
+
// Polygon or Linestring
|
|
68
|
+
return ` ${name}(${coordinate.map((ele) => transformGeoData({
|
|
69
|
+
type: element,
|
|
70
|
+
coordinate: ele,
|
|
71
|
+
}))})`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
75
|
+
getDefaultSelectFilter(alias, option) {
|
|
76
|
+
if (option?.includedDeleted) {
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
return ` (\`${alias}\`.\`$$deleteAt$$\` is null)`;
|
|
80
|
+
}
|
|
81
|
+
makeUpSchema() {
|
|
82
|
+
for (const entity in this.schema) {
|
|
83
|
+
const { attributes, indexes } = this.schema[entity];
|
|
84
|
+
const geoIndexes = [];
|
|
85
|
+
for (const attr in attributes) {
|
|
86
|
+
if (attributes[attr].type === 'geometry') {
|
|
87
|
+
const geoIndex = indexes?.find((idx) => idx.config?.type === 'spatial' && idx.attributes.find((attrDef) => attrDef.name === attr));
|
|
88
|
+
if (!geoIndex) {
|
|
89
|
+
geoIndexes.push({
|
|
90
|
+
name: `${entity}_geo_${attr}`,
|
|
91
|
+
attributes: [{
|
|
92
|
+
name: attr,
|
|
93
|
+
}],
|
|
94
|
+
config: {
|
|
95
|
+
type: 'spatial',
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (geoIndexes.length > 0) {
|
|
102
|
+
if (indexes) {
|
|
103
|
+
indexes.push(...geoIndexes);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
(0, lodash_1.assign)(this.schema[entity], {
|
|
107
|
+
indexes: geoIndexes,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
constructor(schema) {
|
|
114
|
+
super(schema);
|
|
115
|
+
// MySQL为geometry属性默认创建索引
|
|
116
|
+
this.makeUpSchema();
|
|
117
|
+
}
|
|
118
|
+
static supportedDataTypes = [
|
|
119
|
+
// numeric types
|
|
120
|
+
"bit",
|
|
121
|
+
"int",
|
|
122
|
+
"integer", // synonym for int
|
|
123
|
+
"tinyint",
|
|
124
|
+
"smallint",
|
|
125
|
+
"mediumint",
|
|
126
|
+
"bigint",
|
|
127
|
+
"float",
|
|
128
|
+
"double",
|
|
129
|
+
"double precision", // synonym for double
|
|
130
|
+
"real", // synonym for double
|
|
131
|
+
"decimal",
|
|
132
|
+
"dec", // synonym for decimal
|
|
133
|
+
"numeric", // synonym for decimal
|
|
134
|
+
"fixed", // synonym for decimal
|
|
135
|
+
"bool", // synonym for tinyint
|
|
136
|
+
"boolean", // synonym for tinyint
|
|
137
|
+
// date and time types
|
|
138
|
+
"date",
|
|
139
|
+
"datetime",
|
|
140
|
+
"timestamp",
|
|
141
|
+
"time",
|
|
142
|
+
"year",
|
|
143
|
+
// string types
|
|
144
|
+
"char",
|
|
145
|
+
"nchar", // synonym for national char
|
|
146
|
+
"national char",
|
|
147
|
+
"varchar",
|
|
148
|
+
"nvarchar", // synonym for national varchar
|
|
149
|
+
"national varchar",
|
|
150
|
+
"blob",
|
|
151
|
+
"text",
|
|
152
|
+
"tinyblob",
|
|
153
|
+
"tinytext",
|
|
154
|
+
"mediumblob",
|
|
155
|
+
"mediumtext",
|
|
156
|
+
"longblob",
|
|
157
|
+
"longtext",
|
|
158
|
+
"enum",
|
|
159
|
+
"set",
|
|
160
|
+
"binary",
|
|
161
|
+
"varbinary",
|
|
162
|
+
// json data type
|
|
163
|
+
"json",
|
|
164
|
+
// spatial data types
|
|
165
|
+
"geometry",
|
|
166
|
+
"point",
|
|
167
|
+
"linestring",
|
|
168
|
+
"polygon",
|
|
169
|
+
"multipoint",
|
|
170
|
+
"multilinestring",
|
|
171
|
+
"multipolygon",
|
|
172
|
+
"geometrycollection"
|
|
173
|
+
];
|
|
174
|
+
static spatialTypes = [
|
|
175
|
+
"geometry",
|
|
176
|
+
"point",
|
|
177
|
+
"linestring",
|
|
178
|
+
"polygon",
|
|
179
|
+
"multipoint",
|
|
180
|
+
"multilinestring",
|
|
181
|
+
"multipolygon",
|
|
182
|
+
"geometrycollection"
|
|
183
|
+
];
|
|
184
|
+
static withLengthDataTypes = [
|
|
185
|
+
"char",
|
|
186
|
+
"varchar",
|
|
187
|
+
"nvarchar",
|
|
188
|
+
"binary",
|
|
189
|
+
"varbinary"
|
|
190
|
+
];
|
|
191
|
+
static withPrecisionDataTypes = [
|
|
192
|
+
"decimal",
|
|
193
|
+
"dec",
|
|
194
|
+
"numeric",
|
|
195
|
+
"fixed",
|
|
196
|
+
"float",
|
|
197
|
+
"double",
|
|
198
|
+
"double precision",
|
|
199
|
+
"real",
|
|
200
|
+
"time",
|
|
201
|
+
"datetime",
|
|
202
|
+
"timestamp"
|
|
203
|
+
];
|
|
204
|
+
static withScaleDataTypes = [
|
|
205
|
+
"decimal",
|
|
206
|
+
"dec",
|
|
207
|
+
"numeric",
|
|
208
|
+
"fixed",
|
|
209
|
+
"float",
|
|
210
|
+
"double",
|
|
211
|
+
"double precision",
|
|
212
|
+
"real"
|
|
213
|
+
];
|
|
214
|
+
static unsignedAndZerofillTypes = [
|
|
215
|
+
"int",
|
|
216
|
+
"integer",
|
|
217
|
+
"smallint",
|
|
218
|
+
"tinyint",
|
|
219
|
+
"mediumint",
|
|
220
|
+
"bigint",
|
|
221
|
+
"decimal",
|
|
222
|
+
"dec",
|
|
223
|
+
"numeric",
|
|
224
|
+
"fixed",
|
|
225
|
+
"float",
|
|
226
|
+
"double",
|
|
227
|
+
"double precision",
|
|
228
|
+
"real"
|
|
229
|
+
];
|
|
230
|
+
static withWidthDataTypes = [
|
|
231
|
+
'int',
|
|
232
|
+
];
|
|
233
|
+
static dataTypeDefaults = {
|
|
234
|
+
"varchar": { length: 255 },
|
|
235
|
+
"nvarchar": { length: 255 },
|
|
236
|
+
"national varchar": { length: 255 },
|
|
237
|
+
"char": { length: 1 },
|
|
238
|
+
"binary": { length: 1 },
|
|
239
|
+
"varbinary": { length: 255 },
|
|
240
|
+
"decimal": { precision: 10, scale: 0 },
|
|
241
|
+
"dec": { precision: 10, scale: 0 },
|
|
242
|
+
"numeric": { precision: 10, scale: 0 },
|
|
243
|
+
"fixed": { precision: 10, scale: 0 },
|
|
244
|
+
"float": { precision: 12 },
|
|
245
|
+
"double": { precision: 22 },
|
|
246
|
+
"time": { precision: 0 },
|
|
247
|
+
"datetime": { precision: 0 },
|
|
248
|
+
"timestamp": { precision: 0 },
|
|
249
|
+
"bit": { width: 1 },
|
|
250
|
+
"int": { width: 11 },
|
|
251
|
+
"integer": { width: 11 },
|
|
252
|
+
"tinyint": { width: 4 },
|
|
253
|
+
"smallint": { width: 6 },
|
|
254
|
+
"mediumint": { width: 9 },
|
|
255
|
+
"bigint": { width: 20 }
|
|
256
|
+
};
|
|
257
|
+
maxAliasLength = 63;
|
|
258
|
+
populateDataTypeDef(type, params, enumeration) {
|
|
259
|
+
if (['date', 'datetime', 'time', 'sequence'].includes(type)) {
|
|
260
|
+
return 'bigint ';
|
|
261
|
+
}
|
|
262
|
+
if (['object', 'array'].includes(type)) {
|
|
263
|
+
return 'json ';
|
|
264
|
+
}
|
|
265
|
+
if (['image', 'function'].includes(type)) {
|
|
266
|
+
return 'text ';
|
|
267
|
+
}
|
|
268
|
+
if (type === 'ref') {
|
|
269
|
+
return 'char(36) ';
|
|
270
|
+
}
|
|
271
|
+
if (['bool', 'boolean'].includes(type)) {
|
|
272
|
+
// MySQL读出来就是tinyint(1)
|
|
273
|
+
return 'tinyint(1) ';
|
|
274
|
+
}
|
|
275
|
+
if (type === 'money') {
|
|
276
|
+
return 'bigint ';
|
|
277
|
+
}
|
|
278
|
+
if (type === 'enum') {
|
|
279
|
+
(0, assert_1.default)(enumeration);
|
|
280
|
+
return `enum(${enumeration.map(ele => `'${ele}'`).join(',')}) `;
|
|
281
|
+
}
|
|
282
|
+
if (MySqlTranslator.withLengthDataTypes.includes(type)) {
|
|
283
|
+
if (params) {
|
|
284
|
+
const { length } = params;
|
|
285
|
+
return `${type}(${length}) `;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
const { length } = MySqlTranslator.dataTypeDefaults[type];
|
|
289
|
+
return `${type}(${length}) `;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (MySqlTranslator.withPrecisionDataTypes.includes(type)) {
|
|
293
|
+
if (params) {
|
|
294
|
+
const { precision, scale } = params;
|
|
295
|
+
if (typeof scale === 'number') {
|
|
296
|
+
return `${type}(${precision}, ${scale}) `;
|
|
297
|
+
}
|
|
298
|
+
return `${type}(${precision}) `;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
const { precision, scale } = MySqlTranslator.dataTypeDefaults[type];
|
|
302
|
+
if (typeof scale === 'number') {
|
|
303
|
+
return `${type}(${precision}, ${scale}) `;
|
|
304
|
+
}
|
|
305
|
+
return `${type}(${precision}) `;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (MySqlTranslator.withWidthDataTypes.includes(type)) {
|
|
309
|
+
(0, assert_1.default)(type === 'int');
|
|
310
|
+
const { width } = params || { width: 4 };
|
|
311
|
+
switch (width) {
|
|
312
|
+
case 1: {
|
|
313
|
+
return 'tinyint ';
|
|
314
|
+
}
|
|
315
|
+
case 2: {
|
|
316
|
+
return 'smallint ';
|
|
317
|
+
}
|
|
318
|
+
case 3: {
|
|
319
|
+
return 'mediumint ';
|
|
320
|
+
}
|
|
321
|
+
case 4: {
|
|
322
|
+
return 'int ';
|
|
323
|
+
}
|
|
324
|
+
default: {
|
|
325
|
+
return 'bigint ';
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return `${type} `;
|
|
330
|
+
}
|
|
331
|
+
translateAttrProjection(dataType, alias, attr) {
|
|
332
|
+
switch (dataType) {
|
|
333
|
+
case 'geometry': {
|
|
334
|
+
return ` st_astext(\`${alias}\`.\`${attr}\`)`;
|
|
335
|
+
}
|
|
336
|
+
default: {
|
|
337
|
+
return ` \`${alias}\`.\`${attr}\``;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
translateObjectPredicate(predicate, alias, attr) {
|
|
342
|
+
const translateInner = (o, p) => {
|
|
343
|
+
let stmt2 = '';
|
|
344
|
+
if (o instanceof Array) {
|
|
345
|
+
o.forEach((ele, idx) => {
|
|
346
|
+
if (ele !== undefined && ele !== null) {
|
|
347
|
+
const part = translateInner(ele, `${p}[${idx}]`);
|
|
348
|
+
if (stmt2) {
|
|
349
|
+
stmt2 += ' and ';
|
|
350
|
+
}
|
|
351
|
+
stmt2 += `${part}`;
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
else if (typeof o === 'object') {
|
|
356
|
+
for (const attr2 in o) {
|
|
357
|
+
if (attr2 === '$and') {
|
|
358
|
+
o[attr2].forEach((ele) => {
|
|
359
|
+
const part = translateInner(ele, p);
|
|
360
|
+
if (stmt2) {
|
|
361
|
+
stmt2 += ' and ';
|
|
362
|
+
}
|
|
363
|
+
stmt2 += `${part}`;
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
else if (attr2 === '$or') {
|
|
367
|
+
let stmtOr = '';
|
|
368
|
+
o[attr2].forEach((ele) => {
|
|
369
|
+
const part = translateInner(ele, p);
|
|
370
|
+
if (stmtOr) {
|
|
371
|
+
stmtOr += ' or ';
|
|
372
|
+
}
|
|
373
|
+
stmtOr += `${part}`;
|
|
374
|
+
});
|
|
375
|
+
if (stmt2) {
|
|
376
|
+
stmt2 += ' and ';
|
|
377
|
+
}
|
|
378
|
+
stmt2 += `(${stmtOr})`;
|
|
379
|
+
}
|
|
380
|
+
else if (attr2 === '$contains') {
|
|
381
|
+
// json_contains,多值的包含关系
|
|
382
|
+
const value = JSON.stringify(o[attr2]);
|
|
383
|
+
if (stmt2) {
|
|
384
|
+
stmt2 += ' and ';
|
|
385
|
+
}
|
|
386
|
+
if (p) {
|
|
387
|
+
stmt2 += `(JSON_CONTAINS(${alias}.${attr}->>"$${p}", CAST('${value}' AS JSON)))`;
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
stmt2 += `(JSON_CONTAINS(${alias}.${attr}, CAST('${value}' AS JSON)))`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else if (attr2 === '$overlaps') {
|
|
394
|
+
// json_overlaps,多值的交叉关系
|
|
395
|
+
const value = JSON.stringify(o[attr2]);
|
|
396
|
+
if (stmt2) {
|
|
397
|
+
stmt2 += ' and ';
|
|
398
|
+
}
|
|
399
|
+
if (p) {
|
|
400
|
+
stmt2 += `(JSON_OVERLAPS(${alias}.${attr}->>"$${p}", CAST('${value}' AS JSON)))`;
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
stmt2 += `(JSON_OVERLAPS(${alias}.${attr}, CAST('${value}' AS JSON)))`;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else if (attr2 === '$length') {
|
|
407
|
+
// json length
|
|
408
|
+
const length = o[attr2];
|
|
409
|
+
if (stmt2) {
|
|
410
|
+
stmt2 += ' and ';
|
|
411
|
+
}
|
|
412
|
+
if (typeof length === 'number') {
|
|
413
|
+
if (p) {
|
|
414
|
+
stmt2 += `(JSON_LENGTH(${alias}.${attr}->>"$${p}") = ${length})`;
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
stmt2 += `(JSON_LENGTH(${alias}.${attr}) = ${length})`;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
(0, assert_1.default)(typeof length === 'object');
|
|
422
|
+
const op = Object.keys(length)[0];
|
|
423
|
+
(0, assert_1.default)(op.startsWith('$'));
|
|
424
|
+
if (p) {
|
|
425
|
+
stmt2 += `(JSON_LENGTH(${alias}.${attr}->>"$${p}") ${this.translatePredicate(op, length[op])})`;
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
stmt2 += `(JSON_LENGTH(${alias}.${attr}) ${this.translatePredicate(op, length[op])})`;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
else if (attr2.startsWith('$')) {
|
|
433
|
+
if (stmt2) {
|
|
434
|
+
stmt2 += ' and ';
|
|
435
|
+
}
|
|
436
|
+
if (p) {
|
|
437
|
+
stmt2 += `(${alias}.${attr}->>"$${p}" ${this.translatePredicate(attr2, o[attr2])})`;
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
stmt2 += `(${alias}.${attr} ${this.translatePredicate(attr2, o[attr2])})`;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// 继续子对象解构
|
|
445
|
+
const attr3 = attr2.startsWith('.') ? attr2.slice(1) : attr2;
|
|
446
|
+
const part = translateInner(o[attr2], `${p}.${attr3}`);
|
|
447
|
+
if (stmt2) {
|
|
448
|
+
stmt2 += ' and ';
|
|
449
|
+
}
|
|
450
|
+
stmt2 += `${part}`;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
// 直接的属性处理
|
|
456
|
+
if (stmt2) {
|
|
457
|
+
stmt2 += ' and ';
|
|
458
|
+
}
|
|
459
|
+
if (typeof o === 'string') {
|
|
460
|
+
if (p) {
|
|
461
|
+
stmt2 += `(${alias}.${attr}->>"$${p}" = '${o}')`;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
// 对根对象的字符串比较
|
|
465
|
+
stmt2 += `(${alias}.${attr} = '${o}')`;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
(0, assert_1.default)(p);
|
|
470
|
+
stmt2 += `(${alias}.${attr}->>"$${p}" = ${o})`;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return stmt2;
|
|
474
|
+
};
|
|
475
|
+
return translateInner(predicate, '');
|
|
476
|
+
}
|
|
477
|
+
translateObjectProjection(projection, alias, attr, prefix) {
|
|
478
|
+
let stmt = '';
|
|
479
|
+
const translateInner = (o, p) => {
|
|
480
|
+
if (o instanceof Array) {
|
|
481
|
+
o.forEach((item, idx) => {
|
|
482
|
+
const p2 = `${p}[${idx}]`;
|
|
483
|
+
if (typeof item === 'number') {
|
|
484
|
+
if (stmt) {
|
|
485
|
+
stmt += ', ';
|
|
486
|
+
}
|
|
487
|
+
stmt += `${alias}.${attr}->>"$${p2}"`;
|
|
488
|
+
stmt += prefix ? ` as \`${prefix}.${attr}${p2}\`` : ` as \`${attr}${p2}\``;
|
|
489
|
+
}
|
|
490
|
+
else if (typeof item === 'object') {
|
|
491
|
+
translateInner(item, p2);
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
for (const key in o) {
|
|
497
|
+
const p2 = `${p}.${key}`;
|
|
498
|
+
if (typeof o[key] === 'number') {
|
|
499
|
+
if (stmt) {
|
|
500
|
+
stmt += ', ';
|
|
501
|
+
}
|
|
502
|
+
stmt += `${alias}.${attr}->>"$${p2}"`;
|
|
503
|
+
stmt += prefix ? ` as \`${prefix}.${attr}${p2}\`` : ` as \`${attr}${p2}\``;
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
translateInner(o[key], p2);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
translateInner(projection, '');
|
|
512
|
+
return stmt;
|
|
513
|
+
}
|
|
514
|
+
translateAttrValue(dataType, value) {
|
|
515
|
+
if (value === null || value === undefined) {
|
|
516
|
+
return 'null';
|
|
517
|
+
}
|
|
518
|
+
switch (dataType) {
|
|
519
|
+
case 'geometry': {
|
|
520
|
+
return transformGeoData(value);
|
|
521
|
+
}
|
|
522
|
+
case 'datetime':
|
|
523
|
+
case 'time':
|
|
524
|
+
case 'date': {
|
|
525
|
+
if (value instanceof Date) {
|
|
526
|
+
return `${value.valueOf()}`;
|
|
527
|
+
}
|
|
528
|
+
else if (typeof value === 'number') {
|
|
529
|
+
return `${value}`;
|
|
530
|
+
}
|
|
531
|
+
return `'${(new Date(value)).valueOf()}'`;
|
|
532
|
+
}
|
|
533
|
+
case 'object':
|
|
534
|
+
case 'array': {
|
|
535
|
+
return this.escapeStringValue(JSON.stringify(value));
|
|
536
|
+
}
|
|
537
|
+
/* case 'function': {
|
|
538
|
+
return `'${Buffer.from(value.toString()).toString('base64')}'`;
|
|
539
|
+
} */
|
|
540
|
+
default: {
|
|
541
|
+
if (typeof value === 'string') {
|
|
542
|
+
return this.escapeStringValue(value);
|
|
543
|
+
}
|
|
544
|
+
return value;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
translateFullTextSearch(value, entity, alias) {
|
|
549
|
+
const { $search } = value;
|
|
550
|
+
const { indexes } = this.schema[entity];
|
|
551
|
+
const ftIndex = indexes && indexes.find((ele) => {
|
|
552
|
+
const { config } = ele;
|
|
553
|
+
return config && config.type === 'fulltext';
|
|
554
|
+
});
|
|
555
|
+
(0, assert_1.default)(ftIndex);
|
|
556
|
+
const { attributes } = ftIndex;
|
|
557
|
+
const columns2 = attributes.map(({ name }) => `${alias}.${name}`);
|
|
558
|
+
return ` match(${columns2.join(',')}) against ('${$search}' in natural language mode)`;
|
|
559
|
+
}
|
|
560
|
+
translateAttributeDef(attr, attrDef) {
|
|
561
|
+
let sql = `\`${attr}\` `;
|
|
562
|
+
const { type, params, default: defaultValue, unique, notNull, sequenceStart, enumeration, } = attrDef;
|
|
563
|
+
sql += this.populateDataTypeDef(type, params, enumeration);
|
|
564
|
+
if (notNull || type === 'geometry') {
|
|
565
|
+
sql += ' not null ';
|
|
566
|
+
}
|
|
567
|
+
if (unique) {
|
|
568
|
+
sql += ' unique ';
|
|
569
|
+
}
|
|
570
|
+
if (typeof sequenceStart === 'number') {
|
|
571
|
+
sql += ' auto_increment unique ';
|
|
572
|
+
}
|
|
573
|
+
if (defaultValue !== undefined) {
|
|
574
|
+
(0, assert_1.default)(type !== 'ref');
|
|
575
|
+
sql += ` default ${this.translateAttrValue(type, defaultValue)}`;
|
|
576
|
+
}
|
|
577
|
+
if (attr === types_1.PrimaryKeyAttribute) {
|
|
578
|
+
sql += ' primary key';
|
|
579
|
+
}
|
|
580
|
+
return sql;
|
|
581
|
+
}
|
|
582
|
+
translateCreateEntity(entity, options) {
|
|
583
|
+
const ifExists = options?.ifExists || 'drop';
|
|
584
|
+
const { schema } = this;
|
|
585
|
+
const entityDef = schema[entity];
|
|
586
|
+
const { storageName, attributes, indexes, view, static: _static } = entityDef;
|
|
587
|
+
let hasSequence = false;
|
|
588
|
+
// todo view暂还不支持
|
|
589
|
+
const entityType = view ? 'view' : 'table';
|
|
590
|
+
let sql = `create ${entityType} `;
|
|
591
|
+
if (ifExists === 'omit' || (_static && ifExists === 'dropIfNotStatic')) {
|
|
592
|
+
sql += ' if not exists';
|
|
593
|
+
}
|
|
594
|
+
if (storageName) {
|
|
595
|
+
sql += `\`${storageName}\` `;
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
sql += `\`${entity}\` `;
|
|
599
|
+
}
|
|
600
|
+
if (view) {
|
|
601
|
+
throw new Error(' view unsupported yet');
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
sql += '(';
|
|
605
|
+
// 翻译所有的属性
|
|
606
|
+
Object.keys(attributes).forEach((attr, idx) => {
|
|
607
|
+
const attrSql = this.translateAttributeDef(attr, attributes[attr]);
|
|
608
|
+
if (idx !== 0) {
|
|
609
|
+
sql += ', ';
|
|
610
|
+
}
|
|
611
|
+
sql += attrSql;
|
|
612
|
+
if (typeof attributes[attr].sequenceStart === 'number') {
|
|
613
|
+
(0, assert_1.default)(hasSequence === false, 'Entity can only have one auto increment attribute.');
|
|
614
|
+
hasSequence = attributes[attr].sequenceStart;
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
// 翻译索引信息
|
|
618
|
+
if (indexes) {
|
|
619
|
+
sql += ',\n';
|
|
620
|
+
indexes.forEach(({ name, attributes, config }, idx) => {
|
|
621
|
+
const { unique, type, parser } = config || {};
|
|
622
|
+
// 因为有deleteAt的存在,这里的unique没意义,只能框架自己去建立checker来处理
|
|
623
|
+
/* if (unique) {
|
|
624
|
+
sql += ' unique ';
|
|
625
|
+
}
|
|
626
|
+
else */ if (type === 'fulltext') {
|
|
627
|
+
sql += ' fulltext ';
|
|
628
|
+
}
|
|
629
|
+
else if (type === 'spatial') {
|
|
630
|
+
sql += ' spatial ';
|
|
631
|
+
}
|
|
632
|
+
sql += `index \`${name}\` `;
|
|
633
|
+
if (type === 'hash') {
|
|
634
|
+
sql += ` using hash `;
|
|
635
|
+
}
|
|
636
|
+
sql += '(';
|
|
637
|
+
attributes.forEach(({ name, size, direction }, idx2) => {
|
|
638
|
+
sql += `\`${name}\``;
|
|
639
|
+
if (size) {
|
|
640
|
+
sql += ` (${size})`;
|
|
641
|
+
}
|
|
642
|
+
if (direction) {
|
|
643
|
+
sql += ` ${direction}`;
|
|
644
|
+
}
|
|
645
|
+
if (idx2 < attributes.length - 1) {
|
|
646
|
+
sql += ', ';
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
sql += ')';
|
|
650
|
+
if (parser) {
|
|
651
|
+
sql += ` with parser ${parser}`;
|
|
652
|
+
}
|
|
653
|
+
if (idx < indexes.length - 1) {
|
|
654
|
+
sql += ',\n';
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
sql += ')';
|
|
660
|
+
if (typeof hasSequence === 'number') {
|
|
661
|
+
sql += `auto_increment = ${hasSequence}`;
|
|
662
|
+
}
|
|
663
|
+
if (ifExists === 'drop' || (!_static && ifExists === 'dropIfNotStatic')) {
|
|
664
|
+
return [`drop ${entityType} if exists \`${storageName || entity}\`;`, sql];
|
|
665
|
+
}
|
|
666
|
+
return [sql];
|
|
667
|
+
}
|
|
668
|
+
translateFnName(fnName, argumentNumber) {
|
|
669
|
+
switch (fnName) {
|
|
670
|
+
case '$add': {
|
|
671
|
+
let result = '%s';
|
|
672
|
+
while (--argumentNumber > 0) {
|
|
673
|
+
result += ' + %s';
|
|
674
|
+
}
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
case '$subtract': {
|
|
678
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
679
|
+
return '%s - %s';
|
|
680
|
+
}
|
|
681
|
+
case '$multiply': {
|
|
682
|
+
let result = '%s';
|
|
683
|
+
while (--argumentNumber > 0) {
|
|
684
|
+
result += ' * %s';
|
|
685
|
+
}
|
|
686
|
+
return result;
|
|
687
|
+
}
|
|
688
|
+
case '$divide': {
|
|
689
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
690
|
+
return '%s / %s';
|
|
691
|
+
}
|
|
692
|
+
case '$abs': {
|
|
693
|
+
return 'ABS(%s)';
|
|
694
|
+
}
|
|
695
|
+
case '$round': {
|
|
696
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
697
|
+
return 'ROUND(%s, %s)';
|
|
698
|
+
}
|
|
699
|
+
case '$ceil': {
|
|
700
|
+
return 'CEIL(%s)';
|
|
701
|
+
}
|
|
702
|
+
case '$floor': {
|
|
703
|
+
return 'FLOOR(%s)';
|
|
704
|
+
}
|
|
705
|
+
case '$mod': {
|
|
706
|
+
return 'MOD(%s, %s)';
|
|
707
|
+
}
|
|
708
|
+
case '$pow': {
|
|
709
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
710
|
+
return 'POW(%s, %s)';
|
|
711
|
+
}
|
|
712
|
+
case '$gt': {
|
|
713
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
714
|
+
return '%s > %s';
|
|
715
|
+
}
|
|
716
|
+
case '$gte': {
|
|
717
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
718
|
+
return '%s >= %s';
|
|
719
|
+
}
|
|
720
|
+
case '$lt': {
|
|
721
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
722
|
+
return '%s < %s';
|
|
723
|
+
}
|
|
724
|
+
case '$lte': {
|
|
725
|
+
return '%s <= %s';
|
|
726
|
+
}
|
|
727
|
+
case '$eq': {
|
|
728
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
729
|
+
return '%s = %s';
|
|
730
|
+
}
|
|
731
|
+
case '$ne': {
|
|
732
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
733
|
+
return '%s <> %s';
|
|
734
|
+
}
|
|
735
|
+
case '$startsWith': {
|
|
736
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
737
|
+
return '%s like CONCAT(%s, \'%\')';
|
|
738
|
+
}
|
|
739
|
+
case '$endsWith': {
|
|
740
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
741
|
+
return '%s like CONCAT(\'%\', %s)';
|
|
742
|
+
}
|
|
743
|
+
case '$includes': {
|
|
744
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
745
|
+
return '%s like CONCAT(\'%\', %s, \'%\')';
|
|
746
|
+
}
|
|
747
|
+
case '$true': {
|
|
748
|
+
return '%s = true';
|
|
749
|
+
}
|
|
750
|
+
case '$false': {
|
|
751
|
+
return '%s = false';
|
|
752
|
+
}
|
|
753
|
+
case '$and': {
|
|
754
|
+
let result = '';
|
|
755
|
+
for (let iter = 0; iter < argumentNumber; iter++) {
|
|
756
|
+
result += '%s';
|
|
757
|
+
if (iter < argumentNumber - 1) {
|
|
758
|
+
result += ' and ';
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return result;
|
|
762
|
+
}
|
|
763
|
+
case '$or': {
|
|
764
|
+
let result = '';
|
|
765
|
+
for (let iter = 0; iter < argumentNumber; iter++) {
|
|
766
|
+
result += '%s';
|
|
767
|
+
if (iter < argumentNumber - 1) {
|
|
768
|
+
result += ' or ';
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return result;
|
|
772
|
+
}
|
|
773
|
+
case '$not': {
|
|
774
|
+
return 'not %s';
|
|
775
|
+
}
|
|
776
|
+
case '$year': {
|
|
777
|
+
return 'YEAR(%s)';
|
|
778
|
+
}
|
|
779
|
+
case '$month': {
|
|
780
|
+
return 'MONTH(%s)';
|
|
781
|
+
}
|
|
782
|
+
case '$weekday': {
|
|
783
|
+
return 'WEEKDAY(%s)';
|
|
784
|
+
}
|
|
785
|
+
case '$weekOfYear': {
|
|
786
|
+
return 'WEEKOFYEAR(%s)';
|
|
787
|
+
}
|
|
788
|
+
case '$day': {
|
|
789
|
+
return 'DAY(%s)';
|
|
790
|
+
}
|
|
791
|
+
case '$dayOfMonth': {
|
|
792
|
+
return 'DAYOFMONTH(%s)';
|
|
793
|
+
}
|
|
794
|
+
case '$dayOfWeek': {
|
|
795
|
+
return 'DAYOFWEEK(%s)';
|
|
796
|
+
}
|
|
797
|
+
case '$dayOfYear': {
|
|
798
|
+
return 'DAYOFYEAR(%s)';
|
|
799
|
+
}
|
|
800
|
+
// 这个实现有问题,DATEDIFF只是计算两个日期之间的天数差,只接受两个参数,放在translateExperession里实现
|
|
801
|
+
// case '$dateDiff': {
|
|
802
|
+
// assert(argumentNumber === 3);
|
|
803
|
+
// return 'DATEDIFF(%s, %s, %s)';
|
|
804
|
+
// }
|
|
805
|
+
case '$contains': {
|
|
806
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
807
|
+
return 'ST_CONTAINS(%s, %s)';
|
|
808
|
+
}
|
|
809
|
+
case '$distance': {
|
|
810
|
+
(0, assert_1.default)(argumentNumber === 2);
|
|
811
|
+
return 'ST_DISTANCE(%s, %s)';
|
|
812
|
+
}
|
|
813
|
+
case '$concat': {
|
|
814
|
+
let result = ' concat(%s';
|
|
815
|
+
while (--argumentNumber > 0) {
|
|
816
|
+
result += ', %s';
|
|
817
|
+
}
|
|
818
|
+
result += ')';
|
|
819
|
+
return result;
|
|
820
|
+
}
|
|
821
|
+
// ========== 聚合函数 ==========
|
|
822
|
+
case '$$count': {
|
|
823
|
+
return 'COUNT(%s)';
|
|
824
|
+
}
|
|
825
|
+
case '$$sum': {
|
|
826
|
+
return 'SUM(%s)';
|
|
827
|
+
}
|
|
828
|
+
case '$$max': {
|
|
829
|
+
return 'MAX(%s)';
|
|
830
|
+
}
|
|
831
|
+
case '$$min': {
|
|
832
|
+
return 'MIN(%s)';
|
|
833
|
+
}
|
|
834
|
+
case '$$avg': {
|
|
835
|
+
return 'AVG(%s)';
|
|
836
|
+
}
|
|
837
|
+
default: {
|
|
838
|
+
throw new Error(`unrecoganized function ${fnName}`);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
translateAttrInExpression(entity, attr, exprText) {
|
|
843
|
+
const { attributes } = this.schema[entity];
|
|
844
|
+
const { type } = attributes[attr];
|
|
845
|
+
if (['date', 'time', 'datetime'].includes(type)) {
|
|
846
|
+
// 从unix时间戵转成date类型参加expr的运算
|
|
847
|
+
return `from_unixtime(${exprText} / 1000)`;
|
|
848
|
+
}
|
|
849
|
+
return exprText;
|
|
850
|
+
}
|
|
851
|
+
translateExpression(entity, alias, expression, refDict) {
|
|
852
|
+
const translateConstant = (constant) => {
|
|
853
|
+
if (constant instanceof Date) {
|
|
854
|
+
return ` from_unixtime(${constant.valueOf()}/1000)`;
|
|
855
|
+
}
|
|
856
|
+
else if (typeof constant === 'string') {
|
|
857
|
+
return ` '${constant}'`;
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
(0, assert_1.default)(typeof constant === 'number');
|
|
861
|
+
return ` ${constant}`;
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
const translateInner = (expr) => {
|
|
865
|
+
const k = Object.keys(expr);
|
|
866
|
+
let result;
|
|
867
|
+
if (k.includes('#attr')) {
|
|
868
|
+
const attrText = `\`${alias}\`.\`${(expr)['#attr']}\``;
|
|
869
|
+
result = this.translateAttrInExpression(entity, (expr)['#attr'], attrText);
|
|
870
|
+
}
|
|
871
|
+
else if (k.includes('#refId')) {
|
|
872
|
+
const refId = (expr)['#refId'];
|
|
873
|
+
const refAttr = (expr)['#refAttr'];
|
|
874
|
+
(0, assert_1.default)(refDict[refId]);
|
|
875
|
+
const attrText = `\`${refDict[refId][0]}\`.\`${refAttr}\``;
|
|
876
|
+
result = this.translateAttrInExpression(entity, (expr)['#refAttr'], attrText);
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
(0, assert_1.default)(k.length === 1);
|
|
880
|
+
const fnKey = k[0];
|
|
881
|
+
const fnArgs = (expr)[fnKey];
|
|
882
|
+
// 特殊处理日期相关函数
|
|
883
|
+
if (fnKey === '$dateDiff') {
|
|
884
|
+
// $dateDiff: [date1, date2, unit]
|
|
885
|
+
(0, assert_1.default)(fnArgs instanceof Array && fnArgs.length === 3);
|
|
886
|
+
const [date1Expr, date2Expr, unit] = fnArgs;
|
|
887
|
+
// 转换日期表达式
|
|
888
|
+
const translateDateArg = (arg) => {
|
|
889
|
+
if (arg instanceof Date) {
|
|
890
|
+
return `FROM_UNIXTIME(${arg.valueOf()} / 1000)`;
|
|
891
|
+
}
|
|
892
|
+
else if (typeof arg === 'number') {
|
|
893
|
+
return `FROM_UNIXTIME(${arg} / 1000)`;
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
return translateInner(arg);
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
const date1Str = translateDateArg(date1Expr);
|
|
900
|
+
const date2Str = translateDateArg(date2Expr);
|
|
901
|
+
// MySQL TIMESTAMPDIFF 单位映射
|
|
902
|
+
const unitMap = {
|
|
903
|
+
's': 'SECOND',
|
|
904
|
+
'm': 'MINUTE',
|
|
905
|
+
'h': 'HOUR',
|
|
906
|
+
'd': 'DAY',
|
|
907
|
+
'M': 'MONTH',
|
|
908
|
+
'y': 'YEAR'
|
|
909
|
+
};
|
|
910
|
+
const mysqlUnit = unitMap[unit];
|
|
911
|
+
if (!mysqlUnit) {
|
|
912
|
+
throw new Error(`Unsupported date diff unit: ${unit}`);
|
|
913
|
+
}
|
|
914
|
+
// TIMESTAMPDIFF(unit, date1, date2) 返回 date2 - date1
|
|
915
|
+
// 但类型定义是 date1 - date2,所以参数顺序要反过来
|
|
916
|
+
result = `TIMESTAMPDIFF(${mysqlUnit}, ${date2Str}, ${date1Str})`;
|
|
917
|
+
}
|
|
918
|
+
else if (fnKey === '$dateCeil') {
|
|
919
|
+
// $dateCeil: [date, unit]
|
|
920
|
+
(0, assert_1.default)(fnArgs instanceof Array && fnArgs.length === 2);
|
|
921
|
+
const [dateExpr, unit] = fnArgs;
|
|
922
|
+
const getTimestampExpr = (arg) => {
|
|
923
|
+
if (arg instanceof Date) {
|
|
924
|
+
return `${arg.valueOf()}`;
|
|
925
|
+
}
|
|
926
|
+
else if (typeof arg === 'number') {
|
|
927
|
+
return `${arg}`;
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
const k = Object.keys(arg);
|
|
931
|
+
if (k.includes('#attr')) {
|
|
932
|
+
return `\`${alias}\`.\`${arg['#attr']}\``;
|
|
933
|
+
}
|
|
934
|
+
else if (k.includes('#refId')) {
|
|
935
|
+
const refId = arg['#refId'];
|
|
936
|
+
const refAttr = arg['#refAttr'];
|
|
937
|
+
return `\`${refDict[refId][0]}\`.\`${refAttr}\``;
|
|
938
|
+
}
|
|
939
|
+
return translateInner(arg);
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
const tsExpr = getTimestampExpr(dateExpr);
|
|
943
|
+
const msPerUnit = {
|
|
944
|
+
's': 1000,
|
|
945
|
+
'm': 60000,
|
|
946
|
+
'h': 3600000,
|
|
947
|
+
'd': 86400000,
|
|
948
|
+
};
|
|
949
|
+
if (msPerUnit[unit]) {
|
|
950
|
+
// CEIL 向上取整
|
|
951
|
+
result = `CEIL(${tsExpr} / ${msPerUnit[unit]}) * ${msPerUnit[unit]}`;
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
(0, assert_1.default)(typeof unit === 'string', 'unit should be string');
|
|
955
|
+
console.warn('暂不支持 $dateCeil 对月年单位的处理');
|
|
956
|
+
throw new Error(`Unsupported date ceil unit: ${unit}`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
else if (fnKey === '$dateFloor') {
|
|
960
|
+
// $dateFloor: [date, unit]
|
|
961
|
+
(0, assert_1.default)(fnArgs instanceof Array && fnArgs.length === 2);
|
|
962
|
+
const [dateExpr, unit] = fnArgs;
|
|
963
|
+
// 获取毫秒时间戳表达式
|
|
964
|
+
const getTimestampExpr = (arg) => {
|
|
965
|
+
if (arg instanceof Date) {
|
|
966
|
+
return `${arg.valueOf()}`;
|
|
967
|
+
}
|
|
968
|
+
else if (typeof arg === 'number') {
|
|
969
|
+
return `${arg}`;
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
// 属性引用,直接返回属性(存储本身就是毫秒时间戳)
|
|
973
|
+
const k = Object.keys(arg);
|
|
974
|
+
if (k.includes('#attr')) {
|
|
975
|
+
return `\`${alias}\`.\`${arg['#attr']}\``;
|
|
976
|
+
}
|
|
977
|
+
else if (k.includes('#refId')) {
|
|
978
|
+
const refId = arg['#refId'];
|
|
979
|
+
const refAttr = arg['#refAttr'];
|
|
980
|
+
return `\`${refDict[refId][0]}\`.\`${refAttr}\``;
|
|
981
|
+
}
|
|
982
|
+
// 其他表达式递归处理
|
|
983
|
+
return translateInner(arg);
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
const tsExpr = getTimestampExpr(dateExpr);
|
|
987
|
+
// 固定间隔单位:直接用时间戳数学运算
|
|
988
|
+
const msPerUnit = {
|
|
989
|
+
's': 1000,
|
|
990
|
+
'm': 60000,
|
|
991
|
+
'h': 3600000,
|
|
992
|
+
'd': 86400000,
|
|
993
|
+
};
|
|
994
|
+
if (msPerUnit[unit]) {
|
|
995
|
+
// FLOOR(timestamp / interval) * interval
|
|
996
|
+
result = `FLOOR(${tsExpr} / ${msPerUnit[unit]}) * ${msPerUnit[unit]}`;
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
(0, assert_1.default)(typeof unit === 'string', 'unit should be string');
|
|
1000
|
+
console.warn('暂不支持 $dateFloor 对月年单位的处理');
|
|
1001
|
+
throw new Error(`Unsupported date floor unit: ${unit}`);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
else if (fnArgs instanceof Array) {
|
|
1005
|
+
// 原有的数组参数处理逻辑
|
|
1006
|
+
const fnName = this.translateFnName(fnKey, fnArgs.length);
|
|
1007
|
+
const args = [fnName];
|
|
1008
|
+
args.push(...fnArgs.map((ele) => {
|
|
1009
|
+
if (['string', 'number'].includes(typeof ele) || ele instanceof Date) {
|
|
1010
|
+
return translateConstant(ele);
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
return translateInner(ele);
|
|
1014
|
+
}
|
|
1015
|
+
}));
|
|
1016
|
+
result = util_1.format.apply(null, args);
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
// 原有的单参数处理逻辑
|
|
1020
|
+
const fnName = this.translateFnName(fnKey, 1);
|
|
1021
|
+
const args = [fnName];
|
|
1022
|
+
const arg = fnArgs;
|
|
1023
|
+
if (['string', 'number'].includes(typeof arg) || arg instanceof Date) {
|
|
1024
|
+
args.push(translateConstant(arg));
|
|
1025
|
+
}
|
|
1026
|
+
else {
|
|
1027
|
+
args.push(translateInner(arg));
|
|
1028
|
+
}
|
|
1029
|
+
result = util_1.format.apply(null, args);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
return result;
|
|
1033
|
+
};
|
|
1034
|
+
return translateInner(expression);
|
|
1035
|
+
}
|
|
1036
|
+
populateSelectStmt(projectionText, fromText, aliasDict, filterText, sorterText, groupByText, indexFrom, count, option) {
|
|
1037
|
+
// todo hint of use index
|
|
1038
|
+
let sql = `select ${projectionText} from ${fromText}`;
|
|
1039
|
+
if (filterText) {
|
|
1040
|
+
sql += ` where ${filterText}`;
|
|
1041
|
+
}
|
|
1042
|
+
if (sorterText) {
|
|
1043
|
+
sql += ` order by ${sorterText}`;
|
|
1044
|
+
}
|
|
1045
|
+
if (groupByText) {
|
|
1046
|
+
sql += ` group by ${groupByText}`;
|
|
1047
|
+
}
|
|
1048
|
+
if (typeof indexFrom === 'number') {
|
|
1049
|
+
(0, assert_1.default)(typeof count === 'number');
|
|
1050
|
+
sql += ` limit ${indexFrom}, ${count}`;
|
|
1051
|
+
}
|
|
1052
|
+
if (option?.forUpdate) {
|
|
1053
|
+
sql += ' for update';
|
|
1054
|
+
if (typeof option?.forUpdate === 'string') {
|
|
1055
|
+
sql += ` ${option.forUpdate}`;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return sql;
|
|
1059
|
+
}
|
|
1060
|
+
populateUpdateStmt(updateText, fromText, aliasDict, filterText, sorterText, indexFrom, count, option) {
|
|
1061
|
+
// todo using index
|
|
1062
|
+
(0, assert_1.default)(updateText);
|
|
1063
|
+
let sql = `update ${fromText} set ${updateText}`;
|
|
1064
|
+
if (filterText) {
|
|
1065
|
+
sql += ` where ${filterText}`;
|
|
1066
|
+
}
|
|
1067
|
+
if (sorterText) {
|
|
1068
|
+
sql += ` order by ${sorterText}`;
|
|
1069
|
+
}
|
|
1070
|
+
if (typeof indexFrom === 'number') {
|
|
1071
|
+
(0, assert_1.default)(typeof count === 'number');
|
|
1072
|
+
sql += ` limit ${indexFrom}, ${count}`;
|
|
1073
|
+
}
|
|
1074
|
+
return sql;
|
|
1075
|
+
}
|
|
1076
|
+
populateRemoveStmt(updateText, fromText, aliasDict, filterText, sorterText, indexFrom, count, option) {
|
|
1077
|
+
// todo using index
|
|
1078
|
+
const alias = aliasDict['./'];
|
|
1079
|
+
if (option?.deletePhysically) {
|
|
1080
|
+
// assert(!updateText, 'physically delete does not support setting trigger data');
|
|
1081
|
+
let sql = `delete ${alias} from ${fromText} `;
|
|
1082
|
+
if (filterText) {
|
|
1083
|
+
sql += ` where ${filterText}`;
|
|
1084
|
+
}
|
|
1085
|
+
if (sorterText) {
|
|
1086
|
+
sql += ` order by ${sorterText}`;
|
|
1087
|
+
}
|
|
1088
|
+
if (typeof indexFrom === 'number') {
|
|
1089
|
+
(0, assert_1.default)(typeof count === 'number');
|
|
1090
|
+
sql += ` limit ${indexFrom}, ${count}`;
|
|
1091
|
+
}
|
|
1092
|
+
return sql;
|
|
1093
|
+
}
|
|
1094
|
+
// 新的remove应该包含$$deleteAt$$的值了
|
|
1095
|
+
/* const now = Date.now();
|
|
1096
|
+
|
|
1097
|
+
const updateText2 = updateText ? `${updateText}, \`${alias}\`.\`$$deleteAt$$\` = '${now}'` : `\`${alias}\`.\`$$deleteAt$$\` = '${now}'`; */
|
|
1098
|
+
(0, assert_1.default)(updateText.includes(types_1.DeleteAtAttribute));
|
|
1099
|
+
let sql = `update ${fromText} set ${updateText}`;
|
|
1100
|
+
if (filterText) {
|
|
1101
|
+
sql += ` where ${filterText}`;
|
|
1102
|
+
}
|
|
1103
|
+
if (sorterText) {
|
|
1104
|
+
sql += ` order by ${sorterText}`;
|
|
1105
|
+
}
|
|
1106
|
+
if (typeof indexFrom === 'number') {
|
|
1107
|
+
(0, assert_1.default)(typeof count === 'number');
|
|
1108
|
+
sql += ` limit ${indexFrom}, ${count}`;
|
|
1109
|
+
}
|
|
1110
|
+
return sql;
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* 将MySQL返回的Type回译成oak的类型,是 populateDataTypeDef 的反函数
|
|
1114
|
+
* @param type
|
|
1115
|
+
*/
|
|
1116
|
+
reTranslateToAttribute(type) {
|
|
1117
|
+
const withLengthDataTypes = MySqlTranslator.withLengthDataTypes.join('|');
|
|
1118
|
+
let result = (new RegExp(`^(${withLengthDataTypes})\\((\\d+)\\)$`)).exec(type);
|
|
1119
|
+
if (result) {
|
|
1120
|
+
return {
|
|
1121
|
+
type: result[1],
|
|
1122
|
+
params: {
|
|
1123
|
+
length: parseInt(result[2]),
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
const withPrecisionDataTypes = MySqlTranslator.withPrecisionDataTypes.join('|');
|
|
1128
|
+
result = (new RegExp(`^(${withPrecisionDataTypes})\\((\\d+),(d+)\\)$`)).exec(type);
|
|
1129
|
+
if (result) {
|
|
1130
|
+
return {
|
|
1131
|
+
type: result[1],
|
|
1132
|
+
params: {
|
|
1133
|
+
precision: parseInt(result[2]),
|
|
1134
|
+
scale: parseInt(result[3]),
|
|
1135
|
+
},
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
result = (/^enum\((\S+)\)$/).exec(type);
|
|
1139
|
+
if (result) {
|
|
1140
|
+
const enumeration = result[1].split(',').map(ele => ele.slice(1, -1));
|
|
1141
|
+
return {
|
|
1142
|
+
type: 'enum',
|
|
1143
|
+
enumeration
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
return {
|
|
1147
|
+
type: type,
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
// 分析当前数据库结构图
|
|
1151
|
+
async readSchema(execFn) {
|
|
1152
|
+
const result = {};
|
|
1153
|
+
const sql = 'show tables;';
|
|
1154
|
+
const [tables] = await execFn(sql);
|
|
1155
|
+
for (const tableItem of tables) {
|
|
1156
|
+
const table = Object.values(tableItem)[0];
|
|
1157
|
+
const [tableResult] = await execFn(`desc \`${table}\``);
|
|
1158
|
+
const attributes = {};
|
|
1159
|
+
for (const attrItem of tableResult) {
|
|
1160
|
+
const { Field: attrName, Null: isNull, Type: type, Key: key } = attrItem;
|
|
1161
|
+
attributes[attrName] = {
|
|
1162
|
+
...this.reTranslateToAttribute(type),
|
|
1163
|
+
notNull: isNull.toUpperCase() === 'NO',
|
|
1164
|
+
unique: key.toUpperCase() === 'UNI',
|
|
1165
|
+
};
|
|
1166
|
+
// 自增列只可能是seq
|
|
1167
|
+
if (attrName === '$$seq$$') {
|
|
1168
|
+
attributes[attrName].sequenceStart = 10000;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
Object.assign(result, {
|
|
1172
|
+
[table]: {
|
|
1173
|
+
attributes,
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
const [indexedColumns] = (await execFn(`show index from \`${table}\``));
|
|
1177
|
+
if (indexedColumns.length) {
|
|
1178
|
+
const groupedColumns = (0, lodash_1.groupBy)(indexedColumns.sort((ele1, ele2) => ele1.Key_name.localeCompare(ele2.Key_name) || ele1.Seq_in_index - ele2.Seq_in_index), 'Key_name');
|
|
1179
|
+
const indexes = Object.values(groupedColumns).map((ele) => {
|
|
1180
|
+
const index = {
|
|
1181
|
+
name: ele[0].Key_name,
|
|
1182
|
+
attributes: ele.map(ele2 => ({
|
|
1183
|
+
name: ele2.Column_name,
|
|
1184
|
+
direction: ele2.Collation === 'D' ? 'DESC' : (ele2.Collation === 'A' ? 'ASC' : undefined),
|
|
1185
|
+
size: ele2.Sub_part || undefined,
|
|
1186
|
+
})),
|
|
1187
|
+
};
|
|
1188
|
+
if (ele[0].Non_unique === 0 || ele[0].Index_type.toUpperCase() !== 'BTREE') {
|
|
1189
|
+
index.config = {};
|
|
1190
|
+
if (ele[0].Non_unique === 0) {
|
|
1191
|
+
index.config.unique = true;
|
|
1192
|
+
}
|
|
1193
|
+
if (ele[0].Index_type.toUpperCase() !== 'BTREE') {
|
|
1194
|
+
index.config.type = ele[0].Index_type.toLowerCase();
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
return index;
|
|
1198
|
+
});
|
|
1199
|
+
Object.assign(result[table], {
|
|
1200
|
+
indexes,
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return result;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
exports.MySqlTranslator = MySqlTranslator;
|