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.
@@ -0,0 +1,13 @@
1
+ export type PostgreSQLConfiguration = {
2
+ host: string;
3
+ user: string;
4
+ password: string;
5
+ database: string;
6
+ port?: number;
7
+ max?: number;
8
+ idleTimeoutMillis?: number;
9
+ connectionTimeoutMillis?: number;
10
+ };
11
+ export type Configuration = {
12
+ postgresql: PostgreSQLConfiguration;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/lib/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
- export * from './MySQL/store';
2
- export { MySqlSelectOption, MysqlOperateOption } from './MySQL/translator';
1
+ export * from './MySQL/store';
2
+ export { MySqlSelectOption, MysqlOperateOption } from './MySQL/translator';
3
+ export * from './PostgreSQL/store';
4
+ export { PostgreSQLSelectOption, PostgreSQLOperateOption } from './PostgreSQL/translator';
package/lib/index.js CHANGED
@@ -1,4 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./MySQL/store"), exports);
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./MySQL/store"), exports);
5
+ tslib_1.__exportStar(require("./PostgreSQL/store"), exports);
@@ -1,55 +1,68 @@
1
- import { EntityDict, OperateOption, Q_FullTextValue, Ref, RefOrExpression, SelectOption, StorageSchema } from "oak-domain/lib/types";
2
- import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
3
- import { DataType } from "oak-domain/lib/types/schema/DataTypes";
4
- import { CreateEntityOption } from './types/Translator';
5
- export interface SqlSelectOption extends SelectOption {
6
- }
7
- export interface SqlOperateOption extends OperateOption {
8
- }
9
- export declare abstract class SqlTranslator<ED extends EntityDict & BaseEntityDict> {
10
- readonly schema: StorageSchema<ED>;
11
- constructor(schema: StorageSchema<ED>);
12
- private makeFullSchema;
13
- protected abstract getDefaultSelectFilter<OP extends SqlSelectOption>(alias: string, option?: OP): string;
14
- protected abstract translateAttrProjection(dataType: DataType, alias: string, attr: string): string;
15
- protected abstract translateObjectProjection(projection: Record<string, any>, alias: string, attr: string, prefix: string): string;
16
- protected abstract translateAttrValue(dataType: DataType | Ref, value: any): string;
17
- protected abstract translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
18
- abstract translateCreateEntity<T extends keyof ED>(entity: T, option: CreateEntityOption): string[];
19
- protected abstract translateObjectPredicate(predicate: Record<string, any>, alias: string, attr: string): string;
20
- protected abstract populateSelectStmt<T extends keyof ED, OP extends SqlSelectOption>(projectionText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, groupByText?: string, indexFrom?: number, count?: number, option?: OP, selection?: ED[T]['Selection'], aggregation?: ED[T]['Aggregation']): string;
21
- protected abstract populateUpdateStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
22
- protected abstract populateRemoveStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
23
- protected abstract translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, [string, keyof ED]>): string;
24
- private getStorageName;
25
- translateInsert<T extends keyof ED>(entity: T, data: ED[T]['CreateMulti']['data']): string;
26
- /**
27
- * analyze the join relations in projection/query/sort
28
- * 所有的层次关系都当成left join处理,如果有内表为空的情况,请手动处理
29
- * {
30
- * b: {
31
- * name: {
32
- * $exists: false,
33
- * }
34
- * }
35
- * }
36
- * 这样的query会把内表为空的行也返回
37
- * @param param0
38
- */
39
- private analyzeJoin;
40
- private translateComparison;
41
- private translateEvaluation;
42
- protected translatePredicate(predicate: string, value: any, type?: DataType | Ref): string;
43
- private translateFilter;
44
- private translateSorter;
45
- private translateProjection;
46
- private translateSelectInner;
47
- translateSelect<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], option?: OP): string;
48
- translateWhere<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], option?: OP): string;
49
- translateAggregate<T extends keyof ED, OP extends SqlSelectOption>(entity: T, aggregation: ED[T]['Aggregation'], option?: OP): string;
50
- translateCount<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, option?: OP): string;
51
- translateRemove<T extends keyof ED, OP extends SqlOperateOption>(entity: T, operation: ED[T]['Remove'], option?: OP): string;
52
- translateUpdate<T extends keyof ED, OP extends SqlOperateOption>(entity: T, operation: ED[T]['Update'], option?: OP): string;
53
- translateDestroyEntity(entity: string, truncate?: boolean): string;
54
- escapeStringValue(value: string): string;
55
- }
1
+ import { EntityDict, OperateOption, Q_FullTextValue, Ref, RefOrExpression, SelectOption, StorageSchema } from "oak-domain/lib/types";
2
+ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
3
+ import { DataType } from "oak-domain/lib/types/schema/DataTypes";
4
+ import { CreateEntityOption } from './types/Translator';
5
+ export interface SqlSelectOption extends SelectOption {
6
+ }
7
+ export interface SqlOperateOption extends OperateOption {
8
+ }
9
+ export declare abstract class SqlTranslator<ED extends EntityDict & BaseEntityDict> {
10
+ readonly schema: StorageSchema<ED>;
11
+ constructor(schema: StorageSchema<ED>);
12
+ private makeFullSchema;
13
+ protected abstract getDefaultSelectFilter<OP extends SqlSelectOption>(alias: string, option?: OP): string;
14
+ protected abstract translateAttrProjection(dataType: DataType, alias: string, attr: string): string;
15
+ protected abstract translateObjectProjection(projection: Record<string, any>, alias: string, attr: string, prefix: string): string;
16
+ protected abstract translateAttrValue(dataType: DataType | Ref, value: any): string;
17
+ protected abstract translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
18
+ abstract translateCreateEntity<T extends keyof ED>(entity: T, option: CreateEntityOption): string[];
19
+ protected abstract translateObjectPredicate(predicate: Record<string, any>, alias: string, attr: string): string;
20
+ protected abstract populateSelectStmt<T extends keyof ED, OP extends SqlSelectOption>(projectionText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, groupByText?: string, indexFrom?: number, count?: number, option?: OP, selection?: ED[T]['Selection'], aggregation?: ED[T]['Aggregation']): string;
21
+ protected abstract populateUpdateStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
22
+ protected abstract populateRemoveStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
23
+ protected abstract translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, [string, keyof ED]>): string;
24
+ protected getStorageName<T extends keyof ED>(entity: T): string;
25
+ translateInsert<T extends keyof ED>(entity: T, data: ED[T]['CreateMulti']['data']): string;
26
+ /**
27
+ * analyze the join relations in projection/query/sort
28
+ * 所有的层次关系都当成left join处理,如果有内表为空的情况,请手动处理
29
+ * {
30
+ * b: {
31
+ * name: {
32
+ * $exists: false,
33
+ * }
34
+ * }
35
+ * }
36
+ * 这样的query会把内表为空的行也返回
37
+ * @param param0
38
+ */
39
+ private analyzeJoin;
40
+ /**
41
+ * 对like模式中的特殊字符进行转义
42
+ * 例如 % _,以防止被当成通配符处理
43
+ * @param pattern like模式字符串
44
+ * @returns 转义后的字符串
45
+ */
46
+ escapeLikePattern(pattern: string): string;
47
+ private translateComparison;
48
+ private translateEvaluation;
49
+ protected translatePredicate(predicate: string, value: any, type?: DataType | Ref): string;
50
+ protected translateFilter<T extends keyof ED, OP extends SqlSelectOption>(entity: T, filter: ED[T]['Selection']['filter'], aliasDict: Record<string, string>, filterRefAlias: Record<string, [string, keyof ED]>, initialNumber: number, option?: OP): {
51
+ stmt: string;
52
+ currentNumber: number;
53
+ };
54
+ private translateSorter;
55
+ private translateProjection;
56
+ private translateSelectInner;
57
+ translateSelect<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], option?: OP): string;
58
+ translateWhere<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], option?: OP): string;
59
+ translateAggregate<T extends keyof ED, OP extends SqlSelectOption>(entity: T, aggregation: ED[T]['Aggregation'], option?: OP): string;
60
+ translateCount<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, option?: OP): string;
61
+ translateRemove<T extends keyof ED, OP extends SqlOperateOption>(entity: T, operation: ED[T]['Remove'], option?: OP): string;
62
+ translateUpdate<T extends keyof ED, OP extends SqlOperateOption>(entity: T, operation: ED[T]['Update'], option?: OP): string;
63
+ translateDestroyEntity(entity: string, truncate?: boolean): string;
64
+ escapeStringValue(value: string): string;
65
+ /**比较两段sql是否完全一致,这里是把所有的空格去掉了 */
66
+ compareSql(sql1: string, sql2: string): boolean;
67
+ quoteIdentifier(name: string): string;
68
+ }
@@ -21,7 +21,7 @@ class SqlTranslator {
21
21
  const { attributes, indexes } = schema[entity];
22
22
  // 增加默认的属性
23
23
  (0, lodash_1.assign)(attributes, {
24
- id: {
24
+ [types_1.PrimaryKeyAttribute]: {
25
25
  type: 'char',
26
26
  params: {
27
27
  length: 36,
@@ -69,7 +69,7 @@ class SqlTranslator {
69
69
  name: types_1.DeleteAtAttribute,
70
70
  }],
71
71
  }, {
72
- name: `${entity}_trigger_uuid`,
72
+ name: `${entity}_trigger_uuid_auto_create`,
73
73
  attributes: [{
74
74
  name: types_1.TriggerUuidAttribute,
75
75
  }]
@@ -137,6 +137,16 @@ class SqlTranslator {
137
137
  }
138
138
  }
139
139
  if (indexes) {
140
+ for (const index of indexes) {
141
+ const { attributes, config } = index;
142
+ if (!config?.type || config.type === 'btree') {
143
+ if (!attributes.find((ele) => ele.name === types_1.DeleteAtAttribute)) {
144
+ attributes.push({
145
+ name: types_1.DeleteAtAttribute,
146
+ });
147
+ }
148
+ }
149
+ }
140
150
  indexes.push(...intrinsticIndexes);
141
151
  }
142
152
  else {
@@ -154,14 +164,14 @@ class SqlTranslator {
154
164
  translateInsert(entity, data) {
155
165
  const { schema } = this;
156
166
  const { attributes, storageName = entity } = schema[entity];
157
- let sql = `insert into \`${storageName}\`(`;
167
+ let sql = `insert into ${this.quoteIdentifier(storageName)}(`;
158
168
  /**
159
169
  * 这里的attrs要用所有行的union集合
160
170
  */
161
171
  const dataFull = data.reduce((prev, cur) => Object.assign({}, cur, prev), {});
162
172
  const attrs = Object.keys(dataFull).filter(ele => attributes.hasOwnProperty(ele));
163
173
  attrs.forEach((attr, idx) => {
164
- sql += ` \`${attr}\``;
174
+ sql += ` ${this.quoteIdentifier(attr)}`;
165
175
  if (idx < attrs.length - 1) {
166
176
  sql += ',';
167
177
  }
@@ -209,7 +219,7 @@ class SqlTranslator {
209
219
  const projectionRefAlias = {};
210
220
  const filterRefAlias = {};
211
221
  const alias = `${entity}_${number++}`;
212
- let from = ` \`${this.getStorageName(entity)}\` \`${alias}\` `;
222
+ let from = ` ${this.quoteIdentifier(this.getStorageName(entity))} ${this.quoteIdentifier(alias)} `;
213
223
  const aliasDict = {
214
224
  './': alias,
215
225
  };
@@ -243,7 +253,7 @@ class SqlTranslator {
243
253
  (0, lodash_1.assign)(aliasDict, {
244
254
  [pathAttr]: alias2,
245
255
  });
246
- from += ` left join \`${this.getStorageName(rel)}\` \`${alias2}\` on \`${alias}\`.\`${op}Id\` = \`${alias2}\`.\`id\``;
256
+ from += ` left join ${this.quoteIdentifier(this.getStorageName(rel))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier(op + 'Id')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')}`;
247
257
  }
248
258
  else {
249
259
  alias2 = aliasDict[pathAttr];
@@ -263,7 +273,7 @@ class SqlTranslator {
263
273
  (0, lodash_1.assign)(aliasDict, {
264
274
  [pathAttr]: alias2,
265
275
  });
266
- from += ` left join \`${this.getStorageName(op)}\` \`${alias2}\` on \`${alias}\`.\`entityId\` = \`${alias2}\`.\`id\` and \`${alias}\`.\`entity\` = '${op}'`;
276
+ from += ` left join ${this.quoteIdentifier(this.getStorageName(op))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entityId')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')} and ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entity')} = '${op}'`;
267
277
  }
268
278
  else {
269
279
  alias2 = aliasDict[pathAttr];
@@ -307,7 +317,7 @@ class SqlTranslator {
307
317
  (0, lodash_1.assign)(aliasDict, {
308
318
  [pathAttr]: alias2,
309
319
  });
310
- from += ` left join \`${this.getStorageName(rel)}\` \`${alias2}\` on \`${alias}\`.\`${attr}Id\` = \`${alias2}\`.\`id\``;
320
+ from += ` left join ${this.quoteIdentifier(this.getStorageName(rel))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr + 'Id')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')}`;
311
321
  }
312
322
  else {
313
323
  alias2 = aliasDict[pathAttr];
@@ -327,7 +337,7 @@ class SqlTranslator {
327
337
  (0, lodash_1.assign)(aliasDict, {
328
338
  [pathAttr]: alias2,
329
339
  });
330
- from += ` left join \`${this.getStorageName(attr)}\` \`${alias2}\` on \`${alias}\`.\`entityId\` = \`${alias2}\`.\`id\` and \`${alias}\`.\`entity\` = '${attr}'`;
340
+ from += ` left join ${this.quoteIdentifier(this.getStorageName(attr))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entityId')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')} and ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entity')} = '${attr}'`;
331
341
  }
332
342
  else {
333
343
  alias2 = aliasDict[pathAttr];
@@ -365,7 +375,7 @@ class SqlTranslator {
365
375
  (0, lodash_1.assign)(aliasDict, {
366
376
  [pathAttr]: alias2,
367
377
  });
368
- from += ` left join \`${this.getStorageName(rel)}\` \`${alias2}\` on \`${alias}\`.\`${attr}Id\` = \`${alias2}\`.\`id\``;
378
+ from += ` left join ${this.quoteIdentifier(this.getStorageName(rel))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr + 'Id')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')}`;
369
379
  }
370
380
  else {
371
381
  alias2 = aliasDict[pathAttr];
@@ -385,7 +395,7 @@ class SqlTranslator {
385
395
  (0, lodash_1.assign)(aliasDict, {
386
396
  [pathAttr]: alias2,
387
397
  });
388
- from += ` left join \`${this.getStorageName(attr)}\` \`${alias2}\` on \`${alias}\`.\`entityId\` = \`${alias2}\`.\`id\` and \`${alias}\`.\`entity\` = '${attr}'`;
398
+ from += ` left join ${this.quoteIdentifier(this.getStorageName(attr))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entityId')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')} and ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entity')} = '${attr}'`;
389
399
  }
390
400
  else {
391
401
  alias2 = aliasDict[pathAttr];
@@ -426,6 +436,15 @@ class SqlTranslator {
426
436
  currentNumber: number,
427
437
  };
428
438
  }
439
+ /**
440
+ * 对like模式中的特殊字符进行转义
441
+ * 例如 % 和 _,以防止被当成通配符处理
442
+ * @param pattern like模式字符串
443
+ * @returns 转义后的字符串
444
+ */
445
+ escapeLikePattern(pattern) {
446
+ return pattern.replace(/[%_]/g, (match) => `\\${match}`);
447
+ }
429
448
  translateComparison(attr, value, type) {
430
449
  const SQL_OP = {
431
450
  $gt: '>',
@@ -445,16 +464,19 @@ class SqlTranslator {
445
464
  }
446
465
  switch (attr) {
447
466
  case '$startsWith': {
448
- return ` like '${value}%'`;
467
+ const escaped = this.escapeLikePattern(value);
468
+ return ` LIKE '${escaped}%'`;
449
469
  }
450
470
  case '$endsWith': {
451
- return ` like '%${value}'`;
471
+ const escaped = this.escapeLikePattern(value);
472
+ return ` LIKE '%${escaped}'`;
452
473
  }
453
474
  case '$includes': {
454
- return ` like '%${value}%'`;
475
+ const escaped = this.escapeLikePattern(value);
476
+ return ` LIKE '%${escaped}%'`;
455
477
  }
456
478
  default: {
457
- throw new Error(`unrecoganized comparison operator ${attr}`);
479
+ throw new Error(`unrecognized comparison operator ${attr}`);
458
480
  }
459
481
  }
460
482
  }
@@ -499,7 +521,7 @@ class SqlTranslator {
499
521
  };
500
522
  const values = value.map((v) => {
501
523
  if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
502
- return `'${v}'`;
524
+ return this.escapeStringValue(String(v));
503
525
  }
504
526
  else {
505
527
  return `${v}`;
@@ -516,7 +538,7 @@ class SqlTranslator {
516
538
  else if (predicate === '$between') {
517
539
  const values = value.map((v) => {
518
540
  if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
519
- return `'${v}'`;
541
+ return this.escapeStringValue(String(v));
520
542
  }
521
543
  else {
522
544
  return `${v}`;
@@ -626,7 +648,7 @@ class SqlTranslator {
626
648
  filter: filter2[attr]
627
649
  }, currentNumber, filterRefAlias, option);
628
650
  currentNumber = ct2;
629
- whereText += `(${refAlia2}.id ${predicate} (${stmt}))`;
651
+ whereText += `(${this.quoteIdentifier(alias)}.${this.quoteIdentifier('id')} ${predicate} (${stmt}))`;
630
652
  }
631
653
  else {
632
654
  /**
@@ -682,15 +704,18 @@ class SqlTranslator {
682
704
  whereText += `(${this.translateObjectPredicate(filter2[attr], alias, attr)})`;
683
705
  }
684
706
  else {
707
+ if (!filter2[attr]) {
708
+ throw new Error(`属性${attr}的查询条件不能为null或undefined`);
709
+ }
685
710
  (0, assert_1.default)(Object.keys(filter2[attr]).length === 1);
686
711
  const predicate = Object.keys(filter2[attr])[0];
687
712
  (0, assert_1.default)(predicate.startsWith('$'));
688
713
  // 对属性上的谓词处理
689
- whereText += ` (\`${alias}\`.\`${attr}\` ${this.translatePredicate(predicate, filter2[attr][predicate], type2)})`;
714
+ whereText += ` (${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} ${this.translatePredicate(predicate, filter2[attr][predicate], type2)})`;
690
715
  }
691
716
  }
692
717
  else {
693
- whereText += ` (\`${alias}\`.\`${attr}\` = ${this.translateAttrValue(type2, filter2[attr])})`;
718
+ whereText += ` (${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} = ${this.translateAttrValue(type2, filter2[attr])})`;
694
719
  }
695
720
  }
696
721
  }
@@ -716,7 +741,7 @@ class SqlTranslator {
716
741
  return this.translateExpression(entity2, alias, sortAttr[attr], {});
717
742
  }
718
743
  else if (sortAttr[attr] === 1) {
719
- return `\`${alias}\`.\`${attr}\``;
744
+ return `${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)}`;
720
745
  }
721
746
  else {
722
747
  const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
@@ -765,12 +790,12 @@ class SqlTranslator {
765
790
  projText += ` ${exprText}`;
766
791
  }
767
792
  else {
768
- projText += ` ${exprText} as \`${prefix2}${attr}\``;
793
+ projText += ` ${exprText} as ${this.quoteIdentifier(prefix2 + attr)}`;
769
794
  if (!as) {
770
- as = `\`${prefix2}${attr}\``;
795
+ as = this.quoteIdentifier(prefix2 + attr);
771
796
  }
772
797
  else {
773
- as += `, \`${prefix2}${attr}\``;
798
+ as += `, ${this.quoteIdentifier(prefix2 + attr)}`;
774
799
  }
775
800
  }
776
801
  }
@@ -789,12 +814,12 @@ class SqlTranslator {
789
814
  projText += ` ${this.translateAttrProjection(type, alias, attr)}`;
790
815
  }
791
816
  else {
792
- projText += ` ${this.translateAttrProjection(type, alias, attr)} as \`${prefix2}${attr}\``;
817
+ projText += ` ${this.translateAttrProjection(type, alias, attr)} as ${this.quoteIdentifier(prefix2 + attr)}`;
793
818
  if (!as) {
794
- as = `\`${prefix2}${attr}\``;
819
+ as = this.quoteIdentifier(prefix2 + attr);
795
820
  }
796
821
  else {
797
- as += `, \`${prefix2}${attr}\``;
822
+ as += `, ${this.quoteIdentifier(prefix2 + attr)}`;
798
823
  }
799
824
  }
800
825
  }
@@ -810,12 +835,12 @@ class SqlTranslator {
810
835
  projText += ` ${this.translateAttrProjection(type, alias, attr)}`;
811
836
  }
812
837
  else {
813
- projText += ` ${this.translateAttrProjection(type, alias, attr)} as \`${prefix2}${projection2[attr]}\``;
838
+ projText += ` ${this.translateAttrProjection(type, alias, attr)} as ${this.quoteIdentifier(`${prefix2}${projection2[attr]}`)}`;
814
839
  if (!as) {
815
- as = `\`${prefix2}${projection2[attr]}\``;
840
+ as = this.quoteIdentifier(`${prefix2}${projection2[attr]}`);
816
841
  }
817
842
  else {
818
- as += `\`${prefix2}${projection2[attr]}\``;
843
+ as += `, ${this.quoteIdentifier(`${prefix2}${projection2[attr]}`)}`;
819
844
  }
820
845
  }
821
846
  }
@@ -885,29 +910,29 @@ class SqlTranslator {
885
910
  let { projText: projSubText } = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, undefined, true);
886
911
  let projSubText2 = '';
887
912
  if (k.startsWith('#max')) {
888
- projSubText2 = `max(${projSubText}) as \`${k}\``;
913
+ projSubText2 = `max(${projSubText}) as ${this.quoteIdentifier(k)}`;
889
914
  }
890
915
  else if (k.startsWith('#min')) {
891
- projSubText2 = `min(${projSubText}) as \`${k}\``;
916
+ projSubText2 = `min(${projSubText}) as ${this.quoteIdentifier(k)}`;
892
917
  }
893
918
  else if (k.startsWith('#count')) {
894
919
  if (data.distinct) {
895
920
  projSubText = `distinct ${projSubText}`;
896
921
  }
897
- projSubText2 = `count(${projSubText}) as \`${k}\``;
922
+ projSubText2 = `count(${projSubText}) as ${this.quoteIdentifier(k)}`;
898
923
  }
899
924
  else if (k.startsWith('#sum')) {
900
925
  if (data.distinct) {
901
926
  projSubText = `distinct ${projSubText}`;
902
927
  }
903
- projSubText2 = `sum(${projSubText}) as \`${k}\``;
928
+ projSubText2 = `sum(${projSubText}) as ${this.quoteIdentifier(k)}`;
904
929
  }
905
930
  else {
906
931
  if (data.distinct) {
907
932
  projSubText = `distinct ${projSubText}`;
908
933
  }
909
934
  (0, assert_1.default)(k.startsWith('#avg'));
910
- projSubText2 = `avg(${projSubText}) as \`${k}\``;
935
+ projSubText2 = `avg(${projSubText}) as ${this.quoteIdentifier(k)}`;
911
936
  }
912
937
  if (!projText) {
913
938
  projText = projSubText2;
@@ -955,7 +980,7 @@ class SqlTranslator {
955
980
  // delete只支持对volatile trigger的metadata域赋值
956
981
  (0, assert_1.default)([types_1.TriggerDataAttribute, types_1.TriggerUuidAttribute, types_1.DeleteAtAttribute, types_1.UpdateAtAttribute].includes(attr));
957
982
  const value = this.translateAttrValue(attributes[attr].type, data[attr]);
958
- updateText += `\`${alias}\`.\`${attr}\` = ${value}`;
983
+ updateText += `${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} = ${value}`;
959
984
  }
960
985
  }
961
986
  return this.populateRemoveStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
@@ -973,7 +998,7 @@ class SqlTranslator {
973
998
  }
974
999
  (0, assert_1.default)(attributes.hasOwnProperty(attr));
975
1000
  const value = this.translateAttrValue(attributes[attr].type, data[attr]);
976
- updateText += `\`${alias}\`.\`${attr}\` = ${value}`;
1001
+ updateText += `${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} = ${value}`;
977
1002
  }
978
1003
  const { stmt: filterText } = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, option);
979
1004
  // const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
@@ -984,10 +1009,10 @@ class SqlTranslator {
984
1009
  const { storageName = entity, view } = schema[entity];
985
1010
  let sql;
986
1011
  if (view) {
987
- sql = `drop view if exists \`${storageName}\``;
1012
+ sql = `drop view if exists ${this.quoteIdentifier(storageName)}`;
988
1013
  }
989
1014
  else {
990
- sql = truncate ? `truncate table \`${storageName}\`` : `drop table if exists \`${storageName}\``;
1015
+ sql = truncate ? `truncate table ${this.quoteIdentifier(storageName)}` : `drop table if exists ${this.quoteIdentifier(storageName)}`;
991
1016
  }
992
1017
  return sql;
993
1018
  }
@@ -995,5 +1020,13 @@ class SqlTranslator {
995
1020
  const result = sqlstring_1.default.escape(value);
996
1021
  return result;
997
1022
  }
1023
+ /**比较两段sql是否完全一致,这里是把所有的空格去掉了 */
1024
+ compareSql(sql1, sql2) {
1025
+ const reg = /[\t\r\f\n\s]/g;
1026
+ return sql1.replaceAll(reg, '') === sql2.replaceAll(reg, '');
1027
+ }
1028
+ quoteIdentifier(name) {
1029
+ return `\`${name}\``; // MySQL 默认
1030
+ }
998
1031
  }
999
1032
  exports.SqlTranslator = SqlTranslator;
@@ -1,3 +1,3 @@
1
- export type CreateEntityOption = {
2
- ifExists?: 'drop' | 'omit' | 'dropIfNotStatic';
3
- };
1
+ export type CreateEntityOption = {
2
+ ifExists?: 'drop' | 'omit' | 'dropIfNotStatic';
3
+ };
@@ -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,7 @@
1
+ import { PostgreSQLConfiguration } from './../PostgreSQL/types/Configuration';
2
+ import { MySQLConfiguration } from './../MySQL/types/Configuration';
3
+ export type DbConfiguration = PostgreSQLConfiguration & {
4
+ type: 'postgresql';
5
+ } | MySQLConfiguration & {
6
+ type: 'mysql';
7
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import { EntityDict } from "oak-domain/lib/base-app-domain";
2
+ import { AsyncContext, AsyncRowStore } from "oak-domain/lib/store/AsyncRowStore";
3
+ import { CreateEntityOption } from "./Translator";
4
+ export interface DbStore<ED extends EntityDict, Cxt extends AsyncContext<ED>> extends AsyncRowStore<ED, Cxt> {
5
+ connect: () => Promise<void>;
6
+ disconnect: () => Promise<void>;
7
+ initialize(options: CreateEntityOption): Promise<void>;
8
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-db",
3
- "version": "3.3.10",
3
+ "version": "3.3.12",
4
4
  "description": "oak-db",
5
5
  "main": "lib/index",
6
6
  "author": {
@@ -10,15 +10,16 @@
10
10
  "lib/**/*"
11
11
  ],
12
12
  "scripts": {
13
- "test": "mocha",
13
+ "test": "node --stack-size=65500 ./node_modules/mocha/bin/mocha",
14
14
  "make:test:domain": "ts-node script/makeTestDomain.ts",
15
- "build": "tsc"
15
+ "build": "node --stack-size=4096 ./script/build.js"
16
16
  },
17
17
  "dependencies": {
18
18
  "lodash": "^4.17.21",
19
19
  "mysql": "^2.18.1",
20
20
  "mysql2": "^2.3.3",
21
- "oak-domain": "^5.1.27",
21
+ "oak-domain": "^5.1.33",
22
+ "pg": "^8.16.3",
22
23
  "uuid": "^8.3.2"
23
24
  },
24
25
  "license": "ISC",
@@ -27,11 +28,11 @@
27
28
  "@types/luxon": "^2.3.2",
28
29
  "@types/mocha": "^9.1.1",
29
30
  "@types/node": "^20.6.0",
31
+ "@types/pg": "^8.16.0",
30
32
  "@types/sqlstring": "^2.3.0",
31
33
  "@types/uuid": "^8.3.4",
32
34
  "cross-env": "^7.0.3",
33
35
  "mocha": "^10.2.0",
34
- "oak-general-business": "~5.5.0",
35
36
  "ts-node": "^10.9.1",
36
37
  "tslib": "^2.4.0",
37
38
  "typescript": "^5.2.2"