oak-db 3.3.11 → 3.3.13
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 +50 -37
- package/lib/MySQL/store.js +430 -308
- package/lib/MySQL/translator.d.ts +114 -107
- package/lib/MySQL/translator.js +307 -67
- package/lib/MySQL/types/Configuration.d.ts +12 -12
- package/lib/MySQL/types/Configuration.js +2 -2
- package/lib/PostgreSQL/connector.d.ts +27 -0
- package/lib/PostgreSQL/connector.js +147 -0
- package/lib/PostgreSQL/store.d.ts +50 -0
- package/lib/PostgreSQL/store.js +527 -0
- package/lib/PostgreSQL/translator.d.ts +103 -0
- package/lib/PostgreSQL/translator.js +2159 -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 +1034 -999
- 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 +32 -0
- package/lib/types/dbStore.js +3 -0
- package/package.json +6 -5
package/lib/MySQL/translator.js
CHANGED
|
@@ -119,21 +119,21 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
119
119
|
// numeric types
|
|
120
120
|
"bit",
|
|
121
121
|
"int",
|
|
122
|
-
"integer",
|
|
122
|
+
"integer", // synonym for int
|
|
123
123
|
"tinyint",
|
|
124
124
|
"smallint",
|
|
125
125
|
"mediumint",
|
|
126
126
|
"bigint",
|
|
127
127
|
"float",
|
|
128
128
|
"double",
|
|
129
|
-
"double precision",
|
|
130
|
-
"real",
|
|
129
|
+
"double precision", // synonym for double
|
|
130
|
+
"real", // synonym for double
|
|
131
131
|
"decimal",
|
|
132
|
-
"dec",
|
|
133
|
-
"numeric",
|
|
134
|
-
"fixed",
|
|
135
|
-
"bool",
|
|
136
|
-
"boolean",
|
|
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
137
|
// date and time types
|
|
138
138
|
"date",
|
|
139
139
|
"datetime",
|
|
@@ -142,10 +142,10 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
142
142
|
"year",
|
|
143
143
|
// string types
|
|
144
144
|
"char",
|
|
145
|
-
"nchar",
|
|
145
|
+
"nchar", // synonym for national char
|
|
146
146
|
"national char",
|
|
147
147
|
"varchar",
|
|
148
|
-
"nvarchar",
|
|
148
|
+
"nvarchar", // synonym for national varchar
|
|
149
149
|
"national varchar",
|
|
150
150
|
"blob",
|
|
151
151
|
"text",
|
|
@@ -266,14 +266,18 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
266
266
|
return 'text ';
|
|
267
267
|
}
|
|
268
268
|
if (type === 'ref') {
|
|
269
|
-
return 'char(36)';
|
|
269
|
+
return 'char(36) ';
|
|
270
|
+
}
|
|
271
|
+
if (['bool', 'boolean'].includes(type)) {
|
|
272
|
+
// MySQL读出来就是tinyint(1)
|
|
273
|
+
return 'tinyint(1) ';
|
|
270
274
|
}
|
|
271
275
|
if (type === 'money') {
|
|
272
|
-
return 'bigint';
|
|
276
|
+
return 'bigint ';
|
|
273
277
|
}
|
|
274
278
|
if (type === 'enum') {
|
|
275
279
|
(0, assert_1.default)(enumeration);
|
|
276
|
-
return `enum(${enumeration.map(ele => `'${ele}'`).join(',')})`;
|
|
280
|
+
return `enum(${enumeration.map(ele => `'${ele}'`).join(',')}) `;
|
|
277
281
|
}
|
|
278
282
|
if (MySqlTranslator.withLengthDataTypes.includes(type)) {
|
|
279
283
|
if (params) {
|
|
@@ -291,34 +295,34 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
291
295
|
if (typeof scale === 'number') {
|
|
292
296
|
return `${type}(${precision}, ${scale}) `;
|
|
293
297
|
}
|
|
294
|
-
return `${type}(${precision})`;
|
|
298
|
+
return `${type}(${precision}) `;
|
|
295
299
|
}
|
|
296
300
|
else {
|
|
297
301
|
const { precision, scale } = MySqlTranslator.dataTypeDefaults[type];
|
|
298
302
|
if (typeof scale === 'number') {
|
|
299
303
|
return `${type}(${precision}, ${scale}) `;
|
|
300
304
|
}
|
|
301
|
-
return `${type}(${precision})`;
|
|
305
|
+
return `${type}(${precision}) `;
|
|
302
306
|
}
|
|
303
307
|
}
|
|
304
308
|
if (MySqlTranslator.withWidthDataTypes.includes(type)) {
|
|
305
309
|
(0, assert_1.default)(type === 'int');
|
|
306
|
-
const { width } = params;
|
|
310
|
+
const { width } = params || { width: 4 };
|
|
307
311
|
switch (width) {
|
|
308
312
|
case 1: {
|
|
309
|
-
return 'tinyint';
|
|
313
|
+
return 'tinyint ';
|
|
310
314
|
}
|
|
311
315
|
case 2: {
|
|
312
|
-
return 'smallint';
|
|
316
|
+
return 'smallint ';
|
|
313
317
|
}
|
|
314
318
|
case 3: {
|
|
315
|
-
return 'mediumint';
|
|
319
|
+
return 'mediumint ';
|
|
316
320
|
}
|
|
317
321
|
case 4: {
|
|
318
|
-
return 'int';
|
|
322
|
+
return 'int ';
|
|
319
323
|
}
|
|
320
324
|
default: {
|
|
321
|
-
return 'bigint';
|
|
325
|
+
return 'bigint ';
|
|
322
326
|
}
|
|
323
327
|
}
|
|
324
328
|
}
|
|
@@ -553,6 +557,28 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
553
557
|
const columns2 = attributes.map(({ name }) => `${alias}.${name}`);
|
|
554
558
|
return ` match(${columns2.join(',')}) against ('${$search}' in natural language mode)`;
|
|
555
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
|
+
}
|
|
556
582
|
translateCreateEntity(entity, options) {
|
|
557
583
|
const ifExists = options?.ifExists || 'drop';
|
|
558
584
|
const { schema } = this;
|
|
@@ -578,32 +604,14 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
578
604
|
sql += '(';
|
|
579
605
|
// 翻译所有的属性
|
|
580
606
|
Object.keys(attributes).forEach((attr, idx) => {
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
sql += this.populateDataTypeDef(type, params, enumeration);
|
|
585
|
-
if (notNull || type === 'geometry') {
|
|
586
|
-
sql += ' not null ';
|
|
587
|
-
}
|
|
588
|
-
if (unique) {
|
|
589
|
-
sql += ' unique ';
|
|
590
|
-
}
|
|
591
|
-
if (sequenceStart) {
|
|
592
|
-
if (hasSequence) {
|
|
593
|
-
throw new Error(`「${entity}」只能有一个sequence列`);
|
|
594
|
-
}
|
|
595
|
-
hasSequence = sequenceStart;
|
|
596
|
-
sql += ' auto_increment unique ';
|
|
597
|
-
}
|
|
598
|
-
if (defaultValue !== undefined) {
|
|
599
|
-
(0, assert_1.default)(type !== 'ref');
|
|
600
|
-
sql += ` default ${this.translateAttrValue(type, defaultValue)}`;
|
|
607
|
+
const attrSql = this.translateAttributeDef(attr, attributes[attr]);
|
|
608
|
+
if (idx !== 0) {
|
|
609
|
+
sql += ', ';
|
|
601
610
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
sql += ',\n';
|
|
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;
|
|
607
615
|
}
|
|
608
616
|
});
|
|
609
617
|
// 翻译索引信息
|
|
@@ -621,12 +629,11 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
621
629
|
else if (type === 'spatial') {
|
|
622
630
|
sql += ' spatial ';
|
|
623
631
|
}
|
|
624
|
-
sql += `index
|
|
632
|
+
sql += `index \`${name}\` `;
|
|
625
633
|
if (type === 'hash') {
|
|
626
634
|
sql += ` using hash `;
|
|
627
635
|
}
|
|
628
636
|
sql += '(';
|
|
629
|
-
let includeDeleteAt = false;
|
|
630
637
|
attributes.forEach(({ name, size, direction }, idx2) => {
|
|
631
638
|
sql += `\`${name}\``;
|
|
632
639
|
if (size) {
|
|
@@ -636,15 +643,9 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
636
643
|
sql += ` ${direction}`;
|
|
637
644
|
}
|
|
638
645
|
if (idx2 < attributes.length - 1) {
|
|
639
|
-
sql += ',';
|
|
640
|
-
}
|
|
641
|
-
if (name === '$$deleteAt$$') {
|
|
642
|
-
includeDeleteAt = true;
|
|
646
|
+
sql += ', ';
|
|
643
647
|
}
|
|
644
648
|
});
|
|
645
|
-
if (!includeDeleteAt && !type) {
|
|
646
|
-
sql += ', `$$deleteAt$$`'; // 在mysql80+之后,需要给属性加上``包裹,否则会报错
|
|
647
|
-
}
|
|
648
649
|
sql += ')';
|
|
649
650
|
if (parser) {
|
|
650
651
|
sql += ` with parser ${parser}`;
|
|
@@ -796,10 +797,11 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
796
797
|
case '$dayOfYear': {
|
|
797
798
|
return 'DAYOFYEAR(%s)';
|
|
798
799
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
800
|
+
// 这个实现有问题,DATEDIFF只是计算两个日期之间的天数差,只接受两个参数,放在translateExperession里实现
|
|
801
|
+
// case '$dateDiff': {
|
|
802
|
+
// assert(argumentNumber === 3);
|
|
803
|
+
// return 'DATEDIFF(%s, %s, %s)';
|
|
804
|
+
// }
|
|
803
805
|
case '$contains': {
|
|
804
806
|
(0, assert_1.default)(argumentNumber === 2);
|
|
805
807
|
return 'ST_CONTAINS(%s, %s)';
|
|
@@ -816,6 +818,22 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
816
818
|
result += ')';
|
|
817
819
|
return result;
|
|
818
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
|
+
}
|
|
819
837
|
default: {
|
|
820
838
|
throw new Error(`unrecoganized function ${fnName}`);
|
|
821
839
|
}
|
|
@@ -854,15 +872,142 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
854
872
|
const refId = (expr)['#refId'];
|
|
855
873
|
const refAttr = (expr)['#refAttr'];
|
|
856
874
|
(0, assert_1.default)(refDict[refId]);
|
|
857
|
-
const
|
|
858
|
-
|
|
875
|
+
const [refAlias, refEntity] = refDict[refId];
|
|
876
|
+
const attrText = `\`${refAlias}\`.\`${refAttr}\``;
|
|
877
|
+
// 这里必须使用refEntity,否则在filter深层嵌套节点表达式时会出现entity不对应
|
|
878
|
+
result = this.translateAttrInExpression(refEntity, (expr)['#refAttr'], attrText);
|
|
859
879
|
}
|
|
860
880
|
else {
|
|
861
881
|
(0, assert_1.default)(k.length === 1);
|
|
862
|
-
|
|
863
|
-
|
|
882
|
+
const fnKey = k[0];
|
|
883
|
+
const fnArgs = (expr)[fnKey];
|
|
884
|
+
// 特殊处理日期相关函数
|
|
885
|
+
if (fnKey === '$dateDiff') {
|
|
886
|
+
// $dateDiff: [date1, date2, unit]
|
|
887
|
+
(0, assert_1.default)(fnArgs instanceof Array && fnArgs.length === 3);
|
|
888
|
+
const [date1Expr, date2Expr, unit] = fnArgs;
|
|
889
|
+
// 转换日期表达式
|
|
890
|
+
const translateDateArg = (arg) => {
|
|
891
|
+
if (arg instanceof Date) {
|
|
892
|
+
return `FROM_UNIXTIME(${arg.valueOf()} / 1000)`;
|
|
893
|
+
}
|
|
894
|
+
else if (typeof arg === 'number') {
|
|
895
|
+
return `FROM_UNIXTIME(${arg} / 1000)`;
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
return translateInner(arg);
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
const date1Str = translateDateArg(date1Expr);
|
|
902
|
+
const date2Str = translateDateArg(date2Expr);
|
|
903
|
+
// MySQL TIMESTAMPDIFF 单位映射
|
|
904
|
+
const unitMap = {
|
|
905
|
+
's': 'SECOND',
|
|
906
|
+
'm': 'MINUTE',
|
|
907
|
+
'h': 'HOUR',
|
|
908
|
+
'd': 'DAY',
|
|
909
|
+
'M': 'MONTH',
|
|
910
|
+
'y': 'YEAR'
|
|
911
|
+
};
|
|
912
|
+
const mysqlUnit = unitMap[unit];
|
|
913
|
+
if (!mysqlUnit) {
|
|
914
|
+
throw new Error(`Unsupported date diff unit: ${unit}`);
|
|
915
|
+
}
|
|
916
|
+
// TIMESTAMPDIFF(unit, date1, date2) 返回 date2 - date1
|
|
917
|
+
// 但类型定义是 date1 - date2,所以参数顺序要反过来
|
|
918
|
+
result = `TIMESTAMPDIFF(${mysqlUnit}, ${date2Str}, ${date1Str})`;
|
|
919
|
+
}
|
|
920
|
+
else if (fnKey === '$dateCeil') {
|
|
921
|
+
// $dateCeil: [date, unit]
|
|
922
|
+
(0, assert_1.default)(fnArgs instanceof Array && fnArgs.length === 2);
|
|
923
|
+
const [dateExpr, unit] = fnArgs;
|
|
924
|
+
const getTimestampExpr = (arg) => {
|
|
925
|
+
if (arg instanceof Date) {
|
|
926
|
+
return `${arg.valueOf()}`;
|
|
927
|
+
}
|
|
928
|
+
else if (typeof arg === 'number') {
|
|
929
|
+
return `${arg}`;
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
const k = Object.keys(arg);
|
|
933
|
+
if (k.includes('#attr')) {
|
|
934
|
+
return `\`${alias}\`.\`${arg['#attr']}\``;
|
|
935
|
+
}
|
|
936
|
+
else if (k.includes('#refId')) {
|
|
937
|
+
const refId = arg['#refId'];
|
|
938
|
+
const refAttr = arg['#refAttr'];
|
|
939
|
+
return `\`${refDict[refId][0]}\`.\`${refAttr}\``;
|
|
940
|
+
}
|
|
941
|
+
return translateInner(arg);
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
const tsExpr = getTimestampExpr(dateExpr);
|
|
945
|
+
const msPerUnit = {
|
|
946
|
+
's': 1000,
|
|
947
|
+
'm': 60000,
|
|
948
|
+
'h': 3600000,
|
|
949
|
+
'd': 86400000,
|
|
950
|
+
};
|
|
951
|
+
if (msPerUnit[unit]) {
|
|
952
|
+
// CEIL 向上取整
|
|
953
|
+
result = `CEIL(${tsExpr} / ${msPerUnit[unit]}) * ${msPerUnit[unit]}`;
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
(0, assert_1.default)(typeof unit === 'string', 'unit should be string');
|
|
957
|
+
console.warn('暂不支持 $dateCeil 对月年单位的处理');
|
|
958
|
+
throw new Error(`Unsupported date ceil unit: ${unit}`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
else if (fnKey === '$dateFloor') {
|
|
962
|
+
// $dateFloor: [date, unit]
|
|
963
|
+
(0, assert_1.default)(fnArgs instanceof Array && fnArgs.length === 2);
|
|
964
|
+
const [dateExpr, unit] = fnArgs;
|
|
965
|
+
// 获取毫秒时间戳表达式
|
|
966
|
+
const getTimestampExpr = (arg) => {
|
|
967
|
+
if (arg instanceof Date) {
|
|
968
|
+
return `${arg.valueOf()}`;
|
|
969
|
+
}
|
|
970
|
+
else if (typeof arg === 'number') {
|
|
971
|
+
return `${arg}`;
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
// 属性引用,直接返回属性(存储本身就是毫秒时间戳)
|
|
975
|
+
const k = Object.keys(arg);
|
|
976
|
+
if (k.includes('#attr')) {
|
|
977
|
+
return `\`${alias}\`.\`${arg['#attr']}\``;
|
|
978
|
+
}
|
|
979
|
+
else if (k.includes('#refId')) {
|
|
980
|
+
const refId = arg['#refId'];
|
|
981
|
+
const refAttr = arg['#refAttr'];
|
|
982
|
+
return `\`${refDict[refId][0]}\`.\`${refAttr}\``;
|
|
983
|
+
}
|
|
984
|
+
// 其他表达式递归处理
|
|
985
|
+
return translateInner(arg);
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
const tsExpr = getTimestampExpr(dateExpr);
|
|
989
|
+
// 固定间隔单位:直接用时间戳数学运算
|
|
990
|
+
const msPerUnit = {
|
|
991
|
+
's': 1000,
|
|
992
|
+
'm': 60000,
|
|
993
|
+
'h': 3600000,
|
|
994
|
+
'd': 86400000,
|
|
995
|
+
};
|
|
996
|
+
if (msPerUnit[unit]) {
|
|
997
|
+
// FLOOR(timestamp / interval) * interval
|
|
998
|
+
result = `FLOOR(${tsExpr} / ${msPerUnit[unit]}) * ${msPerUnit[unit]}`;
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
(0, assert_1.default)(typeof unit === 'string', 'unit should be string');
|
|
1002
|
+
console.warn('暂不支持 $dateFloor 对月年单位的处理');
|
|
1003
|
+
throw new Error(`Unsupported date floor unit: ${unit}`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
else if (fnArgs instanceof Array) {
|
|
1007
|
+
// 原有的数组参数处理逻辑
|
|
1008
|
+
const fnName = this.translateFnName(fnKey, fnArgs.length);
|
|
864
1009
|
const args = [fnName];
|
|
865
|
-
args.push(...
|
|
1010
|
+
args.push(...fnArgs.map((ele) => {
|
|
866
1011
|
if (['string', 'number'].includes(typeof ele) || ele instanceof Date) {
|
|
867
1012
|
return translateConstant(ele);
|
|
868
1013
|
}
|
|
@@ -873,9 +1018,10 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
873
1018
|
result = util_1.format.apply(null, args);
|
|
874
1019
|
}
|
|
875
1020
|
else {
|
|
876
|
-
|
|
1021
|
+
// 原有的单参数处理逻辑
|
|
1022
|
+
const fnName = this.translateFnName(fnKey, 1);
|
|
877
1023
|
const args = [fnName];
|
|
878
|
-
const arg =
|
|
1024
|
+
const arg = fnArgs;
|
|
879
1025
|
if (['string', 'number'].includes(typeof arg) || arg instanceof Date) {
|
|
880
1026
|
args.push(translateConstant(arg));
|
|
881
1027
|
}
|
|
@@ -949,7 +1095,7 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
949
1095
|
}
|
|
950
1096
|
// 新的remove应该包含$$deleteAt$$的值了
|
|
951
1097
|
/* const now = Date.now();
|
|
952
|
-
|
|
1098
|
+
|
|
953
1099
|
const updateText2 = updateText ? `${updateText}, \`${alias}\`.\`$$deleteAt$$\` = '${now}'` : `\`${alias}\`.\`$$deleteAt$$\` = '${now}'`; */
|
|
954
1100
|
(0, assert_1.default)(updateText.includes(types_1.DeleteAtAttribute));
|
|
955
1101
|
let sql = `update ${fromText} set ${updateText}`;
|
|
@@ -965,5 +1111,99 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
|
|
|
965
1111
|
}
|
|
966
1112
|
return sql;
|
|
967
1113
|
}
|
|
1114
|
+
/**
|
|
1115
|
+
* 将MySQL返回的Type回译成oak的类型,是 populateDataTypeDef 的反函数
|
|
1116
|
+
* @param type
|
|
1117
|
+
*/
|
|
1118
|
+
reTranslateToAttribute(type) {
|
|
1119
|
+
const withLengthDataTypes = MySqlTranslator.withLengthDataTypes.join('|');
|
|
1120
|
+
let result = (new RegExp(`^(${withLengthDataTypes})\\((\\d+)\\)$`)).exec(type);
|
|
1121
|
+
if (result) {
|
|
1122
|
+
return {
|
|
1123
|
+
type: result[1],
|
|
1124
|
+
params: {
|
|
1125
|
+
length: parseInt(result[2]),
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
const withPrecisionDataTypes = MySqlTranslator.withPrecisionDataTypes.join('|');
|
|
1130
|
+
result = (new RegExp(`^(${withPrecisionDataTypes})\\((\\d+),(d+)\\)$`)).exec(type);
|
|
1131
|
+
if (result) {
|
|
1132
|
+
return {
|
|
1133
|
+
type: result[1],
|
|
1134
|
+
params: {
|
|
1135
|
+
precision: parseInt(result[2]),
|
|
1136
|
+
scale: parseInt(result[3]),
|
|
1137
|
+
},
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
result = (/^enum\((\S+)\)$/).exec(type);
|
|
1141
|
+
if (result) {
|
|
1142
|
+
const enumeration = result[1].split(',').map(ele => ele.slice(1, -1));
|
|
1143
|
+
return {
|
|
1144
|
+
type: 'enum',
|
|
1145
|
+
enumeration
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
return {
|
|
1149
|
+
type: type,
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
// 分析当前数据库结构图
|
|
1153
|
+
async readSchema(execFn) {
|
|
1154
|
+
const result = {};
|
|
1155
|
+
const sql = 'show tables;';
|
|
1156
|
+
const [tables] = await execFn(sql);
|
|
1157
|
+
for (const tableItem of tables) {
|
|
1158
|
+
const table = Object.values(tableItem)[0];
|
|
1159
|
+
const [tableResult] = await execFn(`desc \`${table}\``);
|
|
1160
|
+
const attributes = {};
|
|
1161
|
+
for (const attrItem of tableResult) {
|
|
1162
|
+
const { Field: attrName, Null: isNull, Type: type, Key: key } = attrItem;
|
|
1163
|
+
attributes[attrName] = {
|
|
1164
|
+
...this.reTranslateToAttribute(type),
|
|
1165
|
+
notNull: isNull.toUpperCase() === 'NO',
|
|
1166
|
+
unique: key.toUpperCase() === 'UNI',
|
|
1167
|
+
};
|
|
1168
|
+
// 自增列只可能是seq
|
|
1169
|
+
if (attrName === '$$seq$$') {
|
|
1170
|
+
attributes[attrName].sequenceStart = 10000;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
Object.assign(result, {
|
|
1174
|
+
[table]: {
|
|
1175
|
+
attributes,
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
const [indexedColumns] = (await execFn(`show index from \`${table}\``));
|
|
1179
|
+
if (indexedColumns.length) {
|
|
1180
|
+
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');
|
|
1181
|
+
const indexes = Object.values(groupedColumns).map((ele) => {
|
|
1182
|
+
const index = {
|
|
1183
|
+
name: ele[0].Key_name,
|
|
1184
|
+
attributes: ele.map(ele2 => ({
|
|
1185
|
+
name: ele2.Column_name,
|
|
1186
|
+
direction: ele2.Collation === 'D' ? 'DESC' : (ele2.Collation === 'A' ? 'ASC' : undefined),
|
|
1187
|
+
size: ele2.Sub_part || undefined,
|
|
1188
|
+
})),
|
|
1189
|
+
};
|
|
1190
|
+
if (ele[0].Non_unique === 0 || ele[0].Index_type.toUpperCase() !== 'BTREE') {
|
|
1191
|
+
index.config = {};
|
|
1192
|
+
if (ele[0].Non_unique === 0) {
|
|
1193
|
+
index.config.unique = true;
|
|
1194
|
+
}
|
|
1195
|
+
if (ele[0].Index_type.toUpperCase() !== 'BTREE') {
|
|
1196
|
+
index.config.type = ele[0].Index_type.toLowerCase();
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
return index;
|
|
1200
|
+
});
|
|
1201
|
+
Object.assign(result[table], {
|
|
1202
|
+
indexes,
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return result;
|
|
1207
|
+
}
|
|
968
1208
|
}
|
|
969
1209
|
exports.MySqlTranslator = MySqlTranslator;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export type MySQLConfiguration = {
|
|
2
|
-
host: string;
|
|
3
|
-
user: string;
|
|
4
|
-
password: string;
|
|
5
|
-
database: string;
|
|
6
|
-
charset: 'utf8mb4_general_ci';
|
|
7
|
-
connectionLimit: number;
|
|
8
|
-
port?: number;
|
|
9
|
-
};
|
|
10
|
-
export type Configuration = {
|
|
11
|
-
mysql: MySQLConfiguration;
|
|
12
|
-
};
|
|
1
|
+
export type MySQLConfiguration = {
|
|
2
|
+
host: string;
|
|
3
|
+
user: string;
|
|
4
|
+
password: string;
|
|
5
|
+
database: string;
|
|
6
|
+
charset: 'utf8mb4_general_ci';
|
|
7
|
+
connectionLimit: number;
|
|
8
|
+
port?: number;
|
|
9
|
+
};
|
|
10
|
+
export type Configuration = {
|
|
11
|
+
mysql: MySQLConfiguration;
|
|
12
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Pool, PoolClient, QueryResult, QueryResultRow } from 'pg';
|
|
2
|
+
import { TxnOption } from 'oak-domain/lib/types';
|
|
3
|
+
import { PostgreSQLConfiguration } from './types/Configuration';
|
|
4
|
+
export declare class PostgreSQLConnector {
|
|
5
|
+
pool: Pool;
|
|
6
|
+
configuration: PostgreSQLConfiguration;
|
|
7
|
+
txnDict: Record<string, PoolClient>;
|
|
8
|
+
constructor(configuration: PostgreSQLConfiguration);
|
|
9
|
+
connect(): void;
|
|
10
|
+
disconnect(): Promise<void>;
|
|
11
|
+
startTransaction(option?: TxnOption): Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* 映射隔离级别到 PostgreSQL 语法
|
|
14
|
+
*/
|
|
15
|
+
private mapIsolationLevel;
|
|
16
|
+
exec(sql: string, txn?: string): Promise<[QueryResultRow[], QueryResult]>;
|
|
17
|
+
commitTransaction(txn: string): Promise<void>;
|
|
18
|
+
rollbackTransaction(txn: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* 获取连接池状态
|
|
21
|
+
*/
|
|
22
|
+
getPoolStatus(): {
|
|
23
|
+
total: number;
|
|
24
|
+
idle: number;
|
|
25
|
+
waiting: number;
|
|
26
|
+
};
|
|
27
|
+
}
|