oak-db 3.3.14 → 4.0.1

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,2 @@
1
+ import { MigrationSchema } from '../types/migration';
2
+ export declare function buildPostgreSqlPrepareSql(currentSchema: MigrationSchema, targetSchema: MigrationSchema): string[];
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPostgreSqlPrepareSql = buildPostgreSqlPrepareSql;
4
+ const textSearchConfigRegistry = {
5
+ chinese: {
6
+ getRequirement(parser = 'zhparser') {
7
+ return {
8
+ extension: parser,
9
+ bootstrapSql: [`DO $$
10
+ BEGIN
11
+ IF NOT EXISTS (
12
+ SELECT 1 FROM pg_catalog.pg_ts_config WHERE cfgname = 'chinese'
13
+ ) THEN
14
+ CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = ${parser});
15
+ ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l WITH simple;
16
+ END IF;
17
+ END $$;`],
18
+ };
19
+ },
20
+ },
21
+ };
22
+ function collectPostgreSqlSchemaFeatures(schema) {
23
+ const extensions = new Set();
24
+ const textSearchConfigs = new Map();
25
+ Object.values(schema).forEach((tableDef) => {
26
+ Object.values(tableDef.attributes || {}).forEach((attr) => {
27
+ if (attr.type === 'geometry' || attr.type === 'geography') {
28
+ extensions.add('postgis');
29
+ }
30
+ });
31
+ (tableDef.indexes || []).forEach((index) => {
32
+ const tsConfigs = Array.isArray(index.config?.tsConfig)
33
+ ? index.config.tsConfig
34
+ : [index.config?.tsConfig];
35
+ tsConfigs.filter(Boolean).forEach((tsConfig) => {
36
+ const entry = textSearchConfigRegistry[tsConfig];
37
+ if (!entry) {
38
+ return;
39
+ }
40
+ const requirement = entry.getRequirement(index.config?.chineseParser);
41
+ if (requirement.extension) {
42
+ extensions.add(requirement.extension);
43
+ }
44
+ textSearchConfigs.set(tsConfig, requirement);
45
+ });
46
+ });
47
+ });
48
+ return {
49
+ extensions,
50
+ textSearchConfigs,
51
+ };
52
+ }
53
+ function buildPostgreSqlPrepareSql(currentSchema, targetSchema) {
54
+ const sqls = [];
55
+ const currentFeatures = collectPostgreSqlSchemaFeatures(currentSchema);
56
+ const targetFeatures = collectPostgreSqlSchemaFeatures(targetSchema);
57
+ targetFeatures.extensions.forEach((extension) => {
58
+ if (!currentFeatures.extensions.has(extension)) {
59
+ sqls.push(`CREATE EXTENSION IF NOT EXISTS ${extension};`);
60
+ }
61
+ });
62
+ targetFeatures.textSearchConfigs.forEach((requirement, configName) => {
63
+ if (currentFeatures.textSearchConfigs.has(configName)) {
64
+ return;
65
+ }
66
+ sqls.push(...requirement.bootstrapSql);
67
+ });
68
+ return sqls;
69
+ }
@@ -8,12 +8,14 @@ import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
8
8
  import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
9
9
  import { CreateEntityOption } from '../types/Translator';
10
10
  import { DbStore, Plan } from '../types/dbStore';
11
+ import { MigrationPlanningOptions } from '../types/migration';
11
12
  export declare class PostgreSQLStore<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends CascadeStore<ED> implements DbStore<ED, Cxt> {
12
13
  protected countAbjointRow<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED>>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: OP): number;
13
14
  protected aggregateAbjointRowSync<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
14
15
  protected selectAbjointRow<T extends keyof ED, OP extends SelectOption>(entity: T, selection: ED[T]['Selection'], context: SyncContext<ED>, option: OP): Partial<ED[T]['Schema']>[];
15
16
  protected updateAbjointRow<T extends keyof ED, OP extends OperateOption>(entity: T, operation: ED[T]['Operation'], context: SyncContext<ED>, option: OP): number;
16
17
  exec(script: string, txnId?: string): Promise<void>;
18
+ supportsTransactionalDdl(): boolean;
17
19
  connector: PostgreSQLConnector;
18
20
  translator: PostgreSQLTranslator<ED>;
19
21
  constructor(storageSchema: StorageSchema<ED>, configuration: PostgreSQLConfiguration);
@@ -24,6 +26,7 @@ export declare class PostgreSQLStore<ED extends EntityDict & BaseEntityDict, Cxt
24
26
  protected supportMultipleCreate(): boolean;
25
27
  protected supportUpdateReturning(): boolean;
26
28
  private formResult;
29
+ private lockSelectedRows;
27
30
  protected selectAbjointRowAsync<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: AsyncContext<ED>, option?: PostgreSQLSelectOption): Promise<Partial<ED[T]['Schema']>[]>;
28
31
  protected updateAbjointRowAsync<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: AsyncContext<ED>, option?: PostgreSQLOperateOption): Promise<number>;
29
32
  protected updateAbjointRowReturningSync<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: AsyncContext<ED>, returning: Record<string, any>, option?: PostgreSQLOperateOption): [number, Partial<ED[T]['Schema']>[]];
@@ -37,17 +40,25 @@ export declare class PostgreSQLStore<ED extends EntityDict & BaseEntityDict, Cxt
37
40
  rollback(txnId: string): Promise<void>;
38
41
  connect(): Promise<void>;
39
42
  disconnect(): Promise<void>;
43
+ private shouldLogInitializeProgress;
44
+ private isFullManagedReset;
45
+ private runInitializeTransaction;
46
+ private ensureChineseTextSearchConfiguration;
47
+ private createManagedSchema;
48
+ private applyForeignKeysFromPlan;
49
+ private applyDeclaredForeignKeys;
50
+ private applyMissingForeignKeys;
40
51
  initialize(option: CreateEntityOption): Promise<void>;
41
52
  readSchema(): Promise<StorageSchema<ED>>;
42
53
  /**
43
54
  * 根据载入的dataSchema,和数据库中原来的schema,决定如何来upgrade
44
55
  * 制订出来的plan分为两阶段:增加阶段和削减阶段,在两个阶段之间,由用户来修正数据
45
56
  */
46
- makeUpgradePlan(): Promise<Plan>;
57
+ makeUpgradePlan(options?: MigrationPlanningOptions): Promise<Plan<ED>>;
47
58
  /**
48
59
  * 比较两个schema的不同,这里计算的是new对old的增量
49
60
  * @param schemaOld
50
61
  * @param schemaNew
51
62
  */
52
- diffSchema(schemaOld: StorageSchema<any>, schemaNew: StorageSchema<any>): Plan;
63
+ diffSchema(schemaOld: StorageSchema<ED>, schemaNew: StorageSchema<ED>, options?: MigrationPlanningOptions): Plan<ED>;
53
64
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PostgreSQLStore = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const types_1 = require("oak-domain/lib/types");
5
6
  const CascadeStore_1 = require("oak-domain/lib/store/CascadeStore");
6
7
  const connector_1 = require("./connector");
7
8
  const translator_1 = require("./translator");
@@ -70,6 +71,9 @@ class PostgreSQLStore extends CascadeStore_1.CascadeStore {
70
71
  async exec(script, txnId) {
71
72
  await this.connector.exec(script, txnId);
72
73
  }
74
+ supportsTransactionalDdl() {
75
+ return true;
76
+ }
73
77
  connector;
74
78
  translator;
75
79
  constructor(storageSchema, configuration) {
@@ -275,10 +279,34 @@ class PostgreSQLStore extends CascadeStore_1.CascadeStore {
275
279
  }
276
280
  return formSingleRow(result);
277
281
  }
282
+ async lockSelectedRows(entity, rows, context, forUpdate) {
283
+ // PostgreSQL 不能在 outer join 的 nullable side 上直接 FOR UPDATE,
284
+ // 因此先完成主查询,再按根表主键补锁,保持上层 forUpdate 用法不变。
285
+ if (rows.length === 0) {
286
+ return;
287
+ }
288
+ const ids = Array.from(new Set(rows.map((row) => {
289
+ const id = row[types_1.PrimaryKeyAttribute];
290
+ (0, assert_1.default)(typeof id === 'string' && id.length > 0, `对象${String(entity)}取数据时未能获取主键,无法完成 for update 锁定`);
291
+ return id;
292
+ })));
293
+ const tableName = this.translator.quoteIdentifier(this.getSchema()[entity].storageName || entity);
294
+ const idName = this.translator.quoteIdentifier(types_1.PrimaryKeyAttribute);
295
+ const inClause = ids.map((id) => this.translator.escapeStringValue(id)).join(', ');
296
+ let sql = `SELECT ${idName} FROM ${tableName} WHERE ${idName} IN (${inClause}) FOR UPDATE`;
297
+ if (typeof forUpdate === 'string') {
298
+ sql += ` ${forUpdate}`;
299
+ }
300
+ await this.connector.exec(sql, context.getCurrentTxnId());
301
+ }
278
302
  async selectAbjointRowAsync(entity, selection, context, option) {
279
303
  const sql = this.translator.translateSelect(entity, selection, option);
280
304
  const result = await this.connector.exec(sql, context.getCurrentTxnId());
281
- return this.formResult(entity, result[0]);
305
+ const rows = this.formResult(entity, result[0]);
306
+ if (option?.forUpdate) {
307
+ await this.lockSelectedRows(entity, rows, context, option.forUpdate);
308
+ }
309
+ return rows;
282
310
  }
283
311
  async updateAbjointRowAsync(entity, operation, context, option) {
284
312
  const { translator, connector } = this;
@@ -365,14 +393,108 @@ class PostgreSQLStore extends CascadeStore_1.CascadeStore {
365
393
  async disconnect() {
366
394
  await this.connector.disconnect();
367
395
  }
396
+ shouldLogInitializeProgress(current, total, step) {
397
+ return total <= step || current === 1 || current === total || current % step === 0;
398
+ }
399
+ isFullManagedReset(option) {
400
+ return (option?.ifExists || 'drop') === 'drop';
401
+ }
402
+ async runInitializeTransaction(executor) {
403
+ // PostgreSQL initialize 不能再把整套 schema DDL 塞进一个大事务。
404
+ // 大 schema 下 DDL 锁会一直累积到 COMMIT,最终触发
405
+ // “out of shared memory / max_locks_per_transaction”。
406
+ // 这里把事务边界收敛到“单个初始化单元”(文本检索配置 / 单个实体);
407
+ // 既保留局部原子性,也让锁能及时释放。
408
+ const txn = await this.connector.startTransaction();
409
+ try {
410
+ await executor(txn);
411
+ await this.connector.commitTransaction(txn);
412
+ }
413
+ catch (error) {
414
+ await this.connector.rollbackTransaction(txn);
415
+ throw error;
416
+ }
417
+ }
418
+ async ensureChineseTextSearchConfiguration(hasChineseTsConfig, chineseParser) {
419
+ if (!hasChineseTsConfig) {
420
+ return;
421
+ }
422
+ await this.runInitializeTransaction(async (txn) => {
423
+ console.log('Initializing Chinese text search configuration...');
424
+ const checkChineseConfigSql = `
425
+ SELECT COUNT(*) as cnt
426
+ FROM pg_catalog.pg_ts_config
427
+ WHERE cfgname = 'chinese';
428
+ `;
429
+ const result = await this.connector.exec(checkChineseConfigSql, txn);
430
+ const count = parseInt(result[0][0]?.cnt || '0', 10);
431
+ if (count === 0) {
432
+ const createChineseConfigSql = `
433
+ CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = ${chineseParser || 'zhparser'});
434
+ ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l WITH simple;
435
+ `;
436
+ await this.connector.exec(createChineseConfigSql, txn);
437
+ }
438
+ });
439
+ }
440
+ async createManagedSchema(option) {
441
+ const schema = this.getSchema();
442
+ const entities = Object.keys(schema);
443
+ console.log('Initializing PostgreSQL schema create phase...');
444
+ for (let idx = 0; idx < entities.length; idx++) {
445
+ const entity = entities[idx];
446
+ if (this.shouldLogInitializeProgress(idx + 1, entities.length, 10)) {
447
+ console.log(`Initializing PostgreSQL tables (${idx + 1}/${entities.length}): ${entity}`);
448
+ }
449
+ const sqls = this.translator.translateCreateEntity(entity, option);
450
+ await this.runInitializeTransaction(async (txn) => {
451
+ for (const sql of sqls) {
452
+ await this.connector.exec(sql, txn);
453
+ }
454
+ });
455
+ }
456
+ }
457
+ async applyForeignKeysFromPlan(plan) {
458
+ const foreignKeySqls = [
459
+ ...plan.forwardSql.filter((stmt) => /foreign key/i.test(stmt)),
460
+ ...plan.manualSql.filter((stmt) => /add constraint .*foreign key/i.test(stmt)),
461
+ ];
462
+ console.log('Initializing PostgreSQL foreign key phase...');
463
+ // FK 逐条独立执行,让每条 ALTER TABLE 自己提交。
464
+ // 这样不会再把所有引用关系的锁堆到同一个事务里。
465
+ for (let idx = 0; idx < foreignKeySqls.length; idx++) {
466
+ if (this.shouldLogInitializeProgress(idx + 1, foreignKeySqls.length, 20)) {
467
+ console.log(`Initializing PostgreSQL foreign keys (${idx + 1}/${foreignKeySqls.length})`);
468
+ }
469
+ await this.connector.exec(foreignKeySqls[idx]);
470
+ }
471
+ }
472
+ async applyDeclaredForeignKeys() {
473
+ const plan = this.connector.diffSchema({}, this.translator.schema, this.translator, {
474
+ compareForeignKeys: true,
475
+ });
476
+ await this.applyForeignKeysFromPlan(plan);
477
+ }
478
+ async applyMissingForeignKeys() {
479
+ const inspection = await this.connector.inspectSchema(this.translator);
480
+ const plan = this.connector.diffSchema(inspection.schema, this.translator.schema, this.translator, {
481
+ compareForeignKeys: true,
482
+ currentTableStats: inspection.tableStats,
483
+ });
484
+ await this.applyForeignKeysFromPlan(plan);
485
+ }
368
486
  async initialize(option) {
369
487
  const schema = this.getSchema();
488
+ const entities = Object.keys(schema);
489
+ console.log('Initializing PostgreSQL prepare phase...');
490
+ // PostgreSQL 初始化拆成“事务外准备”和“事务内建表”两段:
491
+ // 扩展/解析器这类对象不能简单塞进同一个 DDL 事务,但表结构本身又希望保持原子性。
370
492
  // ===== 第一阶段:事务外创建扩展 =====
371
493
  let hasGeoType = false;
372
494
  let hasChineseTsConfig = false;
373
495
  let chineseParser = null;
374
496
  // 扫描 schema
375
- for (const entity in schema) {
497
+ for (const entity of entities) {
376
498
  const { attributes, indexes } = schema[entity];
377
499
  for (const attr in attributes) {
378
500
  if (attributes[attr].type === 'geometry') {
@@ -398,54 +520,32 @@ class PostgreSQLStore extends CascadeStore_1.CascadeStore {
398
520
  console.log('Initializing Chinese parser extension...');
399
521
  await this.connector.exec(`CREATE EXTENSION IF NOT EXISTS ${chineseParser || 'zhparser'};`);
400
522
  }
401
- // ===== 第二阶段:事务内创建配置和表 =====
402
- const txn = await this.connector.startTransaction({
403
- isolationLevel: 'serializable',
404
- });
405
- try {
406
- // 创建中文文本搜索配置
407
- if (hasChineseTsConfig) {
408
- console.log('Initializing Chinese text search configuration...');
409
- const checkChineseConfigSql = `
410
- SELECT COUNT(*) as cnt
411
- FROM pg_catalog.pg_ts_config
412
- WHERE cfgname = 'chinese';
413
- `;
414
- const result = await this.connector.exec(checkChineseConfigSql, txn);
415
- const count = parseInt(result[0][0]?.cnt || '0', 10);
416
- if (count === 0) {
417
- const createChineseConfigSql = `
418
- CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = ${chineseParser || 'zhparser'});
419
- ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l WITH simple;
420
- `;
421
- await this.connector.exec(createChineseConfigSql, txn);
422
- }
423
- }
424
- // 创建实体表
425
- for (const entity in schema) {
426
- const sqls = this.translator.translateCreateEntity(entity, option);
427
- for (const sql of sqls) {
428
- await this.connector.exec(sql, txn);
429
- }
430
- }
431
- await this.connector.commitTransaction(txn);
523
+ // ===== 第二阶段:按初始化单元分批执行事务 =====
524
+ // 文本检索配置、每个实体的建表 DDL、以及每条 FK 的 ALTER TABLE
525
+ // 都拆开提交,避免大 schema 初始化时单事务积累过多 relation locks。
526
+ await this.ensureChineseTextSearchConfiguration(hasChineseTsConfig, chineseParser);
527
+ await this.createManagedSchema(option);
528
+ if (this.isFullManagedReset(option)) {
529
+ await this.applyDeclaredForeignKeys();
432
530
  }
433
- catch (error) {
434
- await this.connector.rollbackTransaction(txn);
435
- throw error;
531
+ else {
532
+ await this.applyMissingForeignKeys();
436
533
  }
437
534
  }
438
535
  // 从数据库中读取当前schema
439
536
  readSchema() {
440
- return this.translator.readSchema((sql) => this.connector.exec(sql));
537
+ return this.connector.readSchema(this.translator);
441
538
  }
442
539
  /**
443
540
  * 根据载入的dataSchema,和数据库中原来的schema,决定如何来upgrade
444
541
  * 制订出来的plan分为两阶段:增加阶段和削减阶段,在两个阶段之间,由用户来修正数据
445
542
  */
446
- async makeUpgradePlan() {
447
- const originSchema = await this.readSchema();
448
- const plan = this.diffSchema(originSchema, this.translator.schema);
543
+ async makeUpgradePlan(options) {
544
+ const inspection = await this.connector.inspectSchema(this.translator);
545
+ const plan = this.diffSchema(inspection.schema, this.translator.schema, {
546
+ ...options,
547
+ currentTableStats: options?.currentTableStats || inspection.tableStats,
548
+ });
449
549
  return plan;
450
550
  }
451
551
  /**
@@ -453,117 +553,8 @@ class PostgreSQLStore extends CascadeStore_1.CascadeStore {
453
553
  * @param schemaOld
454
554
  * @param schemaNew
455
555
  */
456
- diffSchema(schemaOld, schemaNew) {
457
- const plan = {
458
- newTables: {},
459
- newIndexes: {},
460
- updatedIndexes: {},
461
- updatedTables: {},
462
- };
463
- for (const table in schemaNew) {
464
- // PostgreSQL 表名区分大小写(使用双引号时)
465
- if (schemaOld[table]) {
466
- const { attributes, indexes } = schemaOld[table];
467
- const { attributes: attributesNew, indexes: indexesNew } = schemaNew[table];
468
- const assignToUpdateTables = (attr, isNew) => {
469
- const skipAttrs = ['$$seq$$', '$$createAt$$', '$$updateAt$$', '$$deleteAt$$', 'id'];
470
- if (skipAttrs.includes(attr)) {
471
- return;
472
- }
473
- if (!plan.updatedTables[table]) {
474
- plan.updatedTables[table] = {
475
- attributes: {
476
- [attr]: {
477
- ...attributesNew[attr],
478
- isNew,
479
- }
480
- }
481
- };
482
- }
483
- else {
484
- plan.updatedTables[table].attributes[attr] = {
485
- ...attributesNew[attr],
486
- isNew,
487
- };
488
- }
489
- };
490
- for (const attr in attributesNew) {
491
- if (attributes[attr]) {
492
- // 比较两次创建的属性定义是否一致
493
- const sql1 = this.translator.translateAttributeDef(attr, attributesNew[attr]);
494
- const sql2 = this.translator.translateAttributeDef(attr, attributes[attr]);
495
- if (!this.translator.compareSql(sql1, sql2)) {
496
- assignToUpdateTables(attr, false);
497
- }
498
- }
499
- else {
500
- assignToUpdateTables(attr, true);
501
- }
502
- }
503
- if (indexesNew) {
504
- const assignToIndexes = (index, isNew) => {
505
- if (isNew) {
506
- if (plan.newIndexes[table]) {
507
- plan.newIndexes[table].push(index);
508
- }
509
- else {
510
- plan.newIndexes[table] = [index];
511
- }
512
- }
513
- else {
514
- if (plan.updatedIndexes[table]) {
515
- plan.updatedIndexes[table].push(index);
516
- }
517
- else {
518
- plan.updatedIndexes[table] = [index];
519
- }
520
- }
521
- };
522
- const compareConfig = (config1, config2) => {
523
- const unique1 = config1?.unique || false;
524
- const unique2 = config2?.unique || false;
525
- if (unique1 !== unique2) {
526
- return false;
527
- }
528
- const type1 = config1?.type || 'btree';
529
- const type2 = config2?.type || 'btree';
530
- // tsConfig 比较
531
- const tsConfig1 = config1?.tsConfig;
532
- const tsConfig2 = config2?.tsConfig;
533
- if (JSON.stringify(tsConfig1) !== JSON.stringify(tsConfig2)) {
534
- return false;
535
- }
536
- return type1 === type2;
537
- };
538
- for (const index of indexesNew) {
539
- const { name, config, attributes: indexAttrs } = index;
540
- const origin = indexes?.find(ele => ele.name === name);
541
- if (origin) {
542
- if (JSON.stringify(indexAttrs) !== JSON.stringify(origin.attributes)) {
543
- assignToIndexes(index, false);
544
- }
545
- else {
546
- if (!compareConfig(config, origin.config)) {
547
- assignToIndexes(index, false);
548
- }
549
- }
550
- }
551
- else {
552
- assignToIndexes(index, true);
553
- }
554
- }
555
- }
556
- }
557
- else {
558
- plan.newTables[table] = {
559
- attributes: schemaNew[table].attributes,
560
- };
561
- if (schemaNew[table].indexes) {
562
- plan.newIndexes[table] = schemaNew[table].indexes;
563
- }
564
- }
565
- }
566
- return plan;
556
+ diffSchema(schemaOld, schemaNew, options) {
557
+ return this.connector.diffSchema(schemaOld, schemaNew, this.translator, options);
567
558
  }
568
559
  }
569
560
  exports.PostgreSQLStore = PostgreSQLStore;
@@ -14,7 +14,14 @@ export interface PostgreSQLOperateOption extends SqlOperateOption {
14
14
  returning?: Record<string, any>;
15
15
  }
16
16
  export declare class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extends SqlTranslator<ED> {
17
- private getEnumTypeName;
17
+ readonly maxIndexNameLength = 63;
18
+ private physicalIndexNameCache?;
19
+ private makeIndexNameCacheKey;
20
+ private getIndexSuffixes;
21
+ private ensurePhysicalIndexNameCache;
22
+ getEnumTypeName(entity: string, attr: string): string;
23
+ getPhysicalIndexName(entityName: string, tableName: string, logicalName: string, suffix?: string): string;
24
+ getLegacyPhysicalIndexNames(entityName: string, tableName: string, logicalName: string, suffix?: string): string[];
18
25
  /**
19
26
  * 将 MySQL 风格的 JSON 路径转换为 PostgreSQL 路径数组格式
20
27
  * 例如: ".foo.bar[0].baz" -> '{foo,bar,0,baz}'
@@ -96,7 +103,7 @@ export declare class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict
96
103
  * 将 PostgreSQL 返回的 Type 回译成 oak 的类型,是 populateDataTypeDef 的反函数
97
104
  * @param type PostgreSQL 类型字符串
98
105
  */
99
- private reTranslateToAttribute;
106
+ reTranslateToAttribute(type: string): Attribute;
100
107
  /**
101
108
  * 从 PostgreSQL 数据库读取当前的 schema 结构
102
109
  */
@@ -107,6 +114,7 @@ export declare class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict
107
114
  * @param attrDef 属性定义
108
115
  */
109
116
  translateAttributeDef(attr: string, attrDef: Attribute): string;
117
+ translateColumnDefinition(entity: string, attr: string, attrDef: Attribute): string;
110
118
  /**
111
119
  * 比较两个 SQL 语句是否等价(用于 schema diff)
112
120
  * 忽略空格、大小写等格式差异