@an5/adapters 0.1.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.
Files changed (91) hide show
  1. package/README.md +263 -0
  2. package/dotnet/An5Adapter.cs +275 -0
  3. package/dotnet/Base/Core.cs +82 -0
  4. package/dotnet/Mssql/MssqlEngine.cs +144 -0
  5. package/dotnet/Postgres/PostgresEngine.cs +121 -0
  6. package/package.json +46 -0
  7. package/python/an5_adapter.py +97 -0
  8. package/python/base/__init__.py +3 -0
  9. package/python/base/dialects.py +8 -0
  10. package/python/base/metadata.py +9 -0
  11. package/python/base/sql.py +121 -0
  12. package/python/mssql/__init__.py +1 -0
  13. package/python/mssql/provider.py +62 -0
  14. package/python/postgres/__init__.py +1 -0
  15. package/python/postgres/provider.py +15 -0
  16. package/python/table_client.py +209 -0
  17. package/typescript/an5Adapter.d.ts +117 -0
  18. package/typescript/an5Adapter.js +447 -0
  19. package/typescript/an5Adapter.ts +474 -0
  20. package/typescript/base/index.d.ts +3 -0
  21. package/typescript/base/index.js +19 -0
  22. package/typescript/base/index.ts +3 -0
  23. package/typescript/base/metadata.d.ts +14 -0
  24. package/typescript/base/metadata.js +17 -0
  25. package/typescript/base/metadata.ts +28 -0
  26. package/typescript/base/sql.d.ts +4 -0
  27. package/typescript/base/sql.js +143 -0
  28. package/typescript/base/sql.ts +98 -0
  29. package/typescript/base/types.d.ts +21 -0
  30. package/typescript/base/types.js +2 -0
  31. package/typescript/base/types.ts +24 -0
  32. package/typescript/config.d.ts +17 -0
  33. package/typescript/config.js +92 -0
  34. package/typescript/config.ts +95 -0
  35. package/typescript/googlesheets/adapter.d.ts +31 -0
  36. package/typescript/googlesheets/adapter.js +138 -0
  37. package/typescript/googlesheets/adapter.ts +167 -0
  38. package/typescript/googlesheets/an5SheetsAdapter.d.ts +3 -0
  39. package/typescript/googlesheets/an5SheetsAdapter.js +8 -0
  40. package/typescript/googlesheets/an5SheetsAdapter.ts +3 -0
  41. package/typescript/googlesheets/config.d.ts +17 -0
  42. package/typescript/googlesheets/config.js +29 -0
  43. package/typescript/googlesheets/config.ts +33 -0
  44. package/typescript/googlesheets/helpers.d.ts +9 -0
  45. package/typescript/googlesheets/helpers.js +155 -0
  46. package/typescript/googlesheets/helpers.ts +124 -0
  47. package/typescript/googlesheets/index.d.ts +2 -0
  48. package/typescript/googlesheets/index.js +9 -0
  49. package/typescript/googlesheets/index.ts +2 -0
  50. package/typescript/googlesheets/parseConnectionString.d.ts +11 -0
  51. package/typescript/googlesheets/parseConnectionString.js +44 -0
  52. package/typescript/googlesheets/parseConnectionString.ts +44 -0
  53. package/typescript/googlesheets/retry.d.ts +3 -0
  54. package/typescript/googlesheets/retry.js +26 -0
  55. package/typescript/googlesheets/retry.ts +23 -0
  56. package/typescript/googlesheets/sqlExecutor.d.ts +12 -0
  57. package/typescript/googlesheets/sqlExecutor.js +306 -0
  58. package/typescript/googlesheets/sqlExecutor.ts +301 -0
  59. package/typescript/googlesheets/tableClient.d.ts +78 -0
  60. package/typescript/googlesheets/tableClient.js +394 -0
  61. package/typescript/googlesheets/tableClient.ts +434 -0
  62. package/typescript/googlesheets/types.d.ts +4 -0
  63. package/typescript/googlesheets/types.js +3 -0
  64. package/typescript/googlesheets/types.ts +6 -0
  65. package/typescript/index.d.ts +2 -0
  66. package/typescript/index.js +14 -0
  67. package/typescript/index.ts +15 -0
  68. package/typescript/mssql/engine.d.ts +16 -0
  69. package/typescript/mssql/engine.js +138 -0
  70. package/typescript/mssql/engine.ts +132 -0
  71. package/typescript/mssql/index.d.ts +1 -0
  72. package/typescript/mssql/index.js +17 -0
  73. package/typescript/mssql/index.ts +1 -0
  74. package/typescript/mysql/engine.d.ts +13 -0
  75. package/typescript/mysql/engine.js +77 -0
  76. package/typescript/mysql/engine.ts +80 -0
  77. package/typescript/mysql/index.d.ts +1 -0
  78. package/typescript/mysql/index.js +17 -0
  79. package/typescript/mysql/index.ts +1 -0
  80. package/typescript/postgres/engine.d.ts +13 -0
  81. package/typescript/postgres/engine.js +86 -0
  82. package/typescript/postgres/engine.ts +87 -0
  83. package/typescript/postgres/index.d.ts +1 -0
  84. package/typescript/postgres/index.js +17 -0
  85. package/typescript/postgres/index.ts +1 -0
  86. package/typescript/sqlite/engine.d.ts +13 -0
  87. package/typescript/sqlite/engine.js +58 -0
  88. package/typescript/sqlite/engine.ts +55 -0
  89. package/typescript/sqlite/index.d.ts +1 -0
  90. package/typescript/sqlite/index.js +17 -0
  91. package/typescript/sqlite/index.ts +1 -0
@@ -0,0 +1,132 @@
1
+ import sql from 'mssql';
2
+ import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
3
+
4
+ // ─── MSSQL Connection Config ───────────────────────────────────────────────────────
5
+
6
+ export function parseMssqlConnectionString(url: string): sql.config {
7
+ let cleanUrl = (url || '').trim();
8
+ // Strip scheme prefix
9
+ cleanUrl = cleanUrl.replace(/^(?:sqlserver|mssql):\/\//i, '');
10
+
11
+ const parts = cleanUrl.split(';');
12
+ const firstPart = parts[0].trim();
13
+
14
+ // host:port or host,port (SQL Server native style)
15
+ let server = firstPart;
16
+ let port = 1433;
17
+ const commaIdx = firstPart.lastIndexOf(',');
18
+ const colonIdx = firstPart.lastIndexOf(':');
19
+ if (commaIdx !== -1) {
20
+ server = firstPart.slice(0, commaIdx).trim();
21
+ port = parseInt(firstPart.slice(commaIdx + 1), 10) || 1433;
22
+ } else if (colonIdx !== -1 && !firstPart.includes('=')) {
23
+ server = firstPart.slice(0, colonIdx).trim();
24
+ port = parseInt(firstPart.slice(colonIdx + 1), 10) || 1433;
25
+ }
26
+
27
+ const config: any = {
28
+ server,
29
+ port,
30
+ options: { encrypt: true, trustServerCertificate: true },
31
+ pool: { max: 10, min: 0, idleTimeoutMillis: 30000 },
32
+ requestTimeout: 60000,
33
+ connectionTimeout: 15000,
34
+ };
35
+
36
+ for (let i = 1; i < parts.length; i++) {
37
+ const part = parts[i].trim();
38
+ if (!part) continue;
39
+ const eqIdx = part.indexOf('=');
40
+ if (eqIdx === -1) continue;
41
+ const key = part.slice(0, eqIdx).trim().toLowerCase();
42
+ const value = decodeURIComponent(part.slice(eqIdx + 1).trim());
43
+ if (key === 'database' || key === 'initial catalog') config.database = value;
44
+ else if (key === 'user' || key === 'uid' || key === 'user id') config.user = value;
45
+ else if (key === 'password' || key === 'pwd') config.password = value;
46
+ else if (key === 'server' || key === 'data source') {
47
+ // SERVER=host,port style (key-value form)
48
+ const [s, p] = value.split(',');
49
+ config.server = s.trim();
50
+ if (p) config.port = parseInt(p.trim(), 10) || 1433;
51
+ }
52
+ else if (key === 'encrypt') config.options.encrypt = value.toLowerCase() === 'true';
53
+ else if (key === 'trustservercertificate') config.options.trustServerCertificate = value.toLowerCase() === 'true';
54
+ else if (key === 'connection timeout') config.connectionTimeout = parseInt(value, 10) * 1000;
55
+ }
56
+ return config;
57
+ }
58
+
59
+ // ─── MSSQL Engine ──────────────────────────────────────────────────────────────────
60
+
61
+ export class MssqlEngine implements QueryEngine {
62
+ dialect: Dialect = 'mssql';
63
+ private pool: Promise<sql.ConnectionPool> | null = null;
64
+ private config: sql.config;
65
+
66
+ constructor(adapterConfig: An5AdapterConfig) {
67
+ this.config = parseMssqlConnectionString(adapterConfig.connectionString);
68
+ if (adapterConfig.poolMax) this.config.pool = { ...this.config.pool, max: adapterConfig.poolMax };
69
+ if (adapterConfig.requestTimeout) this.config.requestTimeout = adapterConfig.requestTimeout;
70
+ if (adapterConfig.connectionTimeout) this.config.connectionTimeout = adapterConfig.connectionTimeout;
71
+ }
72
+
73
+ private async getPool(): Promise<sql.ConnectionPool> {
74
+ if (!this.pool) this.pool = new sql.ConnectionPool(this.config).connect();
75
+ return this.pool;
76
+ }
77
+
78
+ private attachParams(req: sql.Request, params?: Record<string, any>): void {
79
+ if (params) for (const [k, v] of Object.entries(params)) req.input(k, v ?? null);
80
+ }
81
+
82
+ async exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]> {
83
+ const pool = await this.getPool();
84
+ const req = new sql.Request(pool);
85
+ this.attachParams(req, params);
86
+ const result = await req.query(query);
87
+ return (result.recordset || []) as T[];
88
+ }
89
+
90
+ async executeRaw(query: string, params?: Record<string, any>): Promise<number> {
91
+ const pool = await this.getPool();
92
+ const req = new sql.Request(pool);
93
+ this.attachParams(req, params);
94
+ const result = await req.query(query);
95
+ return result.rowsAffected[0] ?? 0;
96
+ }
97
+
98
+ async connect(): Promise<void> { await this.getPool(); }
99
+
100
+ async disconnect(): Promise<void> {
101
+ if (this.pool) {
102
+ const p = await this.pool;
103
+ await p.close();
104
+ this.pool = null;
105
+ }
106
+ }
107
+
108
+ async beginTransaction(): Promise<TransactionHandle> {
109
+ const pool = await this.getPool();
110
+ const tx = new sql.Transaction(pool);
111
+ await tx.begin();
112
+
113
+ const buildReq = (params?: Record<string, any>) => {
114
+ const req = new sql.Request(tx);
115
+ if (params) for (const [k, v] of Object.entries(params)) req.input(k, v ?? null);
116
+ return req;
117
+ };
118
+
119
+ return {
120
+ exec: async <T>(q: string, p?: Record<string, any>) => {
121
+ const r = await buildReq(p).query(q);
122
+ return (r.recordset || []) as T[];
123
+ },
124
+ executeRaw: async (q: string, p?: Record<string, any>) => {
125
+ const r = await buildReq(p).query(q);
126
+ return r.rowsAffected[0] ?? 0;
127
+ },
128
+ commit: () => tx.commit(),
129
+ rollback: () => tx.rollback(),
130
+ };
131
+ }
132
+ }
@@ -0,0 +1 @@
1
+ export * from './engine';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./engine"), exports);
@@ -0,0 +1 @@
1
+ export * from './engine';
@@ -0,0 +1,13 @@
1
+ import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
2
+ export declare class MysqlEngine implements QueryEngine {
3
+ dialect: Dialect;
4
+ private pool;
5
+ constructor(adapterConfig: An5AdapterConfig);
6
+ /** Convert @name → ? (positional); return ordered values */
7
+ private transform;
8
+ exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]>;
9
+ executeRaw(query: string, params?: Record<string, any>): Promise<number>;
10
+ connect(): Promise<void>;
11
+ disconnect(): Promise<void>;
12
+ beginTransaction(): Promise<TransactionHandle>;
13
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MysqlEngine = void 0;
4
+ // ─── MySQL Engine ──────────────────────────────────────────────────────────────────
5
+ let Mysql2 = null;
6
+ try {
7
+ Mysql2 = require('mysql2/promise');
8
+ }
9
+ catch { }
10
+ class MysqlEngine {
11
+ constructor(adapterConfig) {
12
+ this.dialect = 'mysql';
13
+ this.pool = null;
14
+ if (!Mysql2)
15
+ throw new Error('mysql2 package is required for MySQL support. Run: npm install mysql2');
16
+ this.pool = Mysql2.createPool({
17
+ uri: adapterConfig.connectionString,
18
+ connectionLimit: adapterConfig.poolMax ?? 10,
19
+ connectTimeout: adapterConfig.connectionTimeout ?? 15000,
20
+ });
21
+ }
22
+ /** Convert @name → ? (positional); return ordered values */
23
+ transform(query, params) {
24
+ if (!params || Object.keys(params).length === 0)
25
+ return { text: query, values: [] };
26
+ const values = [];
27
+ const text = query.replace(/@(\w+)/g, (_, name) => {
28
+ values.push(params[name] ?? null);
29
+ return '?';
30
+ });
31
+ return { text, values };
32
+ }
33
+ async exec(query, params) {
34
+ const { text, values } = this.transform(query, params);
35
+ const [rows] = await this.pool.query(text, values);
36
+ return rows;
37
+ }
38
+ async executeRaw(query, params) {
39
+ const { text, values } = this.transform(query, params);
40
+ const [result] = await this.pool.query(text, values);
41
+ return result.affectedRows ?? 0;
42
+ }
43
+ async connect() {
44
+ const conn = await this.pool.getConnection();
45
+ conn.release();
46
+ }
47
+ async disconnect() { await this.pool.end(); }
48
+ async beginTransaction() {
49
+ const conn = await this.pool.getConnection();
50
+ await conn.beginTransaction();
51
+ const transform = (query, params) => {
52
+ if (!params || Object.keys(params).length === 0)
53
+ return { text: query, values: [] };
54
+ const values = [];
55
+ const text = query.replace(/@(\w+)/g, (_, name) => {
56
+ values.push(params[name] ?? null);
57
+ return '?';
58
+ });
59
+ return { text, values };
60
+ };
61
+ return {
62
+ exec: async (q, p) => {
63
+ const { text, values } = transform(q, p);
64
+ const [rows] = await conn.query(text, values);
65
+ return rows;
66
+ },
67
+ executeRaw: async (q, p) => {
68
+ const { text, values } = transform(q, p);
69
+ const [result] = await conn.query(text, values);
70
+ return result.affectedRows ?? 0;
71
+ },
72
+ commit: async () => { await conn.commit(); conn.release(); },
73
+ rollback: async () => { await conn.rollback(); conn.release(); },
74
+ };
75
+ }
76
+ }
77
+ exports.MysqlEngine = MysqlEngine;
@@ -0,0 +1,80 @@
1
+ import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
2
+
3
+ // ─── MySQL Engine ──────────────────────────────────────────────────────────────────
4
+
5
+ let Mysql2: any = null;
6
+ try { Mysql2 = require('mysql2/promise'); } catch { }
7
+
8
+ export class MysqlEngine implements QueryEngine {
9
+ dialect: Dialect = 'mysql';
10
+ private pool: any = null;
11
+
12
+ constructor(adapterConfig: An5AdapterConfig) {
13
+ if (!Mysql2) throw new Error('mysql2 package is required for MySQL support. Run: npm install mysql2');
14
+ this.pool = Mysql2.createPool({
15
+ uri: adapterConfig.connectionString,
16
+ connectionLimit: adapterConfig.poolMax ?? 10,
17
+ connectTimeout: adapterConfig.connectionTimeout ?? 15000,
18
+ });
19
+ }
20
+
21
+ /** Convert @name → ? (positional); return ordered values */
22
+ private transform(query: string, params?: Record<string, any>): { text: string; values: any[] } {
23
+ if (!params || Object.keys(params).length === 0) return { text: query, values: [] };
24
+ const values: any[] = [];
25
+ const text = query.replace(/@(\w+)/g, (_, name: string) => {
26
+ values.push(params[name] ?? null);
27
+ return '?';
28
+ });
29
+ return { text, values };
30
+ }
31
+
32
+ async exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]> {
33
+ const { text, values } = this.transform(query, params);
34
+ const [rows] = await this.pool.query(text, values);
35
+ return rows as T[];
36
+ }
37
+
38
+ async executeRaw(query: string, params?: Record<string, any>): Promise<number> {
39
+ const { text, values } = this.transform(query, params);
40
+ const [result] = await this.pool.query(text, values);
41
+ return (result as any).affectedRows ?? 0;
42
+ }
43
+
44
+ async connect(): Promise<void> {
45
+ const conn = await this.pool.getConnection();
46
+ conn.release();
47
+ }
48
+
49
+ async disconnect(): Promise<void> { await this.pool.end(); }
50
+
51
+ async beginTransaction(): Promise<TransactionHandle> {
52
+ const conn = await this.pool.getConnection();
53
+ await conn.beginTransaction();
54
+
55
+ const transform = (query: string, params?: Record<string, any>) => {
56
+ if (!params || Object.keys(params).length === 0) return { text: query, values: [] };
57
+ const values: any[] = [];
58
+ const text = query.replace(/@(\w+)/g, (_, name: string) => {
59
+ values.push(params[name] ?? null);
60
+ return '?';
61
+ });
62
+ return { text, values };
63
+ };
64
+
65
+ return {
66
+ exec: async <T>(q: string, p?: Record<string, any>) => {
67
+ const { text, values } = transform(q, p);
68
+ const [rows] = await conn.query(text, values);
69
+ return rows as T[];
70
+ },
71
+ executeRaw: async (q: string, p?: Record<string, any>) => {
72
+ const { text, values } = transform(q, p);
73
+ const [result] = await conn.query(text, values);
74
+ return (result as any).affectedRows ?? 0;
75
+ },
76
+ commit: async () => { await conn.commit(); conn.release(); },
77
+ rollback: async () => { await conn.rollback(); conn.release(); },
78
+ };
79
+ }
80
+ }
@@ -0,0 +1 @@
1
+ export * from './engine';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./engine"), exports);
@@ -0,0 +1 @@
1
+ export * from './engine';
@@ -0,0 +1,13 @@
1
+ import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
2
+ export declare class PostgresEngine implements QueryEngine {
3
+ dialect: Dialect;
4
+ private pool;
5
+ constructor(adapterConfig: An5AdapterConfig);
6
+ /** Convert @name → $N; identical names reuse the same $N */
7
+ private transform;
8
+ exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]>;
9
+ executeRaw(query: string, params?: Record<string, any>): Promise<number>;
10
+ connect(): Promise<void>;
11
+ disconnect(): Promise<void>;
12
+ beginTransaction(): Promise<TransactionHandle>;
13
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresEngine = void 0;
4
+ // ─── PostgreSQL Engine ─────────────────────────────────────────────────────────────
5
+ let PgPool = null;
6
+ try {
7
+ PgPool = require('pg').Pool;
8
+ }
9
+ catch { }
10
+ class PostgresEngine {
11
+ constructor(adapterConfig) {
12
+ this.dialect = 'postgres';
13
+ this.pool = null;
14
+ if (!PgPool)
15
+ throw new Error('pg package is required for PostgreSQL support. Run: npm install pg');
16
+ this.pool = new PgPool({
17
+ connectionString: adapterConfig.connectionString,
18
+ max: adapterConfig.poolMax ?? 10,
19
+ });
20
+ }
21
+ /** Convert @name → $N; identical names reuse the same $N */
22
+ transform(query, params) {
23
+ if (!params || Object.keys(params).length === 0)
24
+ return { text: query, values: [] };
25
+ const values = [];
26
+ const seen = {};
27
+ const text = query.replace(/@(\w+)/g, (_, name) => {
28
+ if (seen[name] !== undefined)
29
+ return `$${seen[name]}`;
30
+ const idx = values.length + 1;
31
+ seen[name] = idx;
32
+ values.push(params[name] ?? null);
33
+ return `$${idx}`;
34
+ });
35
+ return { text, values };
36
+ }
37
+ async exec(query, params) {
38
+ const { text, values } = this.transform(query, params);
39
+ const result = await this.pool.query(text, values);
40
+ return result.rows;
41
+ }
42
+ async executeRaw(query, params) {
43
+ const { text, values } = this.transform(query, params);
44
+ const result = await this.pool.query(text, values);
45
+ return result.rowCount ?? 0;
46
+ }
47
+ async connect() {
48
+ const client = await this.pool.connect();
49
+ client.release();
50
+ }
51
+ async disconnect() { await this.pool.end(); }
52
+ async beginTransaction() {
53
+ const client = await this.pool.connect();
54
+ await client.query('BEGIN');
55
+ const transform = (query, params) => {
56
+ if (!params || Object.keys(params).length === 0)
57
+ return { text: query, values: [] };
58
+ const values = [];
59
+ const seen = {};
60
+ const text = query.replace(/@(\w+)/g, (_, name) => {
61
+ if (seen[name] !== undefined)
62
+ return `$${seen[name]}`;
63
+ const idx = values.length + 1;
64
+ seen[name] = idx;
65
+ values.push(params[name] ?? null);
66
+ return `$${idx}`;
67
+ });
68
+ return { text, values };
69
+ };
70
+ return {
71
+ exec: async (q, p) => {
72
+ const { text, values } = transform(q, p);
73
+ const r = await client.query(text, values);
74
+ return (r.rows || []);
75
+ },
76
+ executeRaw: async (q, p) => {
77
+ const { text, values } = transform(q, p);
78
+ const r = await client.query(text, values);
79
+ return r.rowCount ?? 0;
80
+ },
81
+ commit: async () => { await client.query('COMMIT'); client.release(); },
82
+ rollback: async () => { await client.query('ROLLBACK'); client.release(); },
83
+ };
84
+ }
85
+ }
86
+ exports.PostgresEngine = PostgresEngine;
@@ -0,0 +1,87 @@
1
+ import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
2
+
3
+ // ─── PostgreSQL Engine ─────────────────────────────────────────────────────────────
4
+
5
+ let PgPool: any = null;
6
+ try { PgPool = require('pg').Pool; } catch { }
7
+
8
+ export class PostgresEngine implements QueryEngine {
9
+ dialect: Dialect = 'postgres';
10
+ private pool: any = null;
11
+
12
+ constructor(adapterConfig: An5AdapterConfig) {
13
+ if (!PgPool) throw new Error('pg package is required for PostgreSQL support. Run: npm install pg');
14
+ this.pool = new PgPool({
15
+ connectionString: adapterConfig.connectionString,
16
+ max: adapterConfig.poolMax ?? 10,
17
+ });
18
+ }
19
+
20
+ /** Convert @name → $N; identical names reuse the same $N */
21
+ private transform(query: string, params?: Record<string, any>): { text: string; values: any[] } {
22
+ if (!params || Object.keys(params).length === 0) return { text: query, values: [] };
23
+ const values: any[] = [];
24
+ const seen: Record<string, number> = {};
25
+ const text = query.replace(/@(\w+)/g, (_, name: string) => {
26
+ if (seen[name] !== undefined) return `$${seen[name]}`;
27
+ const idx = values.length + 1;
28
+ seen[name] = idx;
29
+ values.push(params[name] ?? null);
30
+ return `$${idx}`;
31
+ });
32
+ return { text, values };
33
+ }
34
+
35
+ async exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]> {
36
+ const { text, values } = this.transform(query, params);
37
+ const result = await this.pool.query(text, values);
38
+ return result.rows as T[];
39
+ }
40
+
41
+ async executeRaw(query: string, params?: Record<string, any>): Promise<number> {
42
+ const { text, values } = this.transform(query, params);
43
+ const result = await this.pool.query(text, values);
44
+ return result.rowCount ?? 0;
45
+ }
46
+
47
+ async connect(): Promise<void> {
48
+ const client = await this.pool.connect();
49
+ client.release();
50
+ }
51
+
52
+ async disconnect(): Promise<void> { await this.pool.end(); }
53
+
54
+ async beginTransaction(): Promise<TransactionHandle> {
55
+ const client = await this.pool.connect();
56
+ await client.query('BEGIN');
57
+
58
+ const transform = (query: string, params?: Record<string, any>) => {
59
+ if (!params || Object.keys(params).length === 0) return { text: query, values: [] };
60
+ const values: any[] = [];
61
+ const seen: Record<string, number> = {};
62
+ const text = query.replace(/@(\w+)/g, (_, name: string) => {
63
+ if (seen[name] !== undefined) return `$${seen[name]}`;
64
+ const idx = values.length + 1;
65
+ seen[name] = idx;
66
+ values.push(params[name] ?? null);
67
+ return `$${idx}`;
68
+ });
69
+ return { text, values };
70
+ };
71
+
72
+ return {
73
+ exec: async <T>(q: string, p?: Record<string, any>) => {
74
+ const { text, values } = transform(q, p);
75
+ const r = await client.query(text, values);
76
+ return (r.rows || []) as T[];
77
+ },
78
+ executeRaw: async (q: string, p?: Record<string, any>) => {
79
+ const { text, values } = transform(q, p);
80
+ const r = await client.query(text, values);
81
+ return r.rowCount ?? 0;
82
+ },
83
+ commit: async () => { await client.query('COMMIT'); client.release(); },
84
+ rollback: async () => { await client.query('ROLLBACK'); client.release(); },
85
+ };
86
+ }
87
+ }
@@ -0,0 +1 @@
1
+ export * from './engine';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./engine"), exports);
@@ -0,0 +1 @@
1
+ export * from './engine';
@@ -0,0 +1,13 @@
1
+ import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
2
+ export declare class SqliteEngine implements QueryEngine {
3
+ dialect: Dialect;
4
+ private db;
5
+ private readonly filePath;
6
+ constructor(adapterConfig: An5AdapterConfig);
7
+ private getDb;
8
+ exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]>;
9
+ executeRaw(query: string, params?: Record<string, any>): Promise<number>;
10
+ connect(): Promise<void>;
11
+ disconnect(): Promise<void>;
12
+ beginTransaction(): Promise<TransactionHandle>;
13
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqliteEngine = void 0;
4
+ // ─── SQLite Engine ─────────────────────────────────────────────────────────────────
5
+ let BetterSqlite3 = null;
6
+ try {
7
+ BetterSqlite3 = require('better-sqlite3');
8
+ }
9
+ catch { }
10
+ class SqliteEngine {
11
+ constructor(adapterConfig) {
12
+ this.dialect = 'sqlite';
13
+ this.db = null;
14
+ if (!BetterSqlite3)
15
+ throw new Error('better-sqlite3 package is required for SQLite support. Run: npm install better-sqlite3');
16
+ this.filePath = adapterConfig.connectionString
17
+ .replace(/^sqlite:\/\/\//i, '/')
18
+ .replace(/^sqlite:\/\//i, '');
19
+ }
20
+ getDb() {
21
+ if (!this.db)
22
+ this.db = new BetterSqlite3(this.filePath);
23
+ return this.db;
24
+ }
25
+ // better-sqlite3 natively supports @name parameters
26
+ async exec(query, params) {
27
+ return this.getDb().prepare(query).all(params ?? {});
28
+ }
29
+ async executeRaw(query, params) {
30
+ const info = this.getDb().prepare(query).run(params ?? {});
31
+ return info.changes ?? 0;
32
+ }
33
+ async connect() { this.getDb(); }
34
+ async disconnect() {
35
+ if (this.db) {
36
+ this.db.close();
37
+ this.db = null;
38
+ }
39
+ }
40
+ async beginTransaction() {
41
+ const db = this.getDb();
42
+ db.prepare('BEGIN').run();
43
+ let done = false;
44
+ return {
45
+ exec: async (q, p) => db.prepare(q).all(p ?? {}),
46
+ executeRaw: async (q, p) => (db.prepare(q).run(p ?? {}).changes ?? 0),
47
+ commit: async () => { if (!done) {
48
+ db.prepare('COMMIT').run();
49
+ done = true;
50
+ } },
51
+ rollback: async () => { if (!done) {
52
+ db.prepare('ROLLBACK').run();
53
+ done = true;
54
+ } },
55
+ };
56
+ }
57
+ }
58
+ exports.SqliteEngine = SqliteEngine;