@zintrust/db-postgres 0.1.8
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.
- package/dist/index.d.ts +31 -0
- package/dist/index.js +123 -0
- package/dist/register.d.ts +5 -0
- package/dist/register.js +8 -0
- package/package.json +37 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type DatabaseConfig = {
|
|
2
|
+
driver: 'sqlite' | 'postgresql' | 'mysql' | 'sqlserver' | 'd1';
|
|
3
|
+
database?: string;
|
|
4
|
+
host?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
username?: string;
|
|
7
|
+
password?: string;
|
|
8
|
+
synchronize?: boolean;
|
|
9
|
+
logging?: boolean;
|
|
10
|
+
readHosts?: string[];
|
|
11
|
+
};
|
|
12
|
+
export type QueryResult = {
|
|
13
|
+
rows: Record<string, unknown>[];
|
|
14
|
+
rowCount: number;
|
|
15
|
+
};
|
|
16
|
+
export interface IDatabaseAdapter {
|
|
17
|
+
connect(): Promise<void>;
|
|
18
|
+
disconnect(): Promise<void>;
|
|
19
|
+
query(sql: string, parameters: unknown[]): Promise<QueryResult>;
|
|
20
|
+
queryOne(sql: string, parameters: unknown[]): Promise<Record<string, unknown> | null>;
|
|
21
|
+
ping(): Promise<void>;
|
|
22
|
+
transaction<T>(callback: (adapter: IDatabaseAdapter) => Promise<T>): Promise<T>;
|
|
23
|
+
rawQuery<T = unknown>(sql: string, parameters?: unknown[]): Promise<T[]>;
|
|
24
|
+
getType(): string;
|
|
25
|
+
isConnected(): boolean;
|
|
26
|
+
getPlaceholder(index: number): string;
|
|
27
|
+
}
|
|
28
|
+
export declare const PostgreSQLAdapter: Readonly<{
|
|
29
|
+
create(config: DatabaseConfig): IDatabaseAdapter;
|
|
30
|
+
}>;
|
|
31
|
+
export default PostgreSQLAdapter;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ErrorFactory, FeatureFlags, Logger, QueryBuilder } from '@zintrust/core';
|
|
2
|
+
function isMissingEsmPackage(error, packageName) {
|
|
3
|
+
if (error === null || typeof error !== 'object')
|
|
4
|
+
return false;
|
|
5
|
+
const maybe = error;
|
|
6
|
+
if (maybe.code === 'ERR_MODULE_NOT_FOUND') {
|
|
7
|
+
return typeof maybe.message === 'string' && maybe.message.includes(packageName);
|
|
8
|
+
}
|
|
9
|
+
if (typeof maybe.message === 'string') {
|
|
10
|
+
return (maybe.message.includes(`Cannot find package '${packageName}'`) ||
|
|
11
|
+
maybe.message.includes(`Cannot find module '${packageName}'`));
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
export const PostgreSQLAdapter = Object.freeze({
|
|
16
|
+
create(config) {
|
|
17
|
+
return createPostgresAdapter(config);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
function getConnectionParams(config) {
|
|
21
|
+
return {
|
|
22
|
+
host: config.host ?? 'localhost',
|
|
23
|
+
port: config.port ?? 5432,
|
|
24
|
+
database: config.database ?? 'postgres',
|
|
25
|
+
user: config.username ?? 'postgres',
|
|
26
|
+
password: config.password ?? '',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function loadPgPoolCtor() {
|
|
30
|
+
// Dynamic import keeps this package usable even if pg is missing.
|
|
31
|
+
return (await import('pg'));
|
|
32
|
+
}
|
|
33
|
+
function ensurePool(state) {
|
|
34
|
+
if (!state.connected || state.pool === undefined) {
|
|
35
|
+
throw ErrorFactory.createConnectionError('Database not connected');
|
|
36
|
+
}
|
|
37
|
+
return state.pool;
|
|
38
|
+
}
|
|
39
|
+
async function connect(state, config) {
|
|
40
|
+
if (state.connected)
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
const { Pool } = await loadPgPoolCtor();
|
|
44
|
+
const { host, port, database, user, password } = getConnectionParams(config);
|
|
45
|
+
state.pool = new Pool({ host, port, database, user, password });
|
|
46
|
+
await state.pool.query('SELECT 1');
|
|
47
|
+
state.connected = true;
|
|
48
|
+
Logger.info(`✓ PostgreSQL connected (${host}:${port})`);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (isMissingEsmPackage(error, 'pg')) {
|
|
52
|
+
throw ErrorFactory.createConfigError("PostgreSQL adapter requires the 'pg' package (run `zin add db:postgres` or `npm install pg`).");
|
|
53
|
+
}
|
|
54
|
+
throw ErrorFactory.createTryCatchError('Failed to connect to PostgreSQL', error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function disconnect(state) {
|
|
58
|
+
if (!state.connected)
|
|
59
|
+
return;
|
|
60
|
+
const current = state.pool;
|
|
61
|
+
state.pool = undefined;
|
|
62
|
+
state.connected = false;
|
|
63
|
+
if (current !== undefined) {
|
|
64
|
+
await current.end();
|
|
65
|
+
}
|
|
66
|
+
Logger.info('✓ PostgreSQL disconnected');
|
|
67
|
+
}
|
|
68
|
+
async function query(state, sql, parameters) {
|
|
69
|
+
const current = ensurePool(state);
|
|
70
|
+
try {
|
|
71
|
+
const result = await current.query(sql, parameters);
|
|
72
|
+
return {
|
|
73
|
+
rows: (result.rows ?? []),
|
|
74
|
+
rowCount: result.rowCount ?? result.rows?.length ?? 0,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw ErrorFactory.createTryCatchError('PostgreSQL query failed', error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function transaction(state, adapter, callback) {
|
|
82
|
+
if (!state.connected)
|
|
83
|
+
throw ErrorFactory.createConnectionError('Database not connected');
|
|
84
|
+
try {
|
|
85
|
+
await adapter.query('BEGIN', []);
|
|
86
|
+
const result = await callback(adapter);
|
|
87
|
+
await adapter.query('COMMIT', []);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
await adapter.query('ROLLBACK', []);
|
|
92
|
+
throw ErrorFactory.createTryCatchError('PostgreSQL transaction failed', error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function rawQuery(adapter, sql, parameters) {
|
|
96
|
+
if (!FeatureFlags.isRawQueryEnabled()) {
|
|
97
|
+
throw ErrorFactory.createConfigError('Raw SQL queries are disabled. Set USE_RAW_QRY=true environment variable to enable.');
|
|
98
|
+
}
|
|
99
|
+
const result = await adapter.query(sql, parameters ?? []);
|
|
100
|
+
return result.rows;
|
|
101
|
+
}
|
|
102
|
+
function createPostgresAdapter(config) {
|
|
103
|
+
const state = { connected: false, pool: undefined };
|
|
104
|
+
const adapter = {
|
|
105
|
+
connect: async () => connect(state, config),
|
|
106
|
+
disconnect: async () => disconnect(state),
|
|
107
|
+
query: async (sql, parameters) => query(state, sql, parameters),
|
|
108
|
+
queryOne: async (sql, parameters) => {
|
|
109
|
+
const result = await adapter.query(sql, parameters);
|
|
110
|
+
return result.rows[0] ?? null;
|
|
111
|
+
},
|
|
112
|
+
ping: async () => {
|
|
113
|
+
await adapter.query(QueryBuilder.create('').select('1').toSQL(), []);
|
|
114
|
+
},
|
|
115
|
+
transaction: async (callback) => transaction(state, adapter, callback),
|
|
116
|
+
rawQuery: async (sql, parameters) => rawQuery(adapter, sql, parameters),
|
|
117
|
+
getType: () => 'postgresql',
|
|
118
|
+
isConnected: () => state.connected,
|
|
119
|
+
getPlaceholder: (index) => `$${index}`,
|
|
120
|
+
};
|
|
121
|
+
return adapter;
|
|
122
|
+
}
|
|
123
|
+
export default PostgreSQLAdapter;
|
package/dist/register.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PostgreSQLAdapter } from './index.js';
|
|
2
|
+
export function registerPostgresAdapter(registry) {
|
|
3
|
+
registry.register('postgresql', (config) => PostgreSQLAdapter.create(config));
|
|
4
|
+
}
|
|
5
|
+
const core = (await import('@zintrust/core'));
|
|
6
|
+
if (core.DatabaseAdapterRegistry !== undefined) {
|
|
7
|
+
registerPostgresAdapter(core.DatabaseAdapterRegistry);
|
|
8
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zintrust/db-postgres",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./register": {
|
|
17
|
+
"types": "./dist/register.d.ts",
|
|
18
|
+
"default": "./dist/register.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.0.0"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@zintrust/core": "^0.1.8"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"pg": "^8.16.3"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p tsconfig.json",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
}
|
|
37
|
+
}
|