oak-db 3.3.13 → 4.0.0

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.
@@ -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) => {
@@ -36,37 +39,29 @@ class PostgreSQLConnector {
36
39
  await this.pool.end();
37
40
  }
38
41
  async startTransaction(option) {
39
- const startInner = async () => {
40
- const connection = await this.pool.connect();
41
- // 添加:检测连接是否已被其他事务占用
42
- for (const txn2 in this.txnDict) {
43
- if (this.txnDict[txn2] === connection) {
44
- return new Promise((resolve) => {
45
- this.pool.on('release', () => resolve(startInner()));
46
- });
47
- }
48
- }
49
- try {
50
- let beginStmt = 'BEGIN';
51
- if (option?.isolationLevel) {
52
- // PostgreSQL 隔离级别:
53
- // READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE
54
- // 注意: PostgreSQL 的 READ UNCOMMITTED 行为等同于 READ COMMITTED
55
- const level = this.mapIsolationLevel(option.isolationLevel);
56
- beginStmt = `BEGIN ISOLATION LEVEL ${level}`;
57
- }
58
- await connection.query(beginStmt);
59
- const id = (0, uuid_1.v4)();
60
- this.txnDict[id] = connection;
61
- return id;
62
- }
63
- catch (error) {
64
- // 如果启动事务失败,释放连接
65
- connection.release();
66
- throw error;
42
+ const connection = await this.pool.connect();
43
+ const id = (0, uuid_1.v4)();
44
+ try {
45
+ let beginStmt = 'BEGIN';
46
+ if (option?.isolationLevel) {
47
+ // PostgreSQL 隔离级别:
48
+ // READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE
49
+ // 注意: PostgreSQL 的 READ UNCOMMITTED 行为等同于 READ COMMITTED
50
+ const level = this.mapIsolationLevel(option.isolationLevel);
51
+ beginStmt = `BEGIN ISOLATION LEVEL ${level}`;
67
52
  }
68
- };
69
- return startInner();
53
+ await connection.query(beginStmt);
54
+ this.txnDict[id] = connection;
55
+ this.txnExecQueueDict[id] = Promise.resolve();
56
+ return id;
57
+ }
58
+ catch (error) {
59
+ // 如果启动事务失败,释放连接
60
+ connection.release();
61
+ delete this.txnDict[id];
62
+ delete this.txnExecQueueDict[id];
63
+ throw error;
64
+ }
70
65
  }
71
66
  /**
72
67
  * 映射隔离级别到 PostgreSQL 语法
@@ -90,46 +85,58 @@ class PostgreSQLConnector {
90
85
  if (process.env.NODE_ENV === 'development') {
91
86
  // console.log(`SQL: ${sql}; \n`);
92
87
  }
93
- try {
94
- let result;
95
- if (txn) {
96
- const connection = this.txnDict[txn];
97
- (0, assert_1.default)(connection, `Transaction ${txn} not found`);
98
- result = await connection.query(sql);
99
- }
100
- else {
101
- result = await this.pool.query(sql);
102
- }
88
+ if (txn) {
89
+ const result = await this.enqueueTxnQuery(txn, (connection) => connection.query(sql));
103
90
  // 返回格式与 mysql2 兼容: [rows, fields/result]
104
91
  return [result.rows, result];
105
92
  }
106
- catch (error) {
107
- // 增强错误信息
108
- const enhancedError = new Error(`PostgreSQL query failed: ${error.message}\nSQL: ${sql.slice(0, 500)}${sql.length > 500 ? '...' : ''}`);
109
- enhancedError.originalError = error;
110
- enhancedError.sql = sql;
111
- throw enhancedError;
112
- }
93
+ const result = await this.pool.query(sql);
94
+ // 返回格式与 mysql2 兼容: [rows, fields/result]
95
+ return [result.rows, result];
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);
113
118
  }
114
119
  async commitTransaction(txn) {
115
120
  const connection = this.txnDict[txn];
116
121
  (0, assert_1.default)(connection, `Transaction ${txn} not found`);
122
+ delete this.txnDict[txn];
117
123
  try {
118
- await connection.query('COMMIT');
124
+ await this.enqueueTxnTask(txn, () => connection.query('COMMIT'));
119
125
  }
120
126
  finally {
121
- delete this.txnDict[txn];
127
+ delete this.txnExecQueueDict[txn];
122
128
  connection.release();
123
129
  }
124
130
  }
125
131
  async rollbackTransaction(txn) {
126
132
  const connection = this.txnDict[txn];
127
133
  (0, assert_1.default)(connection, `Transaction ${txn} not found`);
134
+ delete this.txnDict[txn];
128
135
  try {
129
- await connection.query('ROLLBACK');
136
+ await this.enqueueTxnTask(txn, () => connection.query('ROLLBACK'));
130
137
  }
131
138
  finally {
132
- delete this.txnDict[txn];
139
+ delete this.txnExecQueueDict[txn];
133
140
  connection.release();
134
141
  }
135
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 {};