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.
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgreSQLConnector = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pg_1 = require("pg");
6
+ const uuid_1 = require("uuid");
7
+ const assert_1 = tslib_1.__importDefault(require("assert"));
8
+ class PostgreSQLConnector {
9
+ pool;
10
+ configuration;
11
+ txnDict;
12
+ constructor(configuration) {
13
+ this.configuration = configuration;
14
+ this.txnDict = {};
15
+ this.pool = new pg_1.Pool(configuration);
16
+ // 错误处理
17
+ this.pool.on('error', (err) => {
18
+ console.error('PostgreSQL pool error:', err);
19
+ });
20
+ }
21
+ connect() {
22
+ // pg Pool 是惰性连接,不需要显式连接
23
+ // 但可以在这里进行连接测试
24
+ }
25
+ async disconnect() {
26
+ // 先获取所有事务ID的快照
27
+ const txnIds = Object.keys(this.txnDict);
28
+ for (const txnId of txnIds) {
29
+ try {
30
+ await this.rollbackTransaction(txnId);
31
+ }
32
+ catch (e) {
33
+ console.error(`Failed to rollback transaction ${txnId}:`, e);
34
+ }
35
+ }
36
+ await this.pool.end();
37
+ }
38
+ 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;
67
+ }
68
+ };
69
+ return startInner();
70
+ }
71
+ /**
72
+ * 映射隔离级别到 PostgreSQL 语法
73
+ */
74
+ mapIsolationLevel(level) {
75
+ const levelUpper = level.toUpperCase().replace(/[-_]/g, ' '); // 同时处理 - 和 _
76
+ const validLevels = [
77
+ 'READ UNCOMMITTED',
78
+ 'READ COMMITTED',
79
+ 'REPEATABLE READ',
80
+ 'SERIALIZABLE'
81
+ ];
82
+ if (validLevels.includes(levelUpper)) {
83
+ return levelUpper;
84
+ }
85
+ // 默认使用 READ COMMITTED
86
+ console.warn(`Unknown isolation level "${level}", using READ COMMITTED`);
87
+ return 'READ COMMITTED';
88
+ }
89
+ async exec(sql, txn) {
90
+ if (process.env.NODE_ENV === 'development') {
91
+ // console.log(`SQL: ${sql}; \n`);
92
+ }
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
+ }
103
+ // 返回格式与 mysql2 兼容: [rows, fields/result]
104
+ return [result.rows, result];
105
+ }
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
+ }
113
+ }
114
+ async commitTransaction(txn) {
115
+ const connection = this.txnDict[txn];
116
+ (0, assert_1.default)(connection, `Transaction ${txn} not found`);
117
+ try {
118
+ await connection.query('COMMIT');
119
+ }
120
+ finally {
121
+ delete this.txnDict[txn];
122
+ connection.release();
123
+ }
124
+ }
125
+ async rollbackTransaction(txn) {
126
+ const connection = this.txnDict[txn];
127
+ (0, assert_1.default)(connection, `Transaction ${txn} not found`);
128
+ try {
129
+ await connection.query('ROLLBACK');
130
+ }
131
+ finally {
132
+ delete this.txnDict[txn];
133
+ connection.release();
134
+ }
135
+ }
136
+ /**
137
+ * 获取连接池状态
138
+ */
139
+ getPoolStatus() {
140
+ return {
141
+ total: this.pool.totalCount,
142
+ idle: this.pool.idleCount,
143
+ waiting: this.pool.waitingCount
144
+ };
145
+ }
146
+ }
147
+ exports.PostgreSQLConnector = PostgreSQLConnector;
@@ -0,0 +1,50 @@
1
+ import { EntityDict, OperateOption, OperationResult, TxnOption, StorageSchema, SelectOption, AggregationResult } from 'oak-domain/lib/types';
2
+ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
3
+ import { CascadeStore } from 'oak-domain/lib/store/CascadeStore';
4
+ import { PostgreSQLConfiguration } from './types/Configuration';
5
+ import { PostgreSQLConnector } from './connector';
6
+ import { PostgreSQLTranslator, PostgreSQLSelectOption, PostgreSQLOperateOption } from './translator';
7
+ import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
8
+ import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
9
+ import { CreateEntityOption } from '../types/Translator';
10
+ import { DbStore, Plan } from '../types/dbStore';
11
+ export declare class PostgreSQLStore<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends CascadeStore<ED> implements DbStore<ED, Cxt> {
12
+ 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
+ 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
+ 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
+ protected updateAbjointRow<T extends keyof ED, OP extends OperateOption>(entity: T, operation: ED[T]['Operation'], context: SyncContext<ED>, option: OP): number;
16
+ exec(script: string, txnId?: string): Promise<void>;
17
+ connector: PostgreSQLConnector;
18
+ translator: PostgreSQLTranslator<ED>;
19
+ constructor(storageSchema: StorageSchema<ED>, configuration: PostgreSQLConfiguration);
20
+ checkRelationAsync<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, operation: Omit<ED[T]['Operation'] | ED[T]['Selection'], 'id'>, context: Cxt): Promise<void>;
21
+ protected aggregateAbjointRowAsync<T extends keyof ED, OP extends SelectOption, Cxt extends AsyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
22
+ aggregate<T extends keyof ED, OP extends SelectOption>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
23
+ protected supportManyToOneJoin(): boolean;
24
+ protected supportMultipleCreate(): boolean;
25
+ private formResult;
26
+ protected selectAbjointRowAsync<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: AsyncContext<ED>, option?: PostgreSQLSelectOption): Promise<Partial<ED[T]['Schema']>[]>;
27
+ protected updateAbjointRowAsync<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: AsyncContext<ED>, option?: PostgreSQLOperateOption): Promise<number>;
28
+ operate<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt, option: OperateOption): Promise<OperationResult<ED>>;
29
+ select<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: SelectOption): Promise<Partial<ED[T]['Schema']>[]>;
30
+ protected countAbjointRowAsync<T extends keyof ED>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: AsyncContext<ED>, option: SelectOption): Promise<number>;
31
+ count<T extends keyof ED>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: SelectOption): Promise<number>;
32
+ begin(option?: TxnOption): Promise<string>;
33
+ commit(txnId: string): Promise<void>;
34
+ rollback(txnId: string): Promise<void>;
35
+ connect(): Promise<void>;
36
+ disconnect(): Promise<void>;
37
+ initialize(option: CreateEntityOption): Promise<void>;
38
+ readSchema(): Promise<StorageSchema<ED>>;
39
+ /**
40
+ * 根据载入的dataSchema,和数据库中原来的schema,决定如何来upgrade
41
+ * 制订出来的plan分为两阶段:增加阶段和削减阶段,在两个阶段之间,由用户来修正数据
42
+ */
43
+ makeUpgradePlan(): Promise<Plan>;
44
+ /**
45
+ * 比较两个schema的不同,这里计算的是new对old的增量
46
+ * @param schemaOld
47
+ * @param schemaNew
48
+ */
49
+ diffSchema(schemaOld: StorageSchema<any>, schemaNew: StorageSchema<any>): Plan;
50
+ }