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.
@@ -37,6 +37,9 @@ class MysqlStore extends CascadeStore_1.CascadeStore {
37
37
  async exec(script, txnId) {
38
38
  await this.connector.exec(script, txnId);
39
39
  }
40
+ supportsTransactionalDdl() {
41
+ return false;
42
+ }
40
43
  connector;
41
44
  translator;
42
45
  constructor(storageSchema, configuration) {
@@ -304,26 +307,164 @@ class MysqlStore extends CascadeStore_1.CascadeStore {
304
307
  async disconnect() {
305
308
  await this.connector.disconnect();
306
309
  }
307
- async initialize(option) {
310
+ shouldResetEntity(option, entity) {
311
+ const ifExists = option?.ifExists || 'drop';
312
+ const entityDef = this.translator.schema[entity];
313
+ if (ifExists === 'drop') {
314
+ return true;
315
+ }
316
+ if (ifExists === 'dropIfNotStatic') {
317
+ return !entityDef.static;
318
+ }
319
+ return false;
320
+ }
321
+ quoteIdentifier(identifier) {
322
+ return `\`${identifier.replace(/`/g, '``')}\``;
323
+ }
324
+ buildResetDropSql(tableNames) {
325
+ return `DROP TABLE IF EXISTS ${tableNames.map((tableName) => this.quoteIdentifier(tableName)).join(', ')};`;
326
+ }
327
+ buildBatchAddForeignKeySql(sqls) {
328
+ const grouped = new Map();
329
+ const orderedTables = [];
330
+ const passthroughSqls = [];
331
+ sqls.forEach((sql) => {
332
+ const normalized = sql.trim();
333
+ const match = /^ALTER TABLE\s+(`[^`]+`)\s+(ADD CONSTRAINT[\s\S]+);$/i.exec(normalized);
334
+ if (!match) {
335
+ passthroughSqls.push(normalized);
336
+ return;
337
+ }
338
+ const [, tableName, clause] = match;
339
+ if (!grouped.has(tableName)) {
340
+ grouped.set(tableName, []);
341
+ orderedTables.push(tableName);
342
+ }
343
+ grouped.get(tableName).push(clause);
344
+ });
345
+ return [
346
+ ...orderedTables.map((tableName) => {
347
+ const clauses = grouped.get(tableName);
348
+ return `ALTER TABLE ${tableName} ${clauses.join(', ')};`;
349
+ }),
350
+ ...passthroughSqls,
351
+ ];
352
+ }
353
+ shouldLogInitializeProgress(current, total, step) {
354
+ return total <= step || current === 1 || current === total || current % step === 0;
355
+ }
356
+ isFullManagedReset(option) {
357
+ return (option?.ifExists || 'drop') === 'drop';
358
+ }
359
+ getCreateOptionForInitialize() {
360
+ return {
361
+ ifExists: 'omit',
362
+ };
363
+ }
364
+ async resetManagedSchema(option) {
365
+ const tableNames = Object.keys(this.translator.schema).filter((entity) => this.shouldResetEntity(option, entity)).map((entity) => this.translator.schema[entity].storageName || entity);
366
+ if (tableNames.length === 0) {
367
+ return;
368
+ }
369
+ await this.connector.withConnection(async (connection) => {
370
+ // MySQL 的 reset 必须在同一个 session 里关闭 FK 检查。
371
+ // 而且要把同一批表放进尽量少的 DROP TABLE 语句里;
372
+ // 逐表 DROP 在复杂 FK 图上会触发 metadata lock deadlock。
373
+ await connection.query('SET FOREIGN_KEY_CHECKS = 0;');
374
+ try {
375
+ await connection.query(this.buildResetDropSql(tableNames));
376
+ }
377
+ finally {
378
+ try {
379
+ await connection.query('SET FOREIGN_KEY_CHECKS = 1;');
380
+ }
381
+ catch (err) {
382
+ connection.destroy();
383
+ throw err;
384
+ }
385
+ }
386
+ });
387
+ }
388
+ async createManagedSchema(option) {
308
389
  const schema = this.getSchema();
309
- for (const entity in schema) {
390
+ const entities = Object.keys(schema);
391
+ // drop/reset 阶段已经独立完成,这里统一走 omit create,
392
+ // 避免 translator 再带入“每个实体自带 drop SQL”的旧流程。
393
+ for (let idx = 0; idx < entities.length; idx++) {
394
+ const entity = entities[idx];
395
+ if (this.shouldLogInitializeProgress(idx + 1, entities.length, 10)) {
396
+ console.log(`Initializing MySQL tables (${idx + 1}/${entities.length}): ${entity}`);
397
+ }
310
398
  const sqls = this.translator.translateCreateEntity(entity, option);
311
399
  for (const sql of sqls) {
312
400
  await this.connector.exec(sql);
313
401
  }
314
402
  }
315
403
  }
404
+ async applyForeignKeysFromPlan(plan) {
405
+ const sqls = [
406
+ ...plan.forwardSql.filter((stmt) => /foreign key/i.test(stmt)),
407
+ ...plan.manualSql.filter((stmt) => /add constraint .*foreign key/i.test(stmt)),
408
+ ];
409
+ const batchedSqls = this.buildBatchAddForeignKeySql(sqls);
410
+ // initialize 阶段只执行“新增 FK”动作:
411
+ // 全量 reset 直接使用目标 schema 里的声明;半保留场景则先 inspect 再只补缺失项。
412
+ for (let idx = 0; idx < batchedSqls.length; idx++) {
413
+ if (this.shouldLogInitializeProgress(idx + 1, batchedSqls.length, 20)) {
414
+ console.log(`Initializing MySQL foreign keys (${idx + 1}/${batchedSqls.length})`);
415
+ }
416
+ const sql = batchedSqls[idx];
417
+ await this.connector.exec(sql);
418
+ }
419
+ }
420
+ async applyDeclaredForeignKeys() {
421
+ const plan = this.connector.diffSchema({}, this.translator.schema, this.translator, {
422
+ compareForeignKeys: true,
423
+ });
424
+ await this.applyForeignKeysFromPlan(plan);
425
+ }
426
+ async applyMissingForeignKeys() {
427
+ const inspection = await this.connector.inspectSchema(this.translator);
428
+ const plan = this.connector.diffSchema(inspection.schema, this.translator.schema, this.translator, {
429
+ compareForeignKeys: true,
430
+ currentTableStats: inspection.tableStats,
431
+ });
432
+ await this.applyForeignKeysFromPlan(plan);
433
+ }
434
+ async initialize(option) {
435
+ console.log('Initializing MySQL schema reset phase...');
436
+ await this.resetManagedSchema(option);
437
+ console.log('Initializing MySQL schema create phase...');
438
+ await this.createManagedSchema(this.getCreateOptionForInitialize());
439
+ console.log('Initializing MySQL foreign key phase...');
440
+ if (this.isFullManagedReset(option)) {
441
+ await this.applyDeclaredForeignKeys();
442
+ }
443
+ else {
444
+ await this.applyMissingForeignKeys();
445
+ }
446
+ }
316
447
  // 从数据库中读取当前schema
317
448
  readSchema() {
318
- return this.translator.readSchema((sql) => this.connector.exec(sql));
449
+ return this.connector.readSchema(this.translator);
319
450
  }
320
451
  /**
321
452
  * 根据载入的dataSchema,和数据库中原来的schema,决定如何来upgrade
322
453
  * 制订出来的plan分为两阶段:增加阶段和削减阶段,在两个阶段之间,由用户来修正数据
323
454
  */
324
- async makeUpgradePlan() {
325
- const originSchema = await this.readSchema();
326
- const plan = this.diffSchema(originSchema, this.translator.schema);
455
+ async makeUpgradePlan(options) {
456
+ const inspection = await this.connector.inspectSchema(this.translator);
457
+ // 自动探测“历史库完全没有物理 FK”的情况:
458
+ // 这类旧库先关闭 FK 对比,避免 upgrade 持续产出噪音计划。
459
+ const hasPhysicalForeignKeys = Object.values(inspection.schema).some((tableDef) => Object.values(tableDef.attributes || {}).some((attr) => {
460
+ const attribute = attr;
461
+ return attribute.type === 'ref' && typeof attribute.ref === 'string';
462
+ }));
463
+ const plan = this.diffSchema(inspection.schema, this.translator.schema, {
464
+ ...options,
465
+ currentTableStats: options?.currentTableStats || inspection.tableStats,
466
+ compareForeignKeys: options?.compareForeignKeys ?? hasPhysicalForeignKeys,
467
+ });
327
468
  return plan;
328
469
  }
329
470
  /**
@@ -331,109 +472,8 @@ class MysqlStore extends CascadeStore_1.CascadeStore {
331
472
  * @param schemaOld
332
473
  * @param SchemaNew
333
474
  */
334
- diffSchema(schemaOld, schemaNew) {
335
- const plan = {
336
- newTables: {},
337
- newIndexes: {},
338
- updatedIndexes: {},
339
- updatedTables: {},
340
- };
341
- for (const table in schemaNew) {
342
- // mysql数据字典不分大小写的
343
- if (schemaOld[table] || schemaOld[table.toLowerCase()]) {
344
- const { attributes, indexes } = schemaOld[table] || schemaOld[table.toLowerCase()];
345
- const { attributes: attributesNew, indexes: indexesNew } = schemaNew[table];
346
- const assignToUpdateTables = (attr, isNew) => {
347
- if (!plan.updatedTables[table]) {
348
- plan.updatedTables[table] = {
349
- attributes: {
350
- [attr]: {
351
- ...attributesNew[attr],
352
- isNew,
353
- }
354
- }
355
- };
356
- }
357
- else {
358
- plan.updatedTables[table].attributes[attr] = {
359
- ...attributesNew[attr],
360
- isNew,
361
- };
362
- }
363
- };
364
- for (const attr in attributesNew) {
365
- if (attributes[attr]) {
366
- // 因为反向无法复原原来定义的attribute类型,这里就比较两次创建的sql是不是一致,不是太好的设计。
367
- const sql1 = this.translator.translateAttributeDef(attr, attributesNew[attr]);
368
- const sql2 = this.translator.translateAttributeDef(attr, attributes[attr]);
369
- if (!this.translator.compareSql(sql1, sql2)) {
370
- assignToUpdateTables(attr, false);
371
- }
372
- }
373
- else {
374
- assignToUpdateTables(attr, true);
375
- }
376
- }
377
- if (indexesNew) {
378
- const assignToIndexes = (index, isNew) => {
379
- if (isNew) {
380
- if (plan.newIndexes[table]) {
381
- plan.newIndexes[table].push(index);
382
- }
383
- else {
384
- plan.newIndexes[table] = [index];
385
- }
386
- }
387
- else {
388
- if (plan.updatedIndexes[table]) {
389
- plan.updatedIndexes[table].push(index);
390
- }
391
- else {
392
- plan.updatedIndexes[table] = [index];
393
- }
394
- }
395
- };
396
- const compareConfig = (config1, config2) => {
397
- const unique1 = config1?.unique || false;
398
- const unique2 = config2?.unique || false;
399
- if (unique1 !== unique2) {
400
- return false;
401
- }
402
- const type1 = config1?.type || 'btree';
403
- const type2 = config2?.type || 'btree';
404
- // parser目前无法从mysql中读出来,所以不比了
405
- return type1 === type2;
406
- };
407
- for (const index of indexesNew) {
408
- const { name, config, attributes } = index;
409
- const origin = indexes?.find(ele => ele.name === name);
410
- if (origin) {
411
- if (JSON.stringify(attributes) !== JSON.stringify(origin.attributes)) {
412
- // todo,这里要细致比较,不能用json.stringify
413
- assignToIndexes(index, false);
414
- }
415
- else {
416
- if (!compareConfig(config, origin.config)) {
417
- assignToIndexes(index, false);
418
- }
419
- }
420
- }
421
- else {
422
- assignToIndexes(index, true);
423
- }
424
- }
425
- }
426
- }
427
- else {
428
- plan.newTables[table] = {
429
- attributes: schemaNew[table].attributes,
430
- };
431
- if (schemaNew[table].indexes) {
432
- plan.newIndexes[table] = schemaNew[table].indexes;
433
- }
434
- }
435
- }
436
- return plan;
475
+ diffSchema(schemaOld, schemaNew, options) {
476
+ return this.connector.diffSchema(schemaOld, schemaNew, this.translator, options);
437
477
  }
438
478
  }
439
479
  exports.MysqlStore = MysqlStore;
@@ -8,6 +8,9 @@ export interface MySqlSelectOption extends SqlSelectOption {
8
8
  export interface MysqlOperateOption extends SqlOperateOption {
9
9
  }
10
10
  export declare class MySqlTranslator<ED extends EntityDict & BaseEntityDict> extends SqlTranslator<ED> {
11
+ readonly maxIndexNameLength = 64;
12
+ getPhysicalIndexName(entityName: string, tableName: string, logicalName: string, suffix?: string): string;
13
+ getLegacyPhysicalIndexNames(entityName: string, tableName: string, logicalName: string, suffix?: string): string[];
11
14
  protected getDefaultSelectFilter(alias: string, option?: MySqlSelectOption): string;
12
15
  private makeUpSchema;
13
16
  constructor(schema: StorageSchema<ED>);
@@ -98,6 +101,7 @@ export declare class MySqlTranslator<ED extends EntityDict & BaseEntityDict> ext
98
101
  protected translateAttrValue(dataType: DataType | Ref, value: any): string;
99
102
  protected translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
100
103
  translateAttributeDef(attr: string, attrDef: Attribute): string;
104
+ translateColumnDefinition(entity: string, attr: string, attrDef: Attribute): string;
101
105
  translateCreateEntity<T extends keyof ED>(entity: T, options?: CreateEntityOption): string[];
102
106
  private translateFnName;
103
107
  private translateAttrInExpression;
@@ -109,6 +113,6 @@ export declare class MySqlTranslator<ED extends EntityDict & BaseEntityDict> ext
109
113
  * 将MySQL返回的Type回译成oak的类型,是 populateDataTypeDef 的反函数
110
114
  * @param type
111
115
  */
112
- private reTranslateToAttribute;
116
+ reTranslateToAttribute(type: string): Attribute;
113
117
  readSchema(execFn: (sql: string) => Promise<any>): Promise<StorageSchema<ED>>;
114
118
  }
@@ -7,6 +7,7 @@ const util_1 = require("util");
7
7
  const lodash_1 = require("lodash");
8
8
  const types_1 = require("oak-domain/lib/types");
9
9
  const sqlTranslator_1 = require("../sqlTranslator");
10
+ const indexName_1 = require("../utils/indexName");
10
11
  const GeoTypes = [
11
12
  {
12
13
  type: 'point',
@@ -72,6 +73,26 @@ function transformGeoData(data) {
72
73
  }
73
74
  }
74
75
  class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
76
+ maxIndexNameLength = 64;
77
+ getPhysicalIndexName(entityName, tableName, logicalName, suffix = '') {
78
+ return (0, indexName_1.buildCompactPhysicalIndexName)({
79
+ entityName,
80
+ tableName,
81
+ logicalName,
82
+ suffix,
83
+ maxLength: this.maxIndexNameLength,
84
+ });
85
+ }
86
+ getLegacyPhysicalIndexNames(entityName, tableName, logicalName, suffix = '') {
87
+ return (0, indexName_1.buildLegacyPhysicalIndexNames)({
88
+ entityName,
89
+ tableName,
90
+ logicalName,
91
+ suffix,
92
+ maxLength: this.maxIndexNameLength,
93
+ serverTruncatesWhenOverflow: false,
94
+ });
95
+ }
75
96
  getDefaultSelectFilter(alias, option) {
76
97
  if (option?.includedDeleted) {
77
98
  return '';
@@ -579,6 +600,9 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
579
600
  }
580
601
  return sql;
581
602
  }
603
+ translateColumnDefinition(entity, attr, attrDef) {
604
+ return this.translateAttributeDef(attr, attrDef);
605
+ }
582
606
  translateCreateEntity(entity, options) {
583
607
  const ifExists = options?.ifExists || 'drop';
584
608
  const { schema } = this;
@@ -619,17 +643,17 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
619
643
  sql += ',\n';
620
644
  indexes.forEach(({ name, attributes, config }, idx) => {
621
645
  const { unique, type, parser } = config || {};
622
- // 因为有deleteAt的存在,这里的unique没意义,只能框架自己去建立checker来处理
623
- /* if (unique) {
646
+ const physicalName = this.getPhysicalIndexName(String(entity), storageName || entity, name);
647
+ if (unique) {
624
648
  sql += ' unique ';
625
649
  }
626
- else */ if (type === 'fulltext') {
650
+ else if (type === 'fulltext') {
627
651
  sql += ' fulltext ';
628
652
  }
629
653
  else if (type === 'spatial') {
630
654
  sql += ' spatial ';
631
655
  }
632
- sql += `index \`${name}\` `;
656
+ sql += `index \`${physicalName}\` `;
633
657
  if (type === 'hash') {
634
658
  sql += ` using hash `;
635
659
  }
@@ -1136,7 +1160,7 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
1136
1160
  };
1137
1161
  }
1138
1162
  const withPrecisionDataTypes = MySqlTranslator.withPrecisionDataTypes.join('|');
1139
- result = (new RegExp(`^(${withPrecisionDataTypes})\\((\\d+),(d+)\\)$`)).exec(type);
1163
+ result = (new RegExp(`^(${withPrecisionDataTypes})\\((\\d+),(\\d+)\\)$`)).exec(type);
1140
1164
  if (result) {
1141
1165
  return {
1142
1166
  type: result[1],
@@ -1,10 +1,15 @@
1
1
  import { Pool, PoolClient, QueryResult, QueryResultRow } from 'pg';
2
2
  import { TxnOption } from 'oak-domain/lib/types';
3
+ import { EntityDict, StorageSchema } from 'oak-domain/lib/types';
4
+ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
3
5
  import { PostgreSQLConfiguration } from './types/Configuration';
6
+ import { PostgreSQLTranslator } from './translator';
7
+ import { MigrationPlanningOptions, Plan, SchemaInspectionResult } from '../types/migration';
4
8
  export declare class PostgreSQLConnector {
5
9
  pool: Pool;
6
10
  configuration: PostgreSQLConfiguration;
7
11
  txnDict: Record<string, PoolClient>;
12
+ txnExecQueueDict: Record<string, Promise<void>>;
8
13
  constructor(configuration: PostgreSQLConfiguration);
9
14
  connect(): void;
10
15
  disconnect(): Promise<void>;
@@ -14,6 +19,11 @@ export declare class PostgreSQLConnector {
14
19
  */
15
20
  private mapIsolationLevel;
16
21
  exec(sql: string, txn?: string): Promise<[QueryResultRow[], QueryResult]>;
22
+ private enqueueTxnQuery;
23
+ private enqueueTxnTask;
24
+ readSchema<ED extends EntityDict & BaseEntityDict>(translator: PostgreSQLTranslator<ED>): Promise<StorageSchema<ED>>;
25
+ inspectSchema<ED extends EntityDict & BaseEntityDict>(translator: PostgreSQLTranslator<ED>): Promise<SchemaInspectionResult<ED>>;
26
+ diffSchema<ED extends EntityDict & BaseEntityDict>(currentSchema: StorageSchema<ED>, targetSchema: StorageSchema<ED>, translator: PostgreSQLTranslator<ED>, options?: MigrationPlanningOptions): Plan<ED>;
17
27
  commitTransaction(txn: string): Promise<void>;
18
28
  rollbackTransaction(txn: string): Promise<void>;
19
29
  /**
@@ -5,13 +5,16 @@ const tslib_1 = require("tslib");
5
5
  const pg_1 = require("pg");
6
6
  const uuid_1 = require("uuid");
7
7
  const assert_1 = tslib_1.__importDefault(require("assert"));
8
+ const migration_1 = require("./migration");
8
9
  class PostgreSQLConnector {
9
10
  pool;
10
11
  configuration;
11
12
  txnDict;
13
+ txnExecQueueDict;
12
14
  constructor(configuration) {
13
15
  this.configuration = configuration;
14
16
  this.txnDict = {};
17
+ this.txnExecQueueDict = {};
15
18
  this.pool = new pg_1.Pool(configuration);
16
19
  // 错误处理
17
20
  this.pool.on('error', (err) => {
@@ -49,12 +52,14 @@ class PostgreSQLConnector {
49
52
  }
50
53
  await connection.query(beginStmt);
51
54
  this.txnDict[id] = connection;
55
+ this.txnExecQueueDict[id] = Promise.resolve();
52
56
  return id;
53
57
  }
54
58
  catch (error) {
55
59
  // 如果启动事务失败,释放连接
56
60
  connection.release();
57
61
  delete this.txnDict[id];
62
+ delete this.txnExecQueueDict[id];
58
63
  throw error;
59
64
  }
60
65
  }
@@ -80,37 +85,58 @@ class PostgreSQLConnector {
80
85
  if (process.env.NODE_ENV === 'development') {
81
86
  // console.log(`SQL: ${sql}; \n`);
82
87
  }
83
- let result;
84
88
  if (txn) {
85
- const connection = this.txnDict[txn];
86
- (0, assert_1.default)(connection, `Transaction ${txn} not found`);
87
- result = await connection.query(sql);
88
- }
89
- else {
90
- result = await this.pool.query(sql);
89
+ const result = await this.enqueueTxnQuery(txn, (connection) => connection.query(sql));
90
+ // 返回格式与 mysql2 兼容: [rows, fields/result]
91
+ return [result.rows, result];
91
92
  }
93
+ const result = await this.pool.query(sql);
92
94
  // 返回格式与 mysql2 兼容: [rows, fields/result]
93
95
  return [result.rows, result];
94
96
  }
97
+ async enqueueTxnQuery(txn, executor) {
98
+ const connection = this.txnDict[txn];
99
+ (0, assert_1.default)(connection, `Transaction ${txn} not found`);
100
+ return this.enqueueTxnTask(txn, () => executor(connection));
101
+ }
102
+ async enqueueTxnTask(txn, executor) {
103
+ const queued = this.txnExecQueueDict[txn] || Promise.resolve();
104
+ const task = queued
105
+ .catch(() => undefined)
106
+ .then(() => executor());
107
+ this.txnExecQueueDict[txn] = task.then(() => undefined, () => undefined);
108
+ return task;
109
+ }
110
+ async readSchema(translator) {
111
+ return (0, migration_1.readPostgreSqlSchema)(this, translator);
112
+ }
113
+ async inspectSchema(translator) {
114
+ return (0, migration_1.inspectPostgreSqlSchema)(this, translator);
115
+ }
116
+ diffSchema(currentSchema, targetSchema, translator, options) {
117
+ return (0, migration_1.buildPostgreSqlMigrationPlan)(currentSchema, targetSchema, translator, options);
118
+ }
95
119
  async commitTransaction(txn) {
96
120
  const connection = this.txnDict[txn];
97
121
  (0, assert_1.default)(connection, `Transaction ${txn} not found`);
122
+ delete this.txnDict[txn];
98
123
  try {
99
- await connection.query('COMMIT');
124
+ await this.enqueueTxnTask(txn, () => connection.query('COMMIT'));
100
125
  }
101
126
  finally {
102
- delete this.txnDict[txn];
127
+ delete this.txnExecQueueDict[txn];
103
128
  connection.release();
104
129
  }
105
130
  }
106
131
  async rollbackTransaction(txn) {
107
132
  const connection = this.txnDict[txn];
108
133
  (0, assert_1.default)(connection, `Transaction ${txn} not found`);
134
+ delete this.txnDict[txn];
109
135
  try {
110
- await connection.query('ROLLBACK');
136
+ await this.enqueueTxnTask(txn, () => connection.query('ROLLBACK'));
111
137
  }
112
138
  finally {
113
- delete this.txnDict[txn];
139
+ delete this.txnExecQueueDict[txn];
114
140
  connection.release();
115
141
  }
116
142
  }
@@ -0,0 +1,10 @@
1
+ import { EntityDict } from 'oak-domain/lib/types';
2
+ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
3
+ import { MigrationSchema, MigrationPlanningOptions, Plan, SchemaInspectionResult } from '../types/migration';
4
+ import { PostgreSQLConnector } from './connector';
5
+ import { PostgreSQLTranslator } from './translator';
6
+ type PostgreSqlMigrationEntityDict = EntityDict & BaseEntityDict;
7
+ export declare function readPostgreSqlSchema<ED extends PostgreSqlMigrationEntityDict>(connector: PostgreSQLConnector, translator: PostgreSQLTranslator<ED>): Promise<MigrationSchema<ED>>;
8
+ export declare function inspectPostgreSqlSchema<ED extends PostgreSqlMigrationEntityDict>(connector: PostgreSQLConnector, translator: PostgreSQLTranslator<ED>): Promise<SchemaInspectionResult<ED>>;
9
+ export declare function buildPostgreSqlMigrationPlan<ED extends PostgreSqlMigrationEntityDict>(currentSchema: MigrationSchema<ED>, targetSchema: MigrationSchema<ED>, translator: PostgreSQLTranslator<ED>, options?: MigrationPlanningOptions): Plan<ED>;
10
+ export {};