oak-db 3.0.0 → 3.0.2

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.
@@ -1,971 +1,966 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SqlTranslator = void 0;
4
- var tslib_1 = require("tslib");
5
- var assert_1 = tslib_1.__importDefault(require("assert"));
6
- var lodash_1 = require("lodash");
7
- var types_1 = require("oak-domain/lib/types");
8
- var relation_1 = require("oak-domain/lib/store/relation");
9
- var filter_1 = require("oak-domain/lib/store/filter");
10
- ;
11
- ;
12
- var SqlTranslator = /** @class */ (function () {
13
- function SqlTranslator(schema) {
14
- this.schema = this.makeFullSchema(schema);
15
- }
16
- SqlTranslator.prototype.makeFullSchema = function (schema2) {
17
- var schema = (0, lodash_1.cloneDeep)(schema2);
18
- for (var entity in schema) {
19
- var _a = schema[entity], attributes = _a.attributes, indexes = _a.indexes;
20
- // 增加默认的属性
21
- (0, lodash_1.assign)(attributes, {
22
- id: {
23
- type: 'char',
24
- params: {
25
- length: 36,
26
- },
27
- },
28
- $$seq$$: {
29
- type: 'sequence',
30
- sequenceStart: 10000,
31
- },
32
- $$createAt$$: {
33
- type: 'datetime',
34
- notNull: true,
35
- },
36
- $$updateAt$$: {
37
- type: 'datetime',
38
- notNull: true,
39
- },
40
- $$deleteAt$$: {
41
- type: 'datetime',
42
- },
43
- $$triggerData$$: {
44
- type: 'object',
45
- },
46
- $$triggerTimestamp$$: {
47
- type: 'datetime',
48
- },
49
- });
50
- // 增加默认的索引
51
- var intrinsticIndexes = [
52
- {
53
- name: "".concat(entity, "_create_at_auto_create"),
54
- attributes: [{
55
- name: '$$createAt$$',
56
- }, {
57
- name: '$$deleteAt$$',
58
- }]
59
- }, {
60
- name: "".concat(entity, "_update_at_auto_create"),
61
- attributes: [{
62
- name: '$$updateAt$$',
63
- }, {
64
- name: '$$deleteAt$$',
65
- }],
66
- }, {
67
- name: "".concat(entity, "_trigger_ts_auto_create"),
68
- attributes: [{
69
- name: '$$triggerTimestamp$$',
70
- }, {
71
- name: '$$deleteAt$$',
72
- }],
73
- }
74
- ];
75
- var _loop_1 = function (attr) {
76
- if (attributes[attr].type === 'ref') {
77
- if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { return ele.attributes[0].name === attr; }))) {
78
- intrinsticIndexes.push({
79
- name: "".concat(entity, "_fk_").concat(attr, "_auto_create"),
80
- attributes: [{
81
- name: attr,
82
- }, {
83
- name: '$$deleteAt$$',
84
- }]
85
- });
86
- }
87
- }
88
- if (attr === 'entity' && attributes[attr].type === 'varchar') {
89
- var entityIdDef = attributes.entityId;
90
- if ((entityIdDef === null || entityIdDef === void 0 ? void 0 : entityIdDef.type) === 'varchar') {
91
- if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { var _a; return ele.attributes[0].name === 'entity' && ((_a = ele.attributes[1]) === null || _a === void 0 ? void 0 : _a.name) === 'entityId'; }))) {
92
- intrinsticIndexes.push({
93
- name: "".concat(entity, "_fk_entity_entityId_auto_create"),
94
- attributes: [{
95
- name: 'entity',
96
- }, {
97
- name: 'entityId',
98
- }, {
99
- name: '$$deleteAt$$',
100
- }]
101
- });
102
- }
103
- }
104
- }
105
- if (attr.endsWith('State') && attributes[attr].type === 'varchar') {
106
- if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { return ele.attributes[0].name === attr; }))) {
107
- intrinsticIndexes.push({
108
- name: "".concat(entity, "_").concat(attr, "_auto_create"),
109
- attributes: [{
110
- name: attr,
111
- }, {
112
- name: '$$deleteAt$$',
113
- }]
114
- });
115
- }
116
- }
117
- if (attr === 'expired' && attributes[attr].type === 'boolean') {
118
- var expiresAtDef = attributes.expiresAt;
119
- if ((expiresAtDef === null || expiresAtDef === void 0 ? void 0 : expiresAtDef.type) === 'datetime') {
120
- if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { var _a; return ele.attributes[0].name === 'expired' && ((_a = ele.attributes[1]) === null || _a === void 0 ? void 0 : _a.name) === 'expiresAt'; }))) {
121
- intrinsticIndexes.push({
122
- name: "".concat(entity, "_expires_expiredAt_auto_create"),
123
- attributes: [{
124
- name: 'expired',
125
- }, {
126
- name: 'expiresAt',
127
- }, {
128
- name: '$$deleteAt$$',
129
- }]
130
- });
131
- }
132
- }
133
- }
134
- };
135
- // 增加外键等相关属性上的索引
136
- for (var attr in attributes) {
137
- _loop_1(attr);
138
- }
139
- if (indexes) {
140
- indexes.push.apply(indexes, intrinsticIndexes);
141
- }
142
- else {
143
- (0, lodash_1.assign)(schema[entity], {
144
- indexes: intrinsticIndexes,
145
- });
146
- }
147
- }
148
- return schema;
149
- };
150
- SqlTranslator.prototype.getStorageName = function (entity) {
151
- var storageName = this.schema[entity].storageName;
152
- return (storageName || entity);
153
- };
154
- SqlTranslator.prototype.translateInsert = function (entity, data) {
155
- var _this = this;
156
- var schema = this.schema;
157
- var _a = schema[entity], attributes = _a.attributes, _b = _a.storageName, storageName = _b === void 0 ? entity : _b;
158
- var sql = "insert into `".concat(storageName, "`(");
159
- /**
160
- * 这里的attrs要用所有行的union集合
161
- */
162
- var dataFull = data.reduce(function (prev, cur) { return Object.assign({}, cur, prev); }, {});
163
- var attrs = Object.keys(dataFull).filter(function (ele) { return attributes.hasOwnProperty(ele); });
164
- attrs.forEach(function (attr, idx) {
165
- sql += " `".concat(attr, "`");
166
- if (idx < attrs.length - 1) {
167
- sql += ',';
168
- }
169
- });
170
- sql += ') values ';
171
- data.forEach(function (d, dataIndex) {
172
- sql += '(';
173
- attrs.forEach(function (attr, attrIdx) {
174
- var attrDef = attributes[attr];
175
- var dataType = attrDef.type;
176
- var value = _this.translateAttrValue(dataType, d[attr]);
177
- sql += value;
178
- if (attrIdx < attrs.length - 1) {
179
- sql += ',';
180
- }
181
- });
182
- if (dataIndex < data.length - 1) {
183
- sql += '),';
184
- }
185
- else {
186
- sql += ')';
187
- }
188
- });
189
- return sql;
190
- };
191
- /**
192
- * analyze the join relations in projection/query/sort
193
- * 所有的层次关系都当成left join处理,如果有内表为空的情况,请手动处理
194
- * {
195
- * b: {
196
- * name: {
197
- * $exists: false,
198
- * }
199
- * }
200
- * }
201
- * 这样的query会把内表为空的行也返回
202
- * @param param0
203
- */
204
- SqlTranslator.prototype.analyzeJoin = function (entity, _a, initialNumber) {
205
- var _this = this;
206
- var projection = _a.projection, filter = _a.filter, sorter = _a.sorter, aggregation = _a.aggregation;
207
- var schema = this.schema;
208
- var number = initialNumber || 1;
209
- var projectionRefAlias = {};
210
- var filterRefAlias = {};
211
- var alias = "".concat(entity, "_").concat(number++);
212
- var from = " `".concat(this.getStorageName(entity), "` `").concat(alias, "` ");
213
- var aliasDict = {
214
- './': alias,
215
- };
216
- var analyzeFilterNode = function (_a) {
217
- var _b;
218
- var node = _a.node, path = _a.path, entityName = _a.entityName, alias = _a.alias;
219
- Object.keys(node).forEach(function (op) {
220
- var _a, _b;
221
- if (['$and', '$or'].includes(op)) {
222
- node[op].forEach(function (subNode) { return analyzeFilterNode({
223
- node: subNode,
224
- path: path,
225
- entityName: entityName,
226
- alias: alias,
227
- }); });
228
- }
229
- else if (['$not'].includes(op)) {
230
- analyzeFilterNode({
231
- node: node[op],
232
- path: path,
233
- entityName: entityName,
234
- alias: alias,
235
- });
236
- }
237
- else if (['$text'].includes(op)) {
238
- }
239
- else {
240
- var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, op);
241
- if (typeof rel === 'string') {
242
- var alias2 = void 0;
243
- var pathAttr = "".concat(path).concat(op, "/");
244
- if (!aliasDict.hasOwnProperty(pathAttr)) {
245
- alias2 = "".concat(rel, "_").concat(number++);
246
- (0, lodash_1.assign)(aliasDict, (_a = {},
247
- _a[pathAttr] = alias2,
248
- _a));
249
- from += " left join `".concat(_this.getStorageName(rel), "` `").concat(alias2, "` on `").concat(alias, "`.`").concat(op, "Id` = `").concat(alias2, "`.`id`");
250
- }
251
- else {
252
- alias2 = aliasDict[pathAttr];
253
- }
254
- analyzeFilterNode({
255
- node: node[op],
256
- path: pathAttr,
257
- entityName: rel,
258
- alias: alias2,
259
- });
260
- }
261
- else if (rel === 2) {
262
- var alias2 = void 0;
263
- var pathAttr = "".concat(path).concat(op, "/");
264
- if (!aliasDict.hasOwnProperty(pathAttr)) {
265
- alias2 = "".concat(op, "_").concat(number++);
266
- (0, lodash_1.assign)(aliasDict, (_b = {},
267
- _b[pathAttr] = alias2,
268
- _b));
269
- from += " left join `".concat(_this.getStorageName(op), "` `").concat(alias2, "` on `").concat(alias, "`.`entityId` = `").concat(alias2, "`.`id` and `").concat(alias, "`.`entity` = '").concat(op, "'");
270
- }
271
- else {
272
- alias2 = aliasDict[pathAttr];
273
- }
274
- analyzeFilterNode({
275
- node: node[op],
276
- path: pathAttr,
277
- entityName: op,
278
- alias: alias2,
279
- });
280
- }
281
- else {
282
- // 不支持一对多
283
- // assert(rel === 0 || rel === 1);
284
- }
285
- }
286
- });
287
- if (node['#id']) {
288
- (0, assert_1.default)(!filterRefAlias[node['#id']]);
289
- (0, lodash_1.assign)(filterRefAlias, (_b = {},
290
- _b[node['#id']] = [alias, entityName],
291
- _b));
292
- }
293
- };
294
- if (filter) {
295
- analyzeFilterNode({
296
- node: filter,
297
- path: './',
298
- entityName: entity,
299
- alias: alias,
300
- });
301
- }
302
- var analyzeSortNode = function (_a) {
303
- var _b, _c;
304
- var node = _a.node, path = _a.path, entityName = _a.entityName, alias = _a.alias;
305
- var attr = (0, lodash_1.keys)(node)[0];
306
- var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, attr);
307
- if (typeof rel === 'string') {
308
- var pathAttr = "".concat(path).concat(attr, "/");
309
- var alias2 = void 0;
310
- if (!aliasDict.hasOwnProperty(pathAttr)) {
311
- alias2 = "".concat(rel, "_").concat(number++);
312
- (0, lodash_1.assign)(aliasDict, (_b = {},
313
- _b[pathAttr] = alias2,
314
- _b));
315
- from += " left join `".concat(_this.getStorageName(rel), "` `").concat(alias2, "` on `").concat(alias, "`.`").concat(attr, "Id` = `").concat(alias2, "`.`id`");
316
- }
317
- else {
318
- alias2 = aliasDict[pathAttr];
319
- }
320
- analyzeSortNode({
321
- node: node[attr],
322
- path: pathAttr,
323
- entityName: rel,
324
- alias: alias2,
325
- });
326
- }
327
- else if (rel === 2) {
328
- var pathAttr = "".concat(path).concat(attr, "/");
329
- var alias2 = void 0;
330
- if (!aliasDict.hasOwnProperty(pathAttr)) {
331
- alias2 = "".concat(attr, "_").concat(number++);
332
- (0, lodash_1.assign)(aliasDict, (_c = {},
333
- _c[pathAttr] = alias2,
334
- _c));
335
- from += " left join `".concat(_this.getStorageName(attr), "` `").concat(alias2, "` on `").concat(alias, "`.`entityId` = `").concat(alias2, "`.`id` and `").concat(alias, "`.`entity` = '").concat(attr, "'");
336
- }
337
- else {
338
- alias2 = aliasDict[pathAttr];
339
- }
340
- analyzeSortNode({
341
- node: node[attr],
342
- path: pathAttr,
343
- entityName: attr,
344
- alias: alias2,
345
- });
346
- }
347
- else {
348
- (0, assert_1.default)(rel === 0 || rel === 1);
349
- }
350
- };
351
- if (sorter) {
352
- sorter.forEach(function (sortNode) {
353
- analyzeSortNode({
354
- node: sortNode.$attr,
355
- path: './',
356
- entityName: entity,
357
- alias: alias,
358
- });
359
- });
360
- }
361
- var analyzeProjectionNode = function (_a) {
362
- var _b;
363
- var node = _a.node, path = _a.path, entityName = _a.entityName, alias = _a.alias;
364
- var attributes = schema[entityName].attributes;
365
- Object.keys(node).forEach(function (attr) {
366
- var _a, _b;
367
- var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, attr);
368
- if (typeof rel === 'string') {
369
- var pathAttr = "".concat(path).concat(attr, "/");
370
- var alias2 = void 0;
371
- if (!aliasDict.hasOwnProperty(pathAttr)) {
372
- alias2 = "".concat(rel, "_").concat(number++);
373
- (0, lodash_1.assign)(aliasDict, (_a = {},
374
- _a[pathAttr] = alias2,
375
- _a));
376
- from += " left join `".concat(_this.getStorageName(rel), "` `").concat(alias2, "` on `").concat(alias, "`.`").concat(attr, "Id` = `").concat(alias2, "`.`id`");
377
- }
378
- else {
379
- alias2 = aliasDict[pathAttr];
380
- }
381
- analyzeProjectionNode({
382
- node: node[attr],
383
- path: pathAttr,
384
- entityName: rel,
385
- alias: alias2,
386
- });
387
- }
388
- else if (rel === 2) {
389
- var pathAttr = "".concat(path).concat(attr, "/");
390
- var alias2 = void 0;
391
- if (!aliasDict.hasOwnProperty(pathAttr)) {
392
- alias2 = "".concat(attr, "_").concat(number++);
393
- (0, lodash_1.assign)(aliasDict, (_b = {},
394
- _b[pathAttr] = alias2,
395
- _b));
396
- from += " left join `".concat(_this.getStorageName(attr), "` `").concat(alias2, "` on `").concat(alias, "`.`entityId` = `").concat(alias2, "`.`id` and `").concat(alias, "`.`entity` = '").concat(attr, "'");
397
- }
398
- else {
399
- alias2 = aliasDict[pathAttr];
400
- }
401
- analyzeProjectionNode({
402
- node: node[attr],
403
- path: pathAttr,
404
- entityName: attr,
405
- alias: alias2,
406
- });
407
- }
408
- });
409
- if (node['#id']) {
410
- (0, assert_1.default)(!projectionRefAlias[node['#id']], "projection\u4E0A\u6709\u91CD\u590D\u7684#id\u5B9A\u4E49\u300C".concat(node['#id'], "\u300D"));
411
- (0, lodash_1.assign)(projectionRefAlias, (_b = {},
412
- _b[node['#id']] = [alias, entityName],
413
- _b));
414
- }
415
- };
416
- if (projection) {
417
- analyzeProjectionNode({ node: projection, path: './', entityName: entity, alias: alias });
418
- }
419
- else if (aggregation) {
420
- for (var k in aggregation) {
421
- analyzeProjectionNode({
422
- node: aggregation[k],
423
- path: './',
424
- entityName: entity,
425
- alias: alias,
426
- });
427
- }
428
- }
429
- return {
430
- aliasDict: aliasDict,
431
- from: from,
432
- projectionRefAlias: projectionRefAlias,
433
- filterRefAlias: filterRefAlias,
434
- currentNumber: number,
435
- };
436
- };
437
- SqlTranslator.prototype.translateComparison = function (attr, value, type) {
438
- var SQL_OP = {
439
- $gt: '>',
440
- $lt: '<',
441
- $gte: '>=',
442
- $lte: '<=',
443
- $eq: '=',
444
- $ne: '<>',
445
- };
446
- if (Object.keys(SQL_OP).includes(attr)) {
447
- if (type) {
448
- return " ".concat(SQL_OP[attr], " ").concat(this.translateAttrValue(type, value));
449
- }
450
- else {
451
- return " ".concat(SQL_OP[attr], " ").concat(value);
452
- }
453
- }
454
- switch (attr) {
455
- case '$startsWith': {
456
- return " like '".concat(value, "%'");
457
- }
458
- case '$endsWith': {
459
- return " like '%".concat(value, "'");
460
- }
461
- case '$includes': {
462
- return " like '%".concat(value, "%'");
463
- }
464
- default: {
465
- throw new Error("unrecoganized comparison operator ".concat(attr));
466
- }
467
- }
468
- };
469
- SqlTranslator.prototype.translateEvaluation = function (attr, value, entity, alias, type, initialNumber, refAlias) {
470
- switch (attr) {
471
- case '$in':
472
- case '$nin': {
473
- var IN_OP = {
474
- $in: 'in',
475
- $nin: 'not in',
476
- };
477
- if (value instanceof Array) {
478
- return {
479
- stmt: this.translatePredicate(attr, value, type),
480
- currentNumber: initialNumber,
481
- };
482
- }
483
- else {
484
- (0, assert_1.default)(false, '子查询已经改写为一对多的形式');
485
- // sub query
486
- /* const { stmt: subQueryStmt, currentNumber } = this.translateSelectInner(value.entity, value, initialNumber, refAlias, undefined);
487
- return {
488
- stmt: ` ${IN_OP[attr]}(${subQueryStmt})`,
489
- currentNumber,
490
- }; */
491
- }
492
- }
493
- default: {
494
- throw new Error("".concat(attr, " is not evaluation predicate"));
495
- }
496
- }
497
- };
498
- SqlTranslator.prototype.translatePredicate = function (predicate, value, type) {
499
- if (['$gt', '$gte', '$lt', '$lte', '$eq', '$ne', '$startsWith', '$endsWith', '$includes'].includes(predicate)) {
500
- return this.translateComparison(predicate, value, type);
501
- }
502
- else if (['$in', '$nin'].includes(predicate)) {
503
- (0, assert_1.default)(value instanceof Array);
504
- var IN_OP = {
505
- $in: 'in',
506
- $nin: 'not in',
507
- };
508
- var values = value.map(function (v) {
509
- if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
510
- return "'".concat(v, "'");
511
- }
512
- else {
513
- return "".concat(v);
514
- }
515
- });
516
- if (values.length > 0) {
517
- return " ".concat(IN_OP[predicate], "(").concat(values.join(','), ")");
518
- }
519
- if (predicate === '$in') {
520
- return ' in (null)';
521
- }
522
- return ' is not null';
523
- }
524
- else if (predicate === '$between') {
525
- var values = value.map(function (v) {
526
- if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
527
- return "'".concat(v, "'");
528
- }
529
- else {
530
- return "".concat(v);
531
- }
532
- });
533
- // between是所有数据库都支持的语法吗?
534
- return " between ".concat(values[0], " and ").concat(values[1]);
535
- }
536
- else {
537
- (0, assert_1.default)(predicate === '$exists');
538
- if (value) {
539
- return ' is not null';
540
- }
541
- return ' is null';
542
- }
543
- };
544
- SqlTranslator.prototype.translateFilter = function (entity, filter, aliasDict, filterRefAlias, initialNumber, option) {
545
- var _this = this;
546
- var schema = this.schema;
547
- var currentNumber = initialNumber;
548
- var translateInner = function (entity2, path, filter2, type) {
549
- var alias = aliasDict[path];
550
- var attributes = schema[entity2].attributes;
551
- var whereText = type ? '' : _this.getDefaultSelectFilter(alias, option);
552
- if (filter2) {
553
- var attrs = Object.keys(filter2).filter(function (ele) { return !ele.startsWith('#'); });
554
- attrs.forEach(function (attr) {
555
- var _a;
556
- if (whereText) {
557
- whereText += ' and ';
558
- }
559
- if (['$and', '$or', '$xor', '$not'].includes(attr)) {
560
- whereText += '(';
561
- switch (attr) {
562
- case '$and':
563
- case '$or':
564
- case '$xor': {
565
- var logicQueries_1 = filter2[attr];
566
- logicQueries_1.forEach(function (logicQuery, index) {
567
- var sql = translateInner(entity2, path, logicQuery, 'ref'); // 只要传个值就行了,应该无所谓
568
- if (sql) {
569
- whereText += " (".concat(sql, ")");
570
- if (index < logicQueries_1.length - 1) {
571
- whereText += " ".concat(attr.slice(1));
572
- }
573
- }
574
- });
575
- break;
576
- }
577
- default: {
578
- (0, assert_1.default)(attr === '$not');
579
- var logicQuery = filter2[attr];
580
- var sql = translateInner(entity2, path, logicQuery, 'ref'); // 只要传个值就行了,应该无所谓
581
- if (sql) {
582
- whereText += " not (".concat(sql, ")");
583
- break;
584
- }
585
- }
586
- }
587
- whereText += ')';
588
- }
589
- else if (attr === '$text') {
590
- whereText += "(".concat(_this.translateFullTextSearch(filter2[attr], entity2, alias), ")");
591
- }
592
- else if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
593
- // expression
594
- whereText += " (".concat(_this.translateExpression(entity2, alias, filter2[attr], filterRefAlias), ")");
595
- }
596
- else {
597
- var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
598
- if (rel === 2) {
599
- whereText += " (".concat(translateInner(attr, "".concat(path).concat(attr, "/"), filter2[attr]), ")");
600
- }
601
- else if (typeof rel === 'string') {
602
- whereText += " (".concat(translateInner(rel, "".concat(path).concat(attr, "/"), filter2[attr]), ")");
603
- }
604
- else if (rel instanceof Array) {
605
- var subEntity = rel[0], foreignKey = rel[1];
606
- var predicate = (filter2[attr]['#sqp'] || 'in');
607
- /**
608
- *
609
- * in代表外键连接后至少有一行数据
610
- * not in代表外键连接后一行也不能有
611
- * all代表反外键连接条件的一行也不能有(符合的是否至少要有一行?直觉上没这个限制)
612
- * not all 代表反外键连接条件的至少有一行
613
- *
614
- * 目前将这种子查询翻译成了exists查询,当外表很大而子查询结果集很小时可能有性能问题,取决于MySQL执行器的能力
615
- * by Xc 20230726
616
- */
617
- var refAlia = Object.keys(filterRefAlias).find(function (ele) { return filterRefAlias[ele][0] === alias; });
618
- var refAlia2 = refAlia || alias; // alias一定是唯一的,可以用来作为node id
619
- if (!refAlia) {
620
- (0, assert_1.default)(!filterRefAlias[refAlia2]);
621
- Object.assign(filterRefAlias, (_a = {},
622
- _a[refAlia2] = [alias, entity2],
623
- _a));
624
- }
625
- var fk = foreignKey || 'entityId';
626
- var joinFilter = ['not in', 'in'].includes(predicate) ? {
627
- $expr12: {
628
- $eq: [
629
- {
630
- '#attr': fk,
631
- },
632
- {
633
- '#refId': refAlia2,
634
- '#refAttr': 'id',
635
- }
636
- ],
637
- }
638
- } : {
639
- $expr12: {
640
- $ne: [
641
- {
642
- '#attr': fk,
643
- },
644
- {
645
- '#refId': refAlia2,
646
- '#refAttr': 'id',
647
- }
648
- ],
649
- }
650
- };
651
- if (!foreignKey) {
652
- Object.assign(joinFilter, {
653
- entity: entity2,
654
- });
655
- }
656
- var _b = _this.translateSelectInner(subEntity, {
657
- data: {
658
- id: 1,
659
- },
660
- filter: (0, filter_1.combineFilters)(subEntity, _this.schema, [joinFilter, filter2[attr]]),
661
- indexFrom: 0,
662
- count: 1,
663
- }, currentNumber, filterRefAlias, option), stmt = _b.stmt, ct2 = _b.currentNumber;
664
- currentNumber = ct2;
665
- var PREDICATE_DICT = {
666
- 'in': 'exists',
667
- 'not in': 'not exists',
668
- 'all': 'not exists',
669
- 'not all': 'exists',
670
- };
671
- whereText += " ".concat(PREDICATE_DICT[predicate], " (").concat(stmt, ")");
672
- }
673
- else {
674
- (0, assert_1.default)(attributes.hasOwnProperty(attr), "\u975E\u6CD5\u7684\u5C5E\u6027".concat(attr));
675
- var type2 = attributes[attr].type;
676
- // assert (type2 !== 'ref');
677
- if (typeof filter2[attr] === 'object') {
678
- if (['object', 'array'].includes(type2)) {
679
- // 对object数据的深层次查询,这里调用数据库所支持的属性对象级查询,如mysql中的json查询
680
- whereText += "(".concat(_this.translateObjectPredicate(filter2[attr], alias, attr), ")");
681
- }
682
- else {
683
- (0, assert_1.default)(Object.keys(filter2[attr]).length === 1);
684
- var predicate = Object.keys(filter2[attr])[0];
685
- (0, assert_1.default)(predicate.startsWith('$'));
686
- // 对属性上的谓词处理
687
- whereText += " (`".concat(alias, "`.`").concat(attr, "` ").concat(_this.translatePredicate(predicate, filter2[attr][predicate], type2), ")");
688
- }
689
- }
690
- else {
691
- whereText += " (`".concat(alias, "`.`").concat(attr, "` = ").concat(_this.translateAttrValue(type2, filter2[attr]), ")");
692
- }
693
- }
694
- }
695
- });
696
- }
697
- if (!whereText) {
698
- whereText = 'true'; // 如果为空就赋一个永真条件,以便处理and
699
- }
700
- return whereText;
701
- };
702
- var where = translateInner(entity, './', filter);
703
- return {
704
- stmt: where,
705
- currentNumber: currentNumber,
706
- };
707
- };
708
- SqlTranslator.prototype.translateSorter = function (entity, sorter, aliasDict) {
709
- var _this = this;
710
- var translateInner = function (entity2, sortAttr, path) {
711
- (0, assert_1.default)(Object.keys(sortAttr).length === 1);
712
- var attr = Object.keys(sortAttr)[0];
713
- var alias = aliasDict[path];
714
- if (attr.toLocaleLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
715
- return _this.translateExpression(entity2, alias, sortAttr[attr], {});
716
- }
717
- else if (sortAttr[attr] === 1) {
718
- return "`".concat(alias, "`.`").concat(attr, "`");
719
- }
720
- else {
721
- var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
722
- if (typeof rel === 'string') {
723
- return translateInner(rel, sortAttr[attr], "".concat(path).concat(attr, "/"));
724
- }
725
- else {
726
- (0, assert_1.default)(rel === 2);
727
- return translateInner(attr, sortAttr[attr], "".concat(path).concat(attr, "/"));
728
- }
729
- }
730
- };
731
- var sortText = '';
732
- sorter.forEach(function (sortNode, index) {
733
- var $attr = sortNode.$attr, $direction = sortNode.$direction;
734
- sortText += translateInner(entity, $attr, './');
735
- if ($direction) {
736
- sortText += " ".concat($direction);
737
- }
738
- if (index < sorter.length - 1) {
739
- sortText += ',';
740
- }
741
- });
742
- return sortText;
743
- };
744
- SqlTranslator.prototype.translateProjection = function (entity, projection, aliasDict, projectionRefAlias, commonPrefix, disableAs) {
745
- var _this = this;
746
- var schema = this.schema;
747
- var as = '';
748
- var translateInner = function (entity2, projection2, path) {
749
- var alias = aliasDict[path];
750
- var attributes = schema[entity2].attributes;
751
- var projText = '';
752
- var prefix = path.slice(2).replace(/\//g, '.');
753
- var attrs = Object.keys(projection2).filter(function (attr) {
754
- if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
755
- return true;
756
- }
757
- var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
758
- return [1, 2].includes(rel) || typeof rel === 'string';
759
- });
760
- attrs.forEach(function (attr, idx) {
761
- var prefix2 = commonPrefix ? "".concat(commonPrefix, ".").concat(prefix) : prefix;
762
- if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
763
- var exprText = _this.translateExpression(entity2, alias, projection2[attr], projectionRefAlias);
764
- if (disableAs) {
765
- projText += " ".concat(exprText);
766
- }
767
- else {
768
- projText += " ".concat(exprText, " as `").concat(prefix2).concat(attr, "`");
769
- if (!as) {
770
- as = "`".concat(prefix2).concat(attr, "`");
771
- }
772
- else {
773
- as += ", `".concat(prefix2).concat(attr, "`");
774
- }
775
- }
776
- }
777
- else {
778
- var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
779
- if (typeof rel === 'string') {
780
- projText += translateInner(rel, projection2[attr], "".concat(path).concat(attr, "/"));
781
- }
782
- else if (rel === 2) {
783
- projText += translateInner(attr, projection2[attr], "".concat(path).concat(attr, "/"));
784
- }
785
- else if (rel === 1) {
786
- var type = attributes[attr].type;
787
- if (projection2[attr] === 1) {
788
- if (disableAs) {
789
- projText += " ".concat(_this.translateAttrProjection(type, alias, attr));
790
- }
791
- else {
792
- projText += " ".concat(_this.translateAttrProjection(type, alias, attr), " as `").concat(prefix2).concat(attr, "`");
793
- if (!as) {
794
- as = "`".concat(prefix2).concat(attr, "`");
795
- }
796
- else {
797
- as += ", `".concat(prefix2).concat(attr, "`");
798
- }
799
- }
800
- }
801
- else if (typeof projection2[attr] === 'object') {
802
- // 对JSON对象的取值
803
- (0, assert_1.default)(!disableAs);
804
- (0, assert_1.default)(['object', 'array'].includes(type));
805
- projText += " ".concat(_this.translateObjectProjection(projection2[attr], alias, attr, prefix2));
806
- }
807
- else {
808
- (0, assert_1.default)(typeof projection2 === 'string');
809
- if (disableAs) {
810
- projText += " ".concat(_this.translateAttrProjection(type, alias, attr));
811
- }
812
- else {
813
- projText += " ".concat(_this.translateAttrProjection(type, alias, attr), " as `").concat(prefix2).concat(projection2[attr], "`");
814
- if (!as) {
815
- as = "`".concat(prefix2).concat(projection2[attr], "`");
816
- }
817
- else {
818
- as += "`".concat(prefix2).concat(projection2[attr], "`");
819
- }
820
- }
821
- }
822
- }
823
- }
824
- if (idx < attrs.length - 1) {
825
- projText += ',';
826
- }
827
- });
828
- return projText;
829
- };
830
- return {
831
- projText: translateInner(entity, projection, './'),
832
- as: as,
833
- };
834
- };
835
- SqlTranslator.prototype.translateSelectInner = function (entity, selection, initialNumber, refAlias, option) {
836
- var data = selection.data, filter = selection.filter, sorter = selection.sorter, indexFrom = selection.indexFrom, count = selection.count;
837
- var _a = this.analyzeJoin(entity, {
838
- projection: data,
839
- filter: filter,
840
- sorter: sorter,
841
- }, initialNumber), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
842
- (0, assert_1.default)((0, lodash_1.intersection)((0, lodash_1.keys)(refAlias), (0, lodash_1.keys)(filterRefAlias)).length === 0, 'filter中的#node结点定义有重复');
843
- (0, lodash_1.assign)(refAlias, filterRefAlias);
844
- var projText = this.translateProjection(entity, data, aliasDict, projectionRefAlias).projText;
845
- var _b = this.translateFilter(entity, filter, aliasDict, refAlias, currentNumber, option), filterText = _b.stmt, currentNumber2 = _b.currentNumber;
846
- var sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
847
- return {
848
- stmt: this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, undefined, indexFrom, count, option, selection),
849
- currentNumber: currentNumber2,
850
- filterStmt: filterText,
851
- };
852
- };
853
- SqlTranslator.prototype.translateSelect = function (entity, selection, option) {
854
- var stmt = this.translateSelectInner(entity, selection, 1, {}, option).stmt;
855
- return stmt;
856
- };
857
- SqlTranslator.prototype.translateWhere = function (entity, selection, option) {
858
- var filterStmt = this.translateSelectInner(entity, selection, 1, {}, option).filterStmt;
859
- return filterStmt;
860
- };
861
- SqlTranslator.prototype.translateAggregate = function (entity, aggregation, option) {
862
- var data = aggregation.data, filter = aggregation.filter, sorter = aggregation.sorter, indexFrom = aggregation.indexFrom, count = aggregation.count;
863
- var _a = this.analyzeJoin(entity, {
864
- aggregation: data,
865
- filter: filter,
866
- sorter: sorter,
867
- }, 1), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
868
- var projText = '';
869
- var groupByText = '';
870
- for (var k in data) {
871
- if (k === '#aggr') {
872
- var _b = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, '#data'), projSubText = _b.projText, as = _b.as;
873
- if (!projText) {
874
- projText = projSubText;
875
- }
876
- else {
877
- projText += ", ".concat(projSubText);
878
- }
879
- groupByText = as;
880
- }
881
- else {
882
- var projSubText = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, undefined, true).projText;
883
- var projSubText2 = '';
884
- if (k.startsWith('#max')) {
885
- projSubText2 = "max(".concat(projSubText, ") as `").concat(k, "`");
886
- }
887
- else if (k.startsWith('#min')) {
888
- projSubText2 = "min(".concat(projSubText, ") as `").concat(k, "`");
889
- }
890
- else if (k.startsWith('#count')) {
891
- projSubText2 = "count(".concat(projSubText, ") as `").concat(k, "`");
892
- }
893
- else if (k.startsWith('#sum')) {
894
- projSubText2 = "sum(".concat(projSubText, ") as `").concat(k, "`");
895
- }
896
- else {
897
- (0, assert_1.default)(k.startsWith('#avg'));
898
- projSubText2 = "avg(".concat(projSubText, ") as `").concat(k, "`");
899
- }
900
- if (!projText) {
901
- projText = projSubText2;
902
- }
903
- else {
904
- projText += ", ".concat(projSubText2);
905
- }
906
- }
907
- }
908
- var filterText = this.translateFilter(entity, filter, aliasDict, {}, currentNumber, option).stmt;
909
- var sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
910
- return this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, groupByText, indexFrom, count, option, undefined, aggregation);
911
- };
912
- SqlTranslator.prototype.translateCount = function (entity, selection, option) {
913
- var filter = selection.filter, count = selection.count;
914
- var _a = this.analyzeJoin(entity, {
915
- filter: filter,
916
- }), fromText = _a.from, aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
917
- var projText = 'count(1) cnt';
918
- var filterText = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, option).stmt;
919
- if (count) {
920
- var subQuerySql = this.populateSelectStmt('1', fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, Object.assign({}, selection, { indexFrom: 0, count: count }));
921
- return "select count(1) cnt from (".concat(subQuerySql, ") __tmp");
922
- }
923
- return this.populateSelectStmt(projText, fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, selection);
924
- };
925
- SqlTranslator.prototype.translateRemove = function (entity, operation, option) {
926
- var filter = operation.filter, sorter = operation.sorter, indexFrom = operation.indexFrom, count = operation.count;
927
- (0, assert_1.default)(!sorter, '当前remove不支持sorter行为');
928
- var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, fromText = _a.from, currentNumber = _a.currentNumber;
929
- var alias = aliasDict['./'];
930
- var filterText = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, { includedDeleted: true }).stmt;
931
- // const sorterText = sorter && sorter.length > 0 ? this.translateSorter(entity, sorter, aliasDict) : undefined;
932
- return this.populateRemoveStmt(alias, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
933
- };
934
- SqlTranslator.prototype.translateUpdate = function (entity, operation, option) {
935
- var attributes = this.schema[entity].attributes;
936
- var filter = operation.filter, sorter = operation.sorter, indexFrom = operation.indexFrom, count = operation.count, data = operation.data;
937
- (0, assert_1.default)(!sorter, '当前update不支持sorter行为');
938
- var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, fromText = _a.from, currentNumber = _a.currentNumber;
939
- var alias = aliasDict['./'];
940
- var updateText = '';
941
- for (var attr in data) {
942
- if (updateText) {
943
- updateText += ',';
944
- }
945
- (0, assert_1.default)(attributes.hasOwnProperty(attr));
946
- var value = this.translateAttrValue(attributes[attr].type, data[attr]);
947
- updateText += "`".concat(alias, "`.`").concat(attr, "` = ").concat(value);
948
- }
949
- var filterText = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber).stmt;
950
- // const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
951
- return this.populateUpdateStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
952
- };
953
- SqlTranslator.prototype.translateDestroyEntity = function (entity, truncate) {
954
- var schema = this.schema;
955
- var _a = schema[entity], _b = _a.storageName, storageName = _b === void 0 ? entity : _b, view = _a.view;
956
- var sql;
957
- if (view) {
958
- sql = "drop view if exists `".concat(storageName, "`");
959
- }
960
- else {
961
- sql = truncate ? "truncate table `".concat(storageName, "`") : "drop table if exists `".concat(storageName, "`");
962
- }
963
- return sql;
964
- };
965
- SqlTranslator.prototype.escapeStringValue = function (value) {
966
- var result = "'".concat(value.replace(/'/g, '\\\'').replace(/"/g, '\\\"'), "'");
967
- return result;
968
- };
969
- return SqlTranslator;
970
- }());
971
- exports.SqlTranslator = SqlTranslator;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqlTranslator = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ const sqlstring_1 = tslib_1.__importDefault(require("sqlstring"));
7
+ const lodash_1 = require("lodash");
8
+ const types_1 = require("oak-domain/lib/types");
9
+ const relation_1 = require("oak-domain/lib/store/relation");
10
+ const filter_1 = require("oak-domain/lib/store/filter");
11
+ ;
12
+ ;
13
+ class SqlTranslator {
14
+ schema;
15
+ constructor(schema) {
16
+ this.schema = this.makeFullSchema(schema);
17
+ }
18
+ makeFullSchema(schema2) {
19
+ const schema = (0, lodash_1.cloneDeep)(schema2);
20
+ for (const entity in schema) {
21
+ const { attributes, indexes } = schema[entity];
22
+ // 增加默认的属性
23
+ (0, lodash_1.assign)(attributes, {
24
+ id: {
25
+ type: 'char',
26
+ params: {
27
+ length: 36,
28
+ },
29
+ },
30
+ [types_1.SeqAttribute]: {
31
+ type: 'sequence',
32
+ sequenceStart: 10000,
33
+ },
34
+ [types_1.CreateAtAttribute]: {
35
+ type: 'datetime',
36
+ notNull: true,
37
+ },
38
+ [types_1.UpdateAtAttribute]: {
39
+ type: 'datetime',
40
+ notNull: true,
41
+ },
42
+ [types_1.DeleteAtAttribute]: {
43
+ type: 'datetime',
44
+ },
45
+ [types_1.TriggerDataAttribute]: {
46
+ type: 'object',
47
+ },
48
+ [types_1.TriggerUuidAttribute]: {
49
+ type: 'char',
50
+ params: {
51
+ length: 36,
52
+ },
53
+ },
54
+ });
55
+ // 增加默认的索引
56
+ const intrinsticIndexes = [
57
+ {
58
+ name: `${entity}_create_at_auto_create`,
59
+ attributes: [{
60
+ name: types_1.CreateAtAttribute,
61
+ }, {
62
+ name: types_1.DeleteAtAttribute,
63
+ }]
64
+ }, {
65
+ name: `${entity}_update_at_auto_create`,
66
+ attributes: [{
67
+ name: types_1.UpdateAtAttribute,
68
+ }, {
69
+ name: types_1.DeleteAtAttribute,
70
+ }],
71
+ }, {
72
+ name: `${entity}_trigger_uuid`,
73
+ attributes: [{
74
+ name: types_1.TriggerUuidAttribute,
75
+ }]
76
+ },
77
+ ];
78
+ // 增加外键等相关属性上的索引
79
+ for (const attr in attributes) {
80
+ if (attributes[attr].type === 'ref') {
81
+ if (!(indexes?.find(ele => ele.attributes[0].name === attr))) {
82
+ intrinsticIndexes.push({
83
+ name: `${entity}_fk_${attr}_auto_create`,
84
+ attributes: [{
85
+ name: attr,
86
+ }, {
87
+ name: '$$deleteAt$$',
88
+ }]
89
+ });
90
+ }
91
+ }
92
+ if (attr === 'entity' && attributes[attr].type === 'varchar') {
93
+ const entityIdDef = attributes.entityId;
94
+ if (entityIdDef?.type === 'varchar') {
95
+ if (!(indexes?.find(ele => ele.attributes[0].name === 'entity' && ele.attributes[1]?.name === 'entityId'))) {
96
+ intrinsticIndexes.push({
97
+ name: `${entity}_fk_entity_entityId_auto_create`,
98
+ attributes: [{
99
+ name: 'entity',
100
+ }, {
101
+ name: 'entityId',
102
+ }, {
103
+ name: '$$deleteAt$$',
104
+ }]
105
+ });
106
+ }
107
+ }
108
+ }
109
+ if (attr.endsWith('State') && attributes[attr].type === 'varchar') {
110
+ if (!(indexes?.find(ele => ele.attributes[0].name === attr))) {
111
+ intrinsticIndexes.push({
112
+ name: `${entity}_${attr}_auto_create`,
113
+ attributes: [{
114
+ name: attr,
115
+ }, {
116
+ name: '$$deleteAt$$',
117
+ }]
118
+ });
119
+ }
120
+ }
121
+ if (attr === 'expired' && attributes[attr].type === 'boolean') {
122
+ const expiresAtDef = attributes.expiresAt;
123
+ if (expiresAtDef?.type === 'datetime') {
124
+ if (!(indexes?.find(ele => ele.attributes[0].name === 'expired' && ele.attributes[1]?.name === 'expiresAt'))) {
125
+ intrinsticIndexes.push({
126
+ name: `${entity}_expires_expiredAt_auto_create`,
127
+ attributes: [{
128
+ name: 'expired',
129
+ }, {
130
+ name: 'expiresAt',
131
+ }, {
132
+ name: '$$deleteAt$$',
133
+ }]
134
+ });
135
+ }
136
+ }
137
+ }
138
+ }
139
+ if (indexes) {
140
+ indexes.push(...intrinsticIndexes);
141
+ }
142
+ else {
143
+ (0, lodash_1.assign)(schema[entity], {
144
+ indexes: intrinsticIndexes,
145
+ });
146
+ }
147
+ }
148
+ return schema;
149
+ }
150
+ getStorageName(entity) {
151
+ const { storageName } = this.schema[entity];
152
+ return (storageName || entity);
153
+ }
154
+ translateInsert(entity, data) {
155
+ const { schema } = this;
156
+ const { attributes, storageName = entity } = schema[entity];
157
+ let sql = `insert into \`${storageName}\`(`;
158
+ /**
159
+ * 这里的attrs要用所有行的union集合
160
+ */
161
+ const dataFull = data.reduce((prev, cur) => Object.assign({}, cur, prev), {});
162
+ const attrs = Object.keys(dataFull).filter(ele => attributes.hasOwnProperty(ele));
163
+ attrs.forEach((attr, idx) => {
164
+ sql += ` \`${attr}\``;
165
+ if (idx < attrs.length - 1) {
166
+ sql += ',';
167
+ }
168
+ });
169
+ sql += ') values ';
170
+ data.forEach((d, dataIndex) => {
171
+ sql += '(';
172
+ attrs.forEach((attr, attrIdx) => {
173
+ const attrDef = attributes[attr];
174
+ const { type: dataType } = attrDef;
175
+ const value = this.translateAttrValue(dataType, d[attr]);
176
+ sql += value;
177
+ if (attrIdx < attrs.length - 1) {
178
+ sql += ',';
179
+ }
180
+ });
181
+ if (dataIndex < data.length - 1) {
182
+ sql += '),';
183
+ }
184
+ else {
185
+ sql += ')';
186
+ }
187
+ });
188
+ return sql;
189
+ }
190
+ /**
191
+ * analyze the join relations in projection/query/sort
192
+ * 所有的层次关系都当成left join处理,如果有内表为空的情况,请手动处理
193
+ * {
194
+ * b: {
195
+ * name: {
196
+ * $exists: false,
197
+ * }
198
+ * }
199
+ * }
200
+ * 这样的query会把内表为空的行也返回
201
+ * @param param0
202
+ */
203
+ analyzeJoin(entity, { projection, filter, sorter, aggregation }, initialNumber) {
204
+ const { schema } = this;
205
+ let number = initialNumber || 1;
206
+ const projectionRefAlias = {};
207
+ const filterRefAlias = {};
208
+ const alias = `${entity}_${number++}`;
209
+ let from = ` \`${this.getStorageName(entity)}\` \`${alias}\` `;
210
+ const aliasDict = {
211
+ './': alias,
212
+ };
213
+ const analyzeFilterNode = ({ node, path, entityName, alias }) => {
214
+ Object.keys(node).forEach((op) => {
215
+ if (['$and', '$or'].includes(op)) {
216
+ node[op].forEach((subNode) => analyzeFilterNode({
217
+ node: subNode,
218
+ path,
219
+ entityName,
220
+ alias,
221
+ }));
222
+ }
223
+ else if (['$not'].includes(op)) {
224
+ analyzeFilterNode({
225
+ node: node[op],
226
+ path,
227
+ entityName,
228
+ alias,
229
+ });
230
+ }
231
+ else if (['$text'].includes(op)) {
232
+ }
233
+ else {
234
+ const rel = (0, relation_1.judgeRelation)(this.schema, entityName, op);
235
+ if (typeof rel === 'string') {
236
+ let alias2;
237
+ const pathAttr = `${path}${op}/`;
238
+ if (!aliasDict.hasOwnProperty(pathAttr)) {
239
+ alias2 = `${rel}_${number++}`;
240
+ (0, lodash_1.assign)(aliasDict, {
241
+ [pathAttr]: alias2,
242
+ });
243
+ from += ` left join \`${this.getStorageName(rel)}\` \`${alias2}\` on \`${alias}\`.\`${op}Id\` = \`${alias2}\`.\`id\``;
244
+ }
245
+ else {
246
+ alias2 = aliasDict[pathAttr];
247
+ }
248
+ analyzeFilterNode({
249
+ node: node[op],
250
+ path: pathAttr,
251
+ entityName: rel,
252
+ alias: alias2,
253
+ });
254
+ }
255
+ else if (rel === 2) {
256
+ let alias2;
257
+ const pathAttr = `${path}${op}/`;
258
+ if (!aliasDict.hasOwnProperty(pathAttr)) {
259
+ alias2 = `${op}_${number++}`;
260
+ (0, lodash_1.assign)(aliasDict, {
261
+ [pathAttr]: alias2,
262
+ });
263
+ from += ` left join \`${this.getStorageName(op)}\` \`${alias2}\` on \`${alias}\`.\`entityId\` = \`${alias2}\`.\`id\` and \`${alias}\`.\`entity\` = '${op}'`;
264
+ }
265
+ else {
266
+ alias2 = aliasDict[pathAttr];
267
+ }
268
+ analyzeFilterNode({
269
+ node: node[op],
270
+ path: pathAttr,
271
+ entityName: op,
272
+ alias: alias2,
273
+ });
274
+ }
275
+ else {
276
+ // 不支持一对多
277
+ // assert(rel === 0 || rel === 1);
278
+ }
279
+ }
280
+ });
281
+ if (node['#id']) {
282
+ (0, assert_1.default)(!filterRefAlias[node['#id']]);
283
+ (0, lodash_1.assign)(filterRefAlias, {
284
+ [node['#id']]: [alias, entityName],
285
+ });
286
+ }
287
+ };
288
+ if (filter) {
289
+ analyzeFilterNode({
290
+ node: filter,
291
+ path: './',
292
+ entityName: entity,
293
+ alias,
294
+ });
295
+ }
296
+ const analyzeSortNode = ({ node, path, entityName, alias }) => {
297
+ const attr = (0, lodash_1.keys)(node)[0];
298
+ const rel = (0, relation_1.judgeRelation)(this.schema, entityName, attr);
299
+ if (typeof rel === 'string') {
300
+ const pathAttr = `${path}${attr}/`;
301
+ let alias2;
302
+ if (!aliasDict.hasOwnProperty(pathAttr)) {
303
+ alias2 = `${rel}_${number++}`;
304
+ (0, lodash_1.assign)(aliasDict, {
305
+ [pathAttr]: alias2,
306
+ });
307
+ from += ` left join \`${this.getStorageName(rel)}\` \`${alias2}\` on \`${alias}\`.\`${attr}Id\` = \`${alias2}\`.\`id\``;
308
+ }
309
+ else {
310
+ alias2 = aliasDict[pathAttr];
311
+ }
312
+ analyzeSortNode({
313
+ node: node[attr],
314
+ path: pathAttr,
315
+ entityName: rel,
316
+ alias: alias2,
317
+ });
318
+ }
319
+ else if (rel === 2) {
320
+ const pathAttr = `${path}${attr}/`;
321
+ let alias2;
322
+ if (!aliasDict.hasOwnProperty(pathAttr)) {
323
+ alias2 = `${attr}_${number++}`;
324
+ (0, lodash_1.assign)(aliasDict, {
325
+ [pathAttr]: alias2,
326
+ });
327
+ from += ` left join \`${this.getStorageName(attr)}\` \`${alias2}\` on \`${alias}\`.\`entityId\` = \`${alias2}\`.\`id\` and \`${alias}\`.\`entity\` = '${attr}'`;
328
+ }
329
+ else {
330
+ alias2 = aliasDict[pathAttr];
331
+ }
332
+ analyzeSortNode({
333
+ node: node[attr],
334
+ path: pathAttr,
335
+ entityName: attr,
336
+ alias: alias2,
337
+ });
338
+ }
339
+ else {
340
+ (0, assert_1.default)(rel === 0 || rel === 1);
341
+ }
342
+ };
343
+ if (sorter) {
344
+ sorter.forEach((sortNode) => {
345
+ analyzeSortNode({
346
+ node: sortNode.$attr,
347
+ path: './',
348
+ entityName: entity,
349
+ alias,
350
+ });
351
+ });
352
+ }
353
+ const analyzeProjectionNode = ({ node, path, entityName, alias }) => {
354
+ const { attributes } = schema[entityName];
355
+ Object.keys(node).forEach((attr) => {
356
+ const rel = (0, relation_1.judgeRelation)(this.schema, entityName, attr);
357
+ if (typeof rel === 'string') {
358
+ const pathAttr = `${path}${attr}/`;
359
+ let alias2;
360
+ if (!aliasDict.hasOwnProperty(pathAttr)) {
361
+ alias2 = `${rel}_${number++}`;
362
+ (0, lodash_1.assign)(aliasDict, {
363
+ [pathAttr]: alias2,
364
+ });
365
+ from += ` left join \`${this.getStorageName(rel)}\` \`${alias2}\` on \`${alias}\`.\`${attr}Id\` = \`${alias2}\`.\`id\``;
366
+ }
367
+ else {
368
+ alias2 = aliasDict[pathAttr];
369
+ }
370
+ analyzeProjectionNode({
371
+ node: node[attr],
372
+ path: pathAttr,
373
+ entityName: rel,
374
+ alias: alias2,
375
+ });
376
+ }
377
+ else if (rel === 2) {
378
+ const pathAttr = `${path}${attr}/`;
379
+ let alias2;
380
+ if (!aliasDict.hasOwnProperty(pathAttr)) {
381
+ alias2 = `${attr}_${number++}`;
382
+ (0, lodash_1.assign)(aliasDict, {
383
+ [pathAttr]: alias2,
384
+ });
385
+ from += ` left join \`${this.getStorageName(attr)}\` \`${alias2}\` on \`${alias}\`.\`entityId\` = \`${alias2}\`.\`id\` and \`${alias}\`.\`entity\` = '${attr}'`;
386
+ }
387
+ else {
388
+ alias2 = aliasDict[pathAttr];
389
+ }
390
+ analyzeProjectionNode({
391
+ node: node[attr],
392
+ path: pathAttr,
393
+ entityName: attr,
394
+ alias: alias2,
395
+ });
396
+ }
397
+ });
398
+ if (node['#id']) {
399
+ (0, assert_1.default)(!projectionRefAlias[node['#id']], `projection上有重复的#id定义「${node['#id']}」`);
400
+ (0, lodash_1.assign)(projectionRefAlias, {
401
+ [node['#id']]: [alias, entityName],
402
+ });
403
+ }
404
+ };
405
+ if (projection) {
406
+ analyzeProjectionNode({ node: projection, path: './', entityName: entity, alias });
407
+ }
408
+ else if (aggregation) {
409
+ for (const k in aggregation) {
410
+ analyzeProjectionNode({
411
+ node: aggregation[k],
412
+ path: './',
413
+ entityName: entity,
414
+ alias,
415
+ });
416
+ }
417
+ }
418
+ return {
419
+ aliasDict,
420
+ from,
421
+ projectionRefAlias,
422
+ filterRefAlias,
423
+ currentNumber: number,
424
+ };
425
+ }
426
+ translateComparison(attr, value, type) {
427
+ const SQL_OP = {
428
+ $gt: '>',
429
+ $lt: '<',
430
+ $gte: '>=',
431
+ $lte: '<=',
432
+ $eq: '=',
433
+ $ne: '<>',
434
+ };
435
+ if (Object.keys(SQL_OP).includes(attr)) {
436
+ if (type) {
437
+ return ` ${SQL_OP[attr]} ${this.translateAttrValue(type, value)}`;
438
+ }
439
+ else {
440
+ return ` ${SQL_OP[attr]} ${value}`;
441
+ }
442
+ }
443
+ switch (attr) {
444
+ case '$startsWith': {
445
+ return ` like '${value}%'`;
446
+ }
447
+ case '$endsWith': {
448
+ return ` like '%${value}'`;
449
+ }
450
+ case '$includes': {
451
+ return ` like '%${value}%'`;
452
+ }
453
+ default: {
454
+ throw new Error(`unrecoganized comparison operator ${attr}`);
455
+ }
456
+ }
457
+ }
458
+ translateEvaluation(attr, value, entity, alias, type, initialNumber, refAlias) {
459
+ switch (attr) {
460
+ case '$in':
461
+ case '$nin': {
462
+ const IN_OP = {
463
+ $in: 'in',
464
+ $nin: 'not in',
465
+ };
466
+ if (value instanceof Array) {
467
+ return {
468
+ stmt: this.translatePredicate(attr, value, type),
469
+ currentNumber: initialNumber,
470
+ };
471
+ }
472
+ else {
473
+ (0, assert_1.default)(false, '子查询已经改写为一对多的形式');
474
+ // sub query
475
+ /* const { stmt: subQueryStmt, currentNumber } = this.translateSelectInner(value.entity, value, initialNumber, refAlias, undefined);
476
+ return {
477
+ stmt: ` ${IN_OP[attr]}(${subQueryStmt})`,
478
+ currentNumber,
479
+ }; */
480
+ }
481
+ }
482
+ default: {
483
+ throw new Error(`${attr} is not evaluation predicate`);
484
+ }
485
+ }
486
+ }
487
+ translatePredicate(predicate, value, type) {
488
+ if (['$gt', '$gte', '$lt', '$lte', '$eq', '$ne', '$startsWith', '$endsWith', '$includes'].includes(predicate)) {
489
+ return this.translateComparison(predicate, value, type);
490
+ }
491
+ else if (['$in', '$nin'].includes(predicate)) {
492
+ (0, assert_1.default)(value instanceof Array);
493
+ const IN_OP = {
494
+ $in: 'in',
495
+ $nin: 'not in',
496
+ };
497
+ const values = value.map((v) => {
498
+ if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
499
+ return `'${v}'`;
500
+ }
501
+ else {
502
+ return `${v}`;
503
+ }
504
+ });
505
+ if (values.length > 0) {
506
+ return ` ${IN_OP[predicate]}(${values.join(',')})`;
507
+ }
508
+ if (predicate === '$in') {
509
+ return ' in (null)';
510
+ }
511
+ return ' is not null';
512
+ }
513
+ else if (predicate === '$between') {
514
+ const values = value.map((v) => {
515
+ if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
516
+ return `'${v}'`;
517
+ }
518
+ else {
519
+ return `${v}`;
520
+ }
521
+ });
522
+ // between是所有数据库都支持的语法吗?
523
+ return ` between ${values[0]} and ${values[1]}`;
524
+ }
525
+ else {
526
+ (0, assert_1.default)(predicate === '$exists');
527
+ if (value) {
528
+ return ' is not null';
529
+ }
530
+ return ' is null';
531
+ }
532
+ }
533
+ translateFilter(entity, filter, aliasDict, filterRefAlias, initialNumber, option) {
534
+ const { schema } = this;
535
+ let currentNumber = initialNumber;
536
+ const translateInner = (entity2, path, filter2, type) => {
537
+ const alias = aliasDict[path];
538
+ const { attributes } = schema[entity2];
539
+ let whereText = type ? '' : this.getDefaultSelectFilter(alias, option);
540
+ if (filter2) {
541
+ const attrs = Object.keys(filter2).filter(ele => !ele.startsWith('#'));
542
+ attrs.forEach((attr) => {
543
+ if (whereText) {
544
+ whereText += ' and ';
545
+ }
546
+ if (['$and', '$or', '$xor', '$not'].includes(attr)) {
547
+ whereText += '(';
548
+ switch (attr) {
549
+ case '$and':
550
+ case '$or':
551
+ case '$xor': {
552
+ const logicQueries = filter2[attr];
553
+ logicQueries.forEach((logicQuery, index) => {
554
+ const sql = translateInner(entity2, path, logicQuery, 'ref'); // 只要传个值就行了,应该无所谓
555
+ if (sql) {
556
+ whereText += ` (${sql})`;
557
+ if (index < logicQueries.length - 1) {
558
+ whereText += ` ${attr.slice(1)}`;
559
+ }
560
+ }
561
+ });
562
+ break;
563
+ }
564
+ default: {
565
+ (0, assert_1.default)(attr === '$not');
566
+ const logicQuery = filter2[attr];
567
+ const sql = translateInner(entity2, path, logicQuery, 'ref'); // 只要传个值就行了,应该无所谓
568
+ if (sql) {
569
+ whereText += ` not (${sql})`;
570
+ break;
571
+ }
572
+ }
573
+ }
574
+ whereText += ')';
575
+ }
576
+ else if (attr === '$text') {
577
+ whereText += `(${this.translateFullTextSearch(filter2[attr], entity2, alias)})`;
578
+ }
579
+ else if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
580
+ // expression
581
+ whereText += ` (${this.translateExpression(entity2, alias, filter2[attr], filterRefAlias)})`;
582
+ }
583
+ else {
584
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
585
+ if (rel === 2) {
586
+ whereText += ` (${translateInner(attr, `${path}${attr}/`, filter2[attr])})`;
587
+ }
588
+ else if (typeof rel === 'string') {
589
+ whereText += ` (${translateInner(rel, `${path}${attr}/`, filter2[attr])})`;
590
+ }
591
+ else if (rel instanceof Array) {
592
+ const [subEntity, foreignKey] = rel;
593
+ const predicate = (filter2[attr]['#sqp'] || 'in');
594
+ /**
595
+ *
596
+ * in代表外键连接后至少有一行数据
597
+ * not in代表外键连接后一行也不能有
598
+ * all代表反外键连接条件的一行也不能有(符合的是否至少要有一行?直觉上没这个限制)
599
+ * not all 代表反外键连接条件的至少有一行
600
+ *
601
+ * 目前将这种子查询翻译成了exists查询,当外表很大而子查询结果集很小时可能有性能问题,取决于MySQL执行器的能力
602
+ * by Xc 20230726
603
+ */
604
+ const refAlia = Object.keys(filterRefAlias).find(ele => filterRefAlias[ele][0] === alias);
605
+ const refAlia2 = refAlia || alias; // alias一定是唯一的,可以用来作为node id
606
+ if (!refAlia) {
607
+ (0, assert_1.default)(!filterRefAlias[refAlia2]);
608
+ Object.assign(filterRefAlias, {
609
+ [refAlia2]: [alias, entity2],
610
+ });
611
+ }
612
+ const fk = foreignKey || 'entityId';
613
+ const joinFilter = ['not in', 'in'].includes(predicate) ? {
614
+ $expr12: {
615
+ $eq: [
616
+ {
617
+ '#attr': fk,
618
+ },
619
+ {
620
+ '#refId': refAlia2,
621
+ '#refAttr': 'id',
622
+ }
623
+ ],
624
+ }
625
+ } : {
626
+ $expr12: {
627
+ $ne: [
628
+ {
629
+ '#attr': fk,
630
+ },
631
+ {
632
+ '#refId': refAlia2,
633
+ '#refAttr': 'id',
634
+ }
635
+ ],
636
+ }
637
+ };
638
+ if (!foreignKey) {
639
+ Object.assign(joinFilter, {
640
+ entity: entity2,
641
+ });
642
+ }
643
+ const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, {
644
+ data: {
645
+ id: 1,
646
+ },
647
+ filter: (0, filter_1.combineFilters)(subEntity, this.schema, [joinFilter, filter2[attr]]),
648
+ indexFrom: 0,
649
+ count: 1,
650
+ }, currentNumber, filterRefAlias, option);
651
+ currentNumber = ct2;
652
+ const PREDICATE_DICT = {
653
+ 'in': 'exists',
654
+ 'not in': 'not exists',
655
+ 'all': 'not exists',
656
+ 'not all': 'exists',
657
+ };
658
+ whereText += ` ${PREDICATE_DICT[predicate]} (${stmt})`;
659
+ }
660
+ else {
661
+ (0, assert_1.default)(attributes.hasOwnProperty(attr), `非法的属性${attr}`);
662
+ const { type: type2 } = attributes[attr];
663
+ // assert (type2 !== 'ref');
664
+ if (typeof filter2[attr] === 'object') {
665
+ if (['object', 'array'].includes(type2)) {
666
+ // 对object数据的深层次查询,这里调用数据库所支持的属性对象级查询,如mysql中的json查询
667
+ whereText += `(${this.translateObjectPredicate(filter2[attr], alias, attr)})`;
668
+ }
669
+ else {
670
+ (0, assert_1.default)(Object.keys(filter2[attr]).length === 1);
671
+ const predicate = Object.keys(filter2[attr])[0];
672
+ (0, assert_1.default)(predicate.startsWith('$'));
673
+ // 对属性上的谓词处理
674
+ whereText += ` (\`${alias}\`.\`${attr}\` ${this.translatePredicate(predicate, filter2[attr][predicate], type2)})`;
675
+ }
676
+ }
677
+ else {
678
+ whereText += ` (\`${alias}\`.\`${attr}\` = ${this.translateAttrValue(type2, filter2[attr])})`;
679
+ }
680
+ }
681
+ }
682
+ });
683
+ }
684
+ if (!whereText) {
685
+ whereText = 'true'; // 如果为空就赋一个永真条件,以便处理and
686
+ }
687
+ return whereText;
688
+ };
689
+ const where = translateInner(entity, './', filter);
690
+ return {
691
+ stmt: where,
692
+ currentNumber,
693
+ };
694
+ }
695
+ translateSorter(entity, sorter, aliasDict) {
696
+ const translateInner = (entity2, sortAttr, path) => {
697
+ (0, assert_1.default)(Object.keys(sortAttr).length === 1);
698
+ const attr = Object.keys(sortAttr)[0];
699
+ const alias = aliasDict[path];
700
+ if (attr.toLocaleLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
701
+ return this.translateExpression(entity2, alias, sortAttr[attr], {});
702
+ }
703
+ else if (sortAttr[attr] === 1) {
704
+ return `\`${alias}\`.\`${attr}\``;
705
+ }
706
+ else {
707
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
708
+ if (typeof rel === 'string') {
709
+ return translateInner(rel, sortAttr[attr], `${path}${attr}/`);
710
+ }
711
+ else {
712
+ (0, assert_1.default)(rel === 2);
713
+ return translateInner(attr, sortAttr[attr], `${path}${attr}/`);
714
+ }
715
+ }
716
+ };
717
+ let sortText = '';
718
+ sorter.forEach((sortNode, index) => {
719
+ const { $attr, $direction } = sortNode;
720
+ sortText += translateInner(entity, $attr, './');
721
+ if ($direction) {
722
+ sortText += ` ${$direction}`;
723
+ }
724
+ if (index < sorter.length - 1) {
725
+ sortText += ',';
726
+ }
727
+ });
728
+ return sortText;
729
+ }
730
+ translateProjection(entity, projection, aliasDict, projectionRefAlias, commonPrefix, disableAs) {
731
+ const { schema } = this;
732
+ let as = '';
733
+ const translateInner = (entity2, projection2, path) => {
734
+ const alias = aliasDict[path];
735
+ const { attributes } = schema[entity2];
736
+ let projText = '';
737
+ let prefix = path.slice(2).replace(/\//g, '.');
738
+ const attrs = Object.keys(projection2).filter((attr) => {
739
+ if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
740
+ return true;
741
+ }
742
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
743
+ return [1, 2].includes(rel) || typeof rel === 'string';
744
+ });
745
+ attrs.forEach((attr, idx) => {
746
+ const prefix2 = commonPrefix ? `${commonPrefix}.${prefix}` : prefix;
747
+ if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
748
+ const exprText = this.translateExpression(entity2, alias, projection2[attr], projectionRefAlias);
749
+ if (disableAs) {
750
+ projText += ` ${exprText}`;
751
+ }
752
+ else {
753
+ projText += ` ${exprText} as \`${prefix2}${attr}\``;
754
+ if (!as) {
755
+ as = `\`${prefix2}${attr}\``;
756
+ }
757
+ else {
758
+ as += `, \`${prefix2}${attr}\``;
759
+ }
760
+ }
761
+ }
762
+ else {
763
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
764
+ if (typeof rel === 'string') {
765
+ projText += translateInner(rel, projection2[attr], `${path}${attr}/`);
766
+ }
767
+ else if (rel === 2) {
768
+ projText += translateInner(attr, projection2[attr], `${path}${attr}/`);
769
+ }
770
+ else if (rel === 1) {
771
+ const { type } = attributes[attr];
772
+ if (projection2[attr] === 1) {
773
+ if (disableAs) {
774
+ projText += ` ${this.translateAttrProjection(type, alias, attr)}`;
775
+ }
776
+ else {
777
+ projText += ` ${this.translateAttrProjection(type, alias, attr)} as \`${prefix2}${attr}\``;
778
+ if (!as) {
779
+ as = `\`${prefix2}${attr}\``;
780
+ }
781
+ else {
782
+ as += `, \`${prefix2}${attr}\``;
783
+ }
784
+ }
785
+ }
786
+ else if (typeof projection2[attr] === 'object') {
787
+ // 对JSON对象的取值
788
+ (0, assert_1.default)(!disableAs);
789
+ (0, assert_1.default)(['object', 'array'].includes(type));
790
+ projText += ` ${this.translateObjectProjection(projection2[attr], alias, attr, prefix2)}`;
791
+ }
792
+ else {
793
+ (0, assert_1.default)(typeof projection2 === 'string');
794
+ if (disableAs) {
795
+ projText += ` ${this.translateAttrProjection(type, alias, attr)}`;
796
+ }
797
+ else {
798
+ projText += ` ${this.translateAttrProjection(type, alias, attr)} as \`${prefix2}${projection2[attr]}\``;
799
+ if (!as) {
800
+ as = `\`${prefix2}${projection2[attr]}\``;
801
+ }
802
+ else {
803
+ as += `\`${prefix2}${projection2[attr]}\``;
804
+ }
805
+ }
806
+ }
807
+ }
808
+ }
809
+ if (idx < attrs.length - 1) {
810
+ projText += ',';
811
+ }
812
+ });
813
+ return projText;
814
+ };
815
+ return {
816
+ projText: translateInner(entity, projection, './'),
817
+ as,
818
+ };
819
+ }
820
+ translateSelectInner(entity, selection, initialNumber, refAlias, option) {
821
+ const { data, filter, sorter, indexFrom, count } = selection;
822
+ const { from: fromText, aliasDict, projectionRefAlias, filterRefAlias, currentNumber } = this.analyzeJoin(entity, {
823
+ projection: data,
824
+ filter,
825
+ sorter,
826
+ }, initialNumber);
827
+ (0, assert_1.default)((0, lodash_1.intersection)((0, lodash_1.keys)(refAlias), (0, lodash_1.keys)(filterRefAlias)).length === 0, 'filter中的#node结点定义有重复');
828
+ (0, lodash_1.assign)(refAlias, filterRefAlias);
829
+ const { projText } = this.translateProjection(entity, data, aliasDict, projectionRefAlias);
830
+ const { stmt: filterText, currentNumber: currentNumber2 } = this.translateFilter(entity, filter, aliasDict, refAlias, currentNumber, option);
831
+ const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
832
+ return {
833
+ stmt: this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, undefined, indexFrom, count, option, selection),
834
+ currentNumber: currentNumber2,
835
+ filterStmt: filterText,
836
+ };
837
+ }
838
+ translateSelect(entity, selection, option) {
839
+ const { stmt } = this.translateSelectInner(entity, selection, 1, {}, option);
840
+ return stmt;
841
+ }
842
+ translateWhere(entity, selection, option) {
843
+ const { filterStmt } = this.translateSelectInner(entity, selection, 1, {}, option);
844
+ return filterStmt;
845
+ }
846
+ translateAggregate(entity, aggregation, option) {
847
+ const { data, filter, sorter, indexFrom, count } = aggregation;
848
+ const { from: fromText, aliasDict, projectionRefAlias, filterRefAlias, currentNumber } = this.analyzeJoin(entity, {
849
+ aggregation: data,
850
+ filter,
851
+ sorter,
852
+ }, 1);
853
+ let projText = '';
854
+ let groupByText = '';
855
+ for (const k in data) {
856
+ if (k === '#aggr') {
857
+ const { projText: projSubText, as } = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, '#data');
858
+ if (!projText) {
859
+ projText = projSubText;
860
+ }
861
+ else {
862
+ projText += `, ${projSubText}`;
863
+ }
864
+ groupByText = as;
865
+ }
866
+ else {
867
+ const { projText: projSubText } = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, undefined, true);
868
+ let projSubText2 = '';
869
+ if (k.startsWith('#max')) {
870
+ projSubText2 = `max(${projSubText}) as \`${k}\``;
871
+ }
872
+ else if (k.startsWith('#min')) {
873
+ projSubText2 = `min(${projSubText}) as \`${k}\``;
874
+ }
875
+ else if (k.startsWith('#count')) {
876
+ projSubText2 = `count(${projSubText}) as \`${k}\``;
877
+ }
878
+ else if (k.startsWith('#sum')) {
879
+ projSubText2 = `sum(${projSubText}) as \`${k}\``;
880
+ }
881
+ else {
882
+ (0, assert_1.default)(k.startsWith('#avg'));
883
+ projSubText2 = `avg(${projSubText}) as \`${k}\``;
884
+ }
885
+ if (!projText) {
886
+ projText = projSubText2;
887
+ }
888
+ else {
889
+ projText += `, ${projSubText2}`;
890
+ }
891
+ }
892
+ }
893
+ const { stmt: filterText } = this.translateFilter(entity, filter, aliasDict, {}, currentNumber, option);
894
+ const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
895
+ return this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, groupByText, indexFrom, count, option, undefined, aggregation);
896
+ }
897
+ translateCount(entity, selection, option) {
898
+ const { filter, count } = selection;
899
+ const { from: fromText, aliasDict, filterRefAlias, currentNumber } = this.analyzeJoin(entity, {
900
+ filter,
901
+ });
902
+ const projText = 'count(1) cnt';
903
+ const { stmt: filterText } = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, option);
904
+ if (count && count > 0) {
905
+ const subQuerySql = this.populateSelectStmt('1', fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, Object.assign({}, selection, { indexFrom: 0, count }));
906
+ return `select count(1) cnt from (${subQuerySql}) __tmp`;
907
+ }
908
+ return this.populateSelectStmt(projText, fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, selection);
909
+ }
910
+ translateRemove(entity, operation, option) {
911
+ const { data, filter, sorter, indexFrom, count } = operation;
912
+ (0, assert_1.default)(!sorter, '当前remove不支持sorter行为');
913
+ const { aliasDict, filterRefAlias, from: fromText, currentNumber } = this.analyzeJoin(entity, { filter, sorter });
914
+ const alias = aliasDict['./'];
915
+ const { stmt: filterText } = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, { includedDeleted: true });
916
+ // const sorterText = sorter && sorter.length > 0 ? this.translateSorter(entity, sorter, aliasDict) : undefined;
917
+ const { attributes } = this.schema[entity];
918
+ let updateText = '';
919
+ for (const attr in data) {
920
+ if (updateText) {
921
+ updateText += ',';
922
+ }
923
+ // delete只支持对volatile trigger的metadata域赋值
924
+ (0, assert_1.default)([types_1.TriggerDataAttribute, types_1.TriggerUuidAttribute].includes(attr));
925
+ const value = this.translateAttrValue(attributes[attr].type, data[attr]);
926
+ updateText += `\`${alias}\`.\`${attr}\` = ${value}`;
927
+ }
928
+ return this.populateRemoveStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
929
+ }
930
+ translateUpdate(entity, operation, option) {
931
+ const { attributes } = this.schema[entity];
932
+ const { filter, sorter, indexFrom, count, data } = operation;
933
+ (0, assert_1.default)(!sorter, '当前update不支持sorter行为');
934
+ const { aliasDict, filterRefAlias, from: fromText, currentNumber } = this.analyzeJoin(entity, { filter, sorter });
935
+ const alias = aliasDict['./'];
936
+ let updateText = '';
937
+ for (const attr in data) {
938
+ if (updateText) {
939
+ updateText += ',';
940
+ }
941
+ (0, assert_1.default)(attributes.hasOwnProperty(attr));
942
+ const value = this.translateAttrValue(attributes[attr].type, data[attr]);
943
+ updateText += `\`${alias}\`.\`${attr}\` = ${value}`;
944
+ }
945
+ const { stmt: filterText } = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, option);
946
+ // const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
947
+ return this.populateUpdateStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
948
+ }
949
+ translateDestroyEntity(entity, truncate) {
950
+ const { schema } = this;
951
+ const { storageName = entity, view } = schema[entity];
952
+ let sql;
953
+ if (view) {
954
+ sql = `drop view if exists \`${storageName}\``;
955
+ }
956
+ else {
957
+ sql = truncate ? `truncate table \`${storageName}\`` : `drop table if exists \`${storageName}\``;
958
+ }
959
+ return sql;
960
+ }
961
+ escapeStringValue(value) {
962
+ const result = sqlstring_1.default.escape(value);
963
+ return result;
964
+ }
965
+ }
966
+ exports.SqlTranslator = SqlTranslator;