@furlow/pipes 1.0.1 → 1.0.3
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/database/index.js +145 -10
- package/dist/database/index.js.map +1 -1
- package/dist/index.js +239 -34
- package/dist/index.js.map +1 -1
- package/dist/mqtt/index.js +18 -3
- package/dist/mqtt/index.js.map +1 -1
- package/dist/tcp/index.d.ts +1 -0
- package/dist/tcp/index.js +44 -11
- package/dist/tcp/index.js.map +1 -1
- package/dist/webhook/index.js +6 -2
- package/dist/webhook/index.js.map +1 -1
- package/dist/websocket/index.d.ts +1 -0
- package/dist/websocket/index.js +26 -8
- package/dist/websocket/index.js.map +1 -1
- package/package.json +2 -2
package/dist/database/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
// src/database/index.ts
|
|
2
|
+
function escapeIdentifier(name) {
|
|
3
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
4
|
+
throw new Error(`Invalid SQL identifier: ${name}`);
|
|
5
|
+
}
|
|
6
|
+
return `"${name}"`;
|
|
7
|
+
}
|
|
2
8
|
var DatabasePipe = class {
|
|
3
9
|
name;
|
|
4
10
|
type = "database";
|
|
@@ -22,6 +28,18 @@ var DatabasePipe = class {
|
|
|
22
28
|
const BetterSqlite3 = (await import("better-sqlite3")).default;
|
|
23
29
|
const connectionString = typeof this.config.connection === "string" ? this.config.connection : ":memory:";
|
|
24
30
|
this.db = new BetterSqlite3(connectionString);
|
|
31
|
+
} else if (this.config.adapter === "postgres") {
|
|
32
|
+
const pgModuleName = "pg";
|
|
33
|
+
const pg = await new Function("m", "return import(m)")(pgModuleName).catch(() => null);
|
|
34
|
+
if (!pg) {
|
|
35
|
+
throw new Error('PostgreSQL adapter requires the "pg" package. Install it with: npm install pg');
|
|
36
|
+
}
|
|
37
|
+
const { Pool } = pg;
|
|
38
|
+
const connectionString = typeof this.config.connection === "string" ? this.config.connection : void 0;
|
|
39
|
+
const connectionOptions = typeof this.config.connection === "object" ? this.config.connection : void 0;
|
|
40
|
+
this.db = new PostgresWrapper(
|
|
41
|
+
connectionString ? new Pool({ connectionString }) : new Pool(connectionOptions)
|
|
42
|
+
);
|
|
25
43
|
} else if (this.config.adapter === "memory") {
|
|
26
44
|
this.db = new MemoryDatabase();
|
|
27
45
|
} else {
|
|
@@ -48,6 +66,8 @@ var DatabasePipe = class {
|
|
|
48
66
|
try {
|
|
49
67
|
if (this.config.adapter === "sqlite" && this.db) {
|
|
50
68
|
this.db.close();
|
|
69
|
+
} else if (this.config.adapter === "postgres" && this.db) {
|
|
70
|
+
await this.db.close();
|
|
51
71
|
}
|
|
52
72
|
this.db = null;
|
|
53
73
|
this.connected = false;
|
|
@@ -84,6 +104,9 @@ var DatabasePipe = class {
|
|
|
84
104
|
const result = stmt.run(...params);
|
|
85
105
|
return { success: true, data: result };
|
|
86
106
|
}
|
|
107
|
+
} else if (this.config.adapter === "postgres") {
|
|
108
|
+
const result = await this.db.query(sql, params);
|
|
109
|
+
return { success: true, data: result };
|
|
87
110
|
} else if (this.config.adapter === "memory") {
|
|
88
111
|
const result = this.db.query(sql, params);
|
|
89
112
|
return { success: true, data: result };
|
|
@@ -105,11 +128,15 @@ var DatabasePipe = class {
|
|
|
105
128
|
const columns = Object.keys(data);
|
|
106
129
|
const values = Object.values(data);
|
|
107
130
|
const placeholders = columns.map(() => "?").join(", ");
|
|
108
|
-
const
|
|
131
|
+
const escapedTable = escapeIdentifier(table);
|
|
132
|
+
const escapedColumns = columns.map((c) => escapeIdentifier(c)).join(", ");
|
|
133
|
+
const sql = `INSERT INTO ${escapedTable} (${escapedColumns}) VALUES (${placeholders})`;
|
|
109
134
|
let result = {};
|
|
110
135
|
if (this.config.adapter === "sqlite") {
|
|
111
136
|
const stmt = this.db.prepare(sql);
|
|
112
137
|
result = stmt.run(...values);
|
|
138
|
+
} else if (this.config.adapter === "postgres") {
|
|
139
|
+
result = await this.db.insert(table, data);
|
|
113
140
|
} else if (this.config.adapter === "memory") {
|
|
114
141
|
result = this.db.insert(table, data);
|
|
115
142
|
}
|
|
@@ -134,14 +161,17 @@ var DatabasePipe = class {
|
|
|
134
161
|
return { success: false, error: "Not connected" };
|
|
135
162
|
}
|
|
136
163
|
try {
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
const
|
|
164
|
+
const escapedTable = escapeIdentifier(table);
|
|
165
|
+
const setClauses = Object.keys(data).map((key) => `${escapeIdentifier(key)} = ?`).join(", ");
|
|
166
|
+
const whereClauses = Object.keys(where).map((key) => `${escapeIdentifier(key)} = ?`).join(" AND ");
|
|
167
|
+
const sql = `UPDATE ${escapedTable} SET ${setClauses} WHERE ${whereClauses}`;
|
|
140
168
|
const params = [...Object.values(data), ...Object.values(where)];
|
|
141
169
|
let result = {};
|
|
142
170
|
if (this.config.adapter === "sqlite") {
|
|
143
171
|
const stmt = this.db.prepare(sql);
|
|
144
172
|
result = stmt.run(...params);
|
|
173
|
+
} else if (this.config.adapter === "postgres") {
|
|
174
|
+
result = await this.db.update(table, where, data);
|
|
145
175
|
} else if (this.config.adapter === "memory") {
|
|
146
176
|
result = this.db.update(table, where, data);
|
|
147
177
|
}
|
|
@@ -167,13 +197,16 @@ var DatabasePipe = class {
|
|
|
167
197
|
return { success: false, error: "Not connected" };
|
|
168
198
|
}
|
|
169
199
|
try {
|
|
170
|
-
const
|
|
171
|
-
const
|
|
200
|
+
const escapedTable = escapeIdentifier(table);
|
|
201
|
+
const whereClauses = Object.keys(where).map((key) => `${escapeIdentifier(key)} = ?`).join(" AND ");
|
|
202
|
+
const sql = `DELETE FROM ${escapedTable} WHERE ${whereClauses}`;
|
|
172
203
|
const params = Object.values(where);
|
|
173
204
|
let result = {};
|
|
174
205
|
if (this.config.adapter === "sqlite") {
|
|
175
206
|
const stmt = this.db.prepare(sql);
|
|
176
207
|
result = stmt.run(...params);
|
|
208
|
+
} else if (this.config.adapter === "postgres") {
|
|
209
|
+
result = await this.db.delete(table, where);
|
|
177
210
|
} else if (this.config.adapter === "memory") {
|
|
178
211
|
result = this.db.delete(table, where);
|
|
179
212
|
}
|
|
@@ -225,14 +258,68 @@ var DatabasePipe = class {
|
|
|
225
258
|
var MemoryDatabase = class {
|
|
226
259
|
tables = /* @__PURE__ */ new Map();
|
|
227
260
|
autoIncrements = /* @__PURE__ */ new Map();
|
|
228
|
-
query(sql,
|
|
229
|
-
const selectMatch = sql.match(
|
|
261
|
+
query(sql, params) {
|
|
262
|
+
const selectMatch = sql.match(
|
|
263
|
+
/SELECT\s+(\*|[\w,\s]+)\s+FROM\s+["']?(\w+)["']?(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+([\w\s,]+?)(?:\s+(ASC|DESC))?)?(?:\s+LIMIT\s+(\d+))?(?:\s+OFFSET\s+(\d+))?$/i
|
|
264
|
+
);
|
|
230
265
|
if (selectMatch) {
|
|
231
|
-
const table = selectMatch
|
|
232
|
-
|
|
266
|
+
const [, columns, table, whereClause, orderBy, orderDir, limitStr, offsetStr] = selectMatch;
|
|
267
|
+
let rows = [...this.tables.get(table) ?? []];
|
|
268
|
+
if (whereClause) {
|
|
269
|
+
const where = this.parseWhereClause(whereClause, params);
|
|
270
|
+
rows = rows.filter((row) => this.matchesWhere(row, where));
|
|
271
|
+
}
|
|
272
|
+
if (orderBy) {
|
|
273
|
+
const col = orderBy.trim();
|
|
274
|
+
const direction = orderDir?.toUpperCase() === "DESC" ? -1 : 1;
|
|
275
|
+
rows.sort((a, b) => {
|
|
276
|
+
const aVal = a[col];
|
|
277
|
+
const bVal = b[col];
|
|
278
|
+
if (aVal === bVal) return 0;
|
|
279
|
+
if (aVal === null || aVal === void 0) return direction;
|
|
280
|
+
if (bVal === null || bVal === void 0) return -direction;
|
|
281
|
+
return (aVal < bVal ? -1 : 1) * direction;
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (offsetStr) {
|
|
285
|
+
const offset = parseInt(offsetStr, 10);
|
|
286
|
+
rows = rows.slice(offset);
|
|
287
|
+
}
|
|
288
|
+
if (limitStr) {
|
|
289
|
+
const limit = parseInt(limitStr, 10);
|
|
290
|
+
rows = rows.slice(0, limit);
|
|
291
|
+
}
|
|
292
|
+
if (columns !== "*") {
|
|
293
|
+
const cols = columns.split(",").map((c) => c.trim());
|
|
294
|
+
rows = rows.map((row) => {
|
|
295
|
+
const result = {};
|
|
296
|
+
for (const col of cols) {
|
|
297
|
+
result[col] = row[col];
|
|
298
|
+
}
|
|
299
|
+
return result;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return rows;
|
|
233
303
|
}
|
|
304
|
+
console.warn(`MemoryDatabase: Unsupported query: ${sql}`);
|
|
234
305
|
return [];
|
|
235
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Parse a simple WHERE clause into key-value pairs
|
|
309
|
+
* Supports: col = ? AND col2 = ?
|
|
310
|
+
*/
|
|
311
|
+
parseWhereClause(whereClause, params) {
|
|
312
|
+
const where = {};
|
|
313
|
+
let paramIndex = 0;
|
|
314
|
+
const conditions = whereClause.split(/\s+AND\s+/i);
|
|
315
|
+
for (const condition of conditions) {
|
|
316
|
+
const match = condition.match(/["']?(\w+)["']?\s*=\s*\?/);
|
|
317
|
+
if (match) {
|
|
318
|
+
where[match[1]] = params[paramIndex++];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return where;
|
|
322
|
+
}
|
|
236
323
|
insert(table, data) {
|
|
237
324
|
if (!this.tables.has(table)) {
|
|
238
325
|
this.tables.set(table, []);
|
|
@@ -270,6 +357,54 @@ var MemoryDatabase = class {
|
|
|
270
357
|
return true;
|
|
271
358
|
}
|
|
272
359
|
};
|
|
360
|
+
var PostgresWrapper = class {
|
|
361
|
+
pool;
|
|
362
|
+
constructor(pool) {
|
|
363
|
+
this.pool = pool;
|
|
364
|
+
}
|
|
365
|
+
async query(sql, params) {
|
|
366
|
+
let paramIndex = 0;
|
|
367
|
+
const pgSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
|
|
368
|
+
const result = await this.pool.query(pgSql, params);
|
|
369
|
+
return result.rows;
|
|
370
|
+
}
|
|
371
|
+
async insert(table, data) {
|
|
372
|
+
const columns = Object.keys(data);
|
|
373
|
+
const values = Object.values(data);
|
|
374
|
+
const placeholders = columns.map((_, i) => `$${i + 1}`).join(", ");
|
|
375
|
+
const escapedTable = escapeIdentifier(table);
|
|
376
|
+
const escapedColumns = columns.map((c) => escapeIdentifier(c)).join(", ");
|
|
377
|
+
const result = await this.pool.query(
|
|
378
|
+
`INSERT INTO ${escapedTable} (${escapedColumns}) VALUES (${placeholders}) RETURNING id`,
|
|
379
|
+
values
|
|
380
|
+
);
|
|
381
|
+
const row = result.rows[0];
|
|
382
|
+
return { lastInsertRowid: row?.id };
|
|
383
|
+
}
|
|
384
|
+
async update(table, where, data) {
|
|
385
|
+
const escapedTable = escapeIdentifier(table);
|
|
386
|
+
const setClauses = Object.keys(data).map((key, i) => `${escapeIdentifier(key)} = $${i + 1}`).join(", ");
|
|
387
|
+
const whereClauses = Object.keys(where).map((key, i) => `${escapeIdentifier(key)} = $${Object.keys(data).length + i + 1}`).join(" AND ");
|
|
388
|
+
const params = [...Object.values(data), ...Object.values(where)];
|
|
389
|
+
const result = await this.pool.query(
|
|
390
|
+
`UPDATE ${escapedTable} SET ${setClauses} WHERE ${whereClauses}`,
|
|
391
|
+
params
|
|
392
|
+
);
|
|
393
|
+
return { changes: result.rowCount ?? 0 };
|
|
394
|
+
}
|
|
395
|
+
async delete(table, where) {
|
|
396
|
+
const escapedTable = escapeIdentifier(table);
|
|
397
|
+
const whereClauses = Object.keys(where).map((key, i) => `${escapeIdentifier(key)} = $${i + 1}`).join(" AND ");
|
|
398
|
+
const result = await this.pool.query(
|
|
399
|
+
`DELETE FROM ${escapedTable} WHERE ${whereClauses}`,
|
|
400
|
+
Object.values(where)
|
|
401
|
+
);
|
|
402
|
+
return { changes: result.rowCount ?? 0 };
|
|
403
|
+
}
|
|
404
|
+
async close() {
|
|
405
|
+
await this.pool.end();
|
|
406
|
+
}
|
|
407
|
+
};
|
|
273
408
|
function createDatabasePipe(options) {
|
|
274
409
|
return new DatabasePipe(options);
|
|
275
410
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/database/index.ts"],"sourcesContent":["/**\n * Database pipe for reactive database operations\n */\n\nimport type {\n Pipe,\n PipeResponse,\n DatabasePipeConfig,\n DatabaseEvent,\n DatabaseEventType,\n} from '../types.js';\n\nexport interface DatabasePipeOptions {\n name: string;\n config: DatabasePipeConfig;\n}\n\nexport type DatabaseEventHandler = (event: DatabaseEvent) => void | Promise<void>;\n\nexport class DatabasePipe implements Pipe {\n public readonly name: string;\n public readonly type = 'database';\n private config: DatabasePipeConfig;\n private connected = false;\n private db: any = null;\n private eventHandlers: Map<string, DatabaseEventHandler[]> = new Map();\n\n constructor(options: DatabasePipeOptions) {\n this.name = options.name;\n this.config = options.config;\n }\n\n /**\n * Connect to the database\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n try {\n if (this.config.adapter === 'sqlite') {\n // Dynamic import to avoid bundling issues\n const BetterSqlite3 = (await import('better-sqlite3')).default;\n const connectionString =\n typeof this.config.connection === 'string'\n ? this.config.connection\n : ':memory:';\n this.db = new BetterSqlite3(connectionString);\n } else if (this.config.adapter === 'memory') {\n // In-memory storage using a simple object\n this.db = new MemoryDatabase();\n } else {\n throw new Error(`Unsupported adapter: ${this.config.adapter}`);\n }\n\n this.connected = true;\n this.emit('connected', {\n type: 'insert',\n table: '',\n data: {},\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to connect to database: ${message}`);\n }\n }\n\n /**\n * Disconnect from the database\n */\n async disconnect(): Promise<void> {\n if (!this.connected) {\n return;\n }\n\n try {\n if (this.config.adapter === 'sqlite' && this.db) {\n this.db.close();\n }\n this.db = null;\n this.connected = false;\n this.emit('disconnected', {\n type: 'delete',\n table: '',\n data: {},\n });\n } catch {\n // Ignore close errors\n this.db = null;\n this.connected = false;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected;\n }\n\n /**\n * Execute a raw SQL query\n */\n async query<T = Record<string, unknown>[]>(\n sql: string,\n params: unknown[] = []\n ): Promise<PipeResponse<T>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n // Check if it's a SELECT query\n if (sql.trim().toUpperCase().startsWith('SELECT')) {\n const rows = stmt.all(...params);\n return { success: true, data: rows as T };\n } else {\n const result = stmt.run(...params);\n return { success: true, data: result as T };\n }\n } else if (this.config.adapter === 'memory') {\n const result = this.db.query(sql, params);\n return { success: true, data: result as T };\n }\n\n return { success: false, error: 'Unsupported adapter' };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Insert a row into a table\n */\n async insert(\n table: string,\n data: Record<string, unknown>\n ): Promise<PipeResponse<{ lastInsertRowid?: number | bigint }>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n const columns = Object.keys(data);\n const values = Object.values(data);\n const placeholders = columns.map(() => '?').join(', ');\n const sql = `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${placeholders})`;\n\n let result: { lastInsertRowid?: number | bigint } = {};\n\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n result = stmt.run(...values);\n } else if (this.config.adapter === 'memory') {\n result = this.db.insert(table, data);\n }\n\n // Emit insert event\n const event: DatabaseEvent = {\n type: 'insert',\n table,\n data,\n };\n this.emit('insert', event);\n this.emit('change', event);\n\n return { success: true, data: result };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Update rows in a table\n */\n async update(\n table: string,\n where: Record<string, unknown>,\n data: Record<string, unknown>\n ): Promise<PipeResponse<{ changes?: number }>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n const setClauses = Object.keys(data)\n .map((key) => `${key} = ?`)\n .join(', ');\n const whereClauses = Object.keys(where)\n .map((key) => `${key} = ?`)\n .join(' AND ');\n const sql = `UPDATE ${table} SET ${setClauses} WHERE ${whereClauses}`;\n const params = [...Object.values(data), ...Object.values(where)];\n\n let result: { changes?: number } = {};\n\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n result = stmt.run(...params);\n } else if (this.config.adapter === 'memory') {\n result = this.db.update(table, where, data);\n }\n\n // Emit update event\n const event: DatabaseEvent = {\n type: 'update',\n table,\n data,\n oldData: where,\n };\n this.emit('update', event);\n this.emit('change', event);\n\n return { success: true, data: result };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Delete rows from a table\n */\n async delete(\n table: string,\n where: Record<string, unknown>\n ): Promise<PipeResponse<{ changes?: number }>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n const whereClauses = Object.keys(where)\n .map((key) => `${key} = ?`)\n .join(' AND ');\n const sql = `DELETE FROM ${table} WHERE ${whereClauses}`;\n const params = Object.values(where);\n\n let result: { changes?: number } = {};\n\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n result = stmt.run(...params);\n } else if (this.config.adapter === 'memory') {\n result = this.db.delete(table, where);\n }\n\n // Emit delete event\n const event: DatabaseEvent = {\n type: 'delete',\n table,\n data: where,\n };\n this.emit('delete', event);\n this.emit('change', event);\n\n return { success: true, data: result };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Register an event handler\n */\n on(event: DatabaseEventType | 'change' | 'connected' | 'disconnected', handler: DatabaseEventHandler): void {\n const handlers = this.eventHandlers.get(event) ?? [];\n handlers.push(handler);\n this.eventHandlers.set(event, handlers);\n }\n\n /**\n * Remove an event handler\n */\n off(event: DatabaseEventType | 'change' | 'connected' | 'disconnected', handler: DatabaseEventHandler): void {\n const handlers = this.eventHandlers.get(event) ?? [];\n const index = handlers.indexOf(handler);\n if (index !== -1) {\n handlers.splice(index, 1);\n }\n }\n\n /**\n * Emit an event\n */\n private emit(event: string, data: DatabaseEvent): void {\n const handlers = this.eventHandlers.get(event) ?? [];\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`Database handler error for \"${event}\":`, error);\n }\n }\n }\n}\n\n/**\n * Simple in-memory database for testing\n */\nclass MemoryDatabase {\n private tables: Map<string, Record<string, unknown>[]> = new Map();\n private autoIncrements: Map<string, number> = new Map();\n\n query(sql: string, _params: unknown[]): Record<string, unknown>[] {\n // Very basic SQL parsing for memory adapter\n const selectMatch = sql.match(/SELECT \\* FROM (\\w+)/i);\n if (selectMatch) {\n const table = selectMatch[1]!;\n return this.tables.get(table) ?? [];\n }\n return [];\n }\n\n insert(table: string, data: Record<string, unknown>): { lastInsertRowid: number } {\n if (!this.tables.has(table)) {\n this.tables.set(table, []);\n }\n\n const id = (this.autoIncrements.get(table) ?? 0) + 1;\n this.autoIncrements.set(table, id);\n\n const row = { id, ...data };\n this.tables.get(table)!.push(row);\n\n return { lastInsertRowid: id };\n }\n\n update(\n table: string,\n where: Record<string, unknown>,\n data: Record<string, unknown>\n ): { changes: number } {\n const rows = this.tables.get(table) ?? [];\n let changes = 0;\n\n for (const row of rows) {\n if (this.matchesWhere(row, where)) {\n Object.assign(row, data);\n changes++;\n }\n }\n\n return { changes };\n }\n\n delete(table: string, where: Record<string, unknown>): { changes: number } {\n const rows = this.tables.get(table) ?? [];\n const initialLength = rows.length;\n\n const remaining = rows.filter((row) => !this.matchesWhere(row, where));\n this.tables.set(table, remaining);\n\n return { changes: initialLength - remaining.length };\n }\n\n private matchesWhere(\n row: Record<string, unknown>,\n where: Record<string, unknown>\n ): boolean {\n for (const [key, value] of Object.entries(where)) {\n if (row[key] !== value) {\n return false;\n }\n }\n return true;\n }\n}\n\n/**\n * Create a database pipe\n */\nexport function createDatabasePipe(options: DatabasePipeOptions): DatabasePipe {\n return new DatabasePipe(options);\n}\n"],"mappings":";AAmBO,IAAM,eAAN,MAAmC;AAAA,EACxB;AAAA,EACA,OAAO;AAAA,EACf;AAAA,EACA,YAAY;AAAA,EACZ,KAAU;AAAA,EACV,gBAAqD,oBAAI,IAAI;AAAA,EAErE,YAAY,SAA8B;AACxC,SAAK,OAAO,QAAQ;AACpB,SAAK,SAAS,QAAQ;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,QAAI,KAAK,WAAW;AAClB;AAAA,IACF;AAEA,QAAI;AACF,UAAI,KAAK,OAAO,YAAY,UAAU;AAEpC,cAAM,iBAAiB,MAAM,OAAO,gBAAgB,GAAG;AACvD,cAAM,mBACJ,OAAO,KAAK,OAAO,eAAe,WAC9B,KAAK,OAAO,aACZ;AACN,aAAK,KAAK,IAAI,cAAc,gBAAgB;AAAA,MAC9C,WAAW,KAAK,OAAO,YAAY,UAAU;AAE3C,aAAK,KAAK,IAAI,eAAe;AAAA,MAC/B,OAAO;AACL,cAAM,IAAI,MAAM,wBAAwB,KAAK,OAAO,OAAO,EAAE;AAAA,MAC/D;AAEA,WAAK,YAAY;AACjB,WAAK,KAAK,aAAa;AAAA,QACrB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM,CAAC;AAAA,MACT,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI,MAAM,kCAAkC,OAAO,EAAE;AAAA,IAC7D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AAEA,QAAI;AACF,UAAI,KAAK,OAAO,YAAY,YAAY,KAAK,IAAI;AAC/C,aAAK,GAAG,MAAM;AAAA,MAChB;AACA,WAAK,KAAK;AACV,WAAK,YAAY;AACjB,WAAK,KAAK,gBAAgB;AAAA,QACxB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM,CAAC;AAAA,MACT,CAAC;AAAA,IACH,QAAQ;AAEN,WAAK,KAAK;AACV,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MACJ,KACA,SAAoB,CAAC,GACK;AAC1B,QAAI,CAAC,KAAK,YAAY,GAAG;AACvB,aAAO,EAAE,SAAS,OAAO,OAAO,gBAAgB;AAAA,IAClD;AAEA,QAAI;AACF,UAAI,KAAK,OAAO,YAAY,UAAU;AACpC,cAAM,OAAO,KAAK,GAAG,QAAQ,GAAG;AAEhC,YAAI,IAAI,KAAK,EAAE,YAAY,EAAE,WAAW,QAAQ,GAAG;AACjD,gBAAM,OAAO,KAAK,IAAI,GAAG,MAAM;AAC/B,iBAAO,EAAE,SAAS,MAAM,MAAM,KAAU;AAAA,QAC1C,OAAO;AACL,gBAAM,SAAS,KAAK,IAAI,GAAG,MAAM;AACjC,iBAAO,EAAE,SAAS,MAAM,MAAM,OAAY;AAAA,QAC5C;AAAA,MACF,WAAW,KAAK,OAAO,YAAY,UAAU;AAC3C,cAAM,SAAS,KAAK,GAAG,MAAM,KAAK,MAAM;AACxC,eAAO,EAAE,SAAS,MAAM,MAAM,OAAY;AAAA,MAC5C;AAEA,aAAO,EAAE,SAAS,OAAO,OAAO,sBAAsB;AAAA,IACxD,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,EAAE,SAAS,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJ,OACA,MAC8D;AAC9D,QAAI,CAAC,KAAK,YAAY,GAAG;AACvB,aAAO,EAAE,SAAS,OAAO,OAAO,gBAAgB;AAAA,IAClD;AAEA,QAAI;AACF,YAAM,UAAU,OAAO,KAAK,IAAI;AAChC,YAAM,SAAS,OAAO,OAAO,IAAI;AACjC,YAAM,eAAe,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACrD,YAAM,MAAM,eAAe,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC,aAAa,YAAY;AAEhF,UAAI,SAAgD,CAAC;AAErD,UAAI,KAAK,OAAO,YAAY,UAAU;AACpC,cAAM,OAAO,KAAK,GAAG,QAAQ,GAAG;AAChC,iBAAS,KAAK,IAAI,GAAG,MAAM;AAAA,MAC7B,WAAW,KAAK,OAAO,YAAY,UAAU;AAC3C,iBAAS,KAAK,GAAG,OAAO,OAAO,IAAI;AAAA,MACrC;AAGA,YAAM,QAAuB;AAAA,QAC3B,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF;AACA,WAAK,KAAK,UAAU,KAAK;AACzB,WAAK,KAAK,UAAU,KAAK;AAEzB,aAAO,EAAE,SAAS,MAAM,MAAM,OAAO;AAAA,IACvC,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,EAAE,SAAS,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJ,OACA,OACA,MAC6C;AAC7C,QAAI,CAAC,KAAK,YAAY,GAAG;AACvB,aAAO,EAAE,SAAS,OAAO,OAAO,gBAAgB;AAAA,IAClD;AAEA,QAAI;AACF,YAAM,aAAa,OAAO,KAAK,IAAI,EAChC,IAAI,CAAC,QAAQ,GAAG,GAAG,MAAM,EACzB,KAAK,IAAI;AACZ,YAAM,eAAe,OAAO,KAAK,KAAK,EACnC,IAAI,CAAC,QAAQ,GAAG,GAAG,MAAM,EACzB,KAAK,OAAO;AACf,YAAM,MAAM,UAAU,KAAK,QAAQ,UAAU,UAAU,YAAY;AACnE,YAAM,SAAS,CAAC,GAAG,OAAO,OAAO,IAAI,GAAG,GAAG,OAAO,OAAO,KAAK,CAAC;AAE/D,UAAI,SAA+B,CAAC;AAEpC,UAAI,KAAK,OAAO,YAAY,UAAU;AACpC,cAAM,OAAO,KAAK,GAAG,QAAQ,GAAG;AAChC,iBAAS,KAAK,IAAI,GAAG,MAAM;AAAA,MAC7B,WAAW,KAAK,OAAO,YAAY,UAAU;AAC3C,iBAAS,KAAK,GAAG,OAAO,OAAO,OAAO,IAAI;AAAA,MAC5C;AAGA,YAAM,QAAuB;AAAA,QAC3B,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,SAAS;AAAA,MACX;AACA,WAAK,KAAK,UAAU,KAAK;AACzB,WAAK,KAAK,UAAU,KAAK;AAEzB,aAAO,EAAE,SAAS,MAAM,MAAM,OAAO;AAAA,IACvC,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,EAAE,SAAS,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJ,OACA,OAC6C;AAC7C,QAAI,CAAC,KAAK,YAAY,GAAG;AACvB,aAAO,EAAE,SAAS,OAAO,OAAO,gBAAgB;AAAA,IAClD;AAEA,QAAI;AACF,YAAM,eAAe,OAAO,KAAK,KAAK,EACnC,IAAI,CAAC,QAAQ,GAAG,GAAG,MAAM,EACzB,KAAK,OAAO;AACf,YAAM,MAAM,eAAe,KAAK,UAAU,YAAY;AACtD,YAAM,SAAS,OAAO,OAAO,KAAK;AAElC,UAAI,SAA+B,CAAC;AAEpC,UAAI,KAAK,OAAO,YAAY,UAAU;AACpC,cAAM,OAAO,KAAK,GAAG,QAAQ,GAAG;AAChC,iBAAS,KAAK,IAAI,GAAG,MAAM;AAAA,MAC7B,WAAW,KAAK,OAAO,YAAY,UAAU;AAC3C,iBAAS,KAAK,GAAG,OAAO,OAAO,KAAK;AAAA,MACtC;AAGA,YAAM,QAAuB;AAAA,QAC3B,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,MACR;AACA,WAAK,KAAK,UAAU,KAAK;AACzB,WAAK,KAAK,UAAU,KAAK;AAEzB,aAAO,EAAE,SAAS,MAAM,MAAM,OAAO;AAAA,IACvC,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,EAAE,SAAS,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,GAAG,OAAoE,SAAqC;AAC1G,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK,KAAK,CAAC;AACnD,aAAS,KAAK,OAAO;AACrB,SAAK,cAAc,IAAI,OAAO,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAoE,SAAqC;AAC3G,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK,KAAK,CAAC;AACnD,UAAM,QAAQ,SAAS,QAAQ,OAAO;AACtC,QAAI,UAAU,IAAI;AAChB,eAAS,OAAO,OAAO,CAAC;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,KAAK,OAAe,MAA2B;AACrD,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK,KAAK,CAAC;AACnD,eAAW,WAAW,UAAU;AAC9B,UAAI;AACF,gBAAQ,IAAI;AAAA,MACd,SAAS,OAAO;AACd,gBAAQ,MAAM,+BAA+B,KAAK,MAAM,KAAK;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACF;AAKA,IAAM,iBAAN,MAAqB;AAAA,EACX,SAAiD,oBAAI,IAAI;AAAA,EACzD,iBAAsC,oBAAI,IAAI;AAAA,EAEtD,MAAM,KAAa,SAA+C;AAEhE,UAAM,cAAc,IAAI,MAAM,uBAAuB;AACrD,QAAI,aAAa;AACf,YAAM,QAAQ,YAAY,CAAC;AAC3B,aAAO,KAAK,OAAO,IAAI,KAAK,KAAK,CAAC;AAAA,IACpC;AACA,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,OAAO,OAAe,MAA4D;AAChF,QAAI,CAAC,KAAK,OAAO,IAAI,KAAK,GAAG;AAC3B,WAAK,OAAO,IAAI,OAAO,CAAC,CAAC;AAAA,IAC3B;AAEA,UAAM,MAAM,KAAK,eAAe,IAAI,KAAK,KAAK,KAAK;AACnD,SAAK,eAAe,IAAI,OAAO,EAAE;AAEjC,UAAM,MAAM,EAAE,IAAI,GAAG,KAAK;AAC1B,SAAK,OAAO,IAAI,KAAK,EAAG,KAAK,GAAG;AAEhC,WAAO,EAAE,iBAAiB,GAAG;AAAA,EAC/B;AAAA,EAEA,OACE,OACA,OACA,MACqB;AACrB,UAAM,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,CAAC;AACxC,QAAI,UAAU;AAEd,eAAW,OAAO,MAAM;AACtB,UAAI,KAAK,aAAa,KAAK,KAAK,GAAG;AACjC,eAAO,OAAO,KAAK,IAAI;AACvB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ;AAAA,EACnB;AAAA,EAEA,OAAO,OAAe,OAAqD;AACzE,UAAM,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,CAAC;AACxC,UAAM,gBAAgB,KAAK;AAE3B,UAAM,YAAY,KAAK,OAAO,CAAC,QAAQ,CAAC,KAAK,aAAa,KAAK,KAAK,CAAC;AACrE,SAAK,OAAO,IAAI,OAAO,SAAS;AAEhC,WAAO,EAAE,SAAS,gBAAgB,UAAU,OAAO;AAAA,EACrD;AAAA,EAEQ,aACN,KACA,OACS;AACT,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,UAAI,IAAI,GAAG,MAAM,OAAO;AACtB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAKO,SAAS,mBAAmB,SAA4C;AAC7E,SAAO,IAAI,aAAa,OAAO;AACjC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/database/index.ts"],"sourcesContent":["/**\n * Database pipe for reactive database operations\n */\n\nimport type {\n Pipe,\n PipeResponse,\n DatabasePipeConfig,\n DatabaseEvent,\n DatabaseEventType,\n} from '../types.js';\n\n// Pool type for pg (dynamically imported at runtime)\ntype PgPool = {\n query: (sql: string, params?: unknown[]) => Promise<{ rows: unknown[]; rowCount: number | null }>;\n end: () => Promise<void>;\n};\n\nexport interface DatabasePipeOptions {\n name: string;\n config: DatabasePipeConfig;\n}\n\n/**\n * Escape a SQL identifier (table/column name) to prevent SQL injection\n */\nfunction escapeIdentifier(name: string): string {\n // Validate identifier - only allow alphanumeric and underscores\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid SQL identifier: ${name}`);\n }\n return `\"${name}\"`;\n}\n\nexport type DatabaseEventHandler = (event: DatabaseEvent) => void | Promise<void>;\n\nexport class DatabasePipe implements Pipe {\n public readonly name: string;\n public readonly type = 'database';\n private config: DatabasePipeConfig;\n private connected = false;\n private db: any = null;\n private eventHandlers: Map<string, DatabaseEventHandler[]> = new Map();\n\n constructor(options: DatabasePipeOptions) {\n this.name = options.name;\n this.config = options.config;\n }\n\n /**\n * Connect to the database\n */\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n try {\n if (this.config.adapter === 'sqlite') {\n // Dynamic import to avoid bundling issues\n const BetterSqlite3 = (await import('better-sqlite3')).default;\n const connectionString =\n typeof this.config.connection === 'string'\n ? this.config.connection\n : ':memory:';\n this.db = new BetterSqlite3(connectionString);\n } else if (this.config.adapter === 'postgres') {\n // Dynamic import to avoid bundling issues - use Function constructor to hide from TS\n const pgModuleName = 'pg';\n const pg = await (new Function('m', 'return import(m)')(pgModuleName) as Promise<{ Pool: new (config?: unknown) => PgPool }>).catch(() => null);\n if (!pg) {\n throw new Error('PostgreSQL adapter requires the \"pg\" package. Install it with: npm install pg');\n }\n const { Pool } = pg;\n const connectionString =\n typeof this.config.connection === 'string'\n ? this.config.connection\n : undefined;\n const connectionOptions =\n typeof this.config.connection === 'object'\n ? this.config.connection\n : undefined;\n this.db = new PostgresWrapper(\n connectionString\n ? new Pool({ connectionString })\n : new Pool(connectionOptions)\n );\n } else if (this.config.adapter === 'memory') {\n // In-memory storage using a simple object\n this.db = new MemoryDatabase();\n } else {\n throw new Error(`Unsupported adapter: ${this.config.adapter}`);\n }\n\n this.connected = true;\n this.emit('connected', {\n type: 'insert',\n table: '',\n data: {},\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to connect to database: ${message}`);\n }\n }\n\n /**\n * Disconnect from the database\n */\n async disconnect(): Promise<void> {\n if (!this.connected) {\n return;\n }\n\n try {\n if (this.config.adapter === 'sqlite' && this.db) {\n this.db.close();\n } else if (this.config.adapter === 'postgres' && this.db) {\n await this.db.close();\n }\n this.db = null;\n this.connected = false;\n this.emit('disconnected', {\n type: 'delete',\n table: '',\n data: {},\n });\n } catch {\n // Ignore close errors\n this.db = null;\n this.connected = false;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected;\n }\n\n /**\n * Execute a raw SQL query\n */\n async query<T = Record<string, unknown>[]>(\n sql: string,\n params: unknown[] = []\n ): Promise<PipeResponse<T>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n // Check if it's a SELECT query\n if (sql.trim().toUpperCase().startsWith('SELECT')) {\n const rows = stmt.all(...params);\n return { success: true, data: rows as T };\n } else {\n const result = stmt.run(...params);\n return { success: true, data: result as T };\n }\n } else if (this.config.adapter === 'postgres') {\n const result = await this.db.query(sql, params);\n return { success: true, data: result as T };\n } else if (this.config.adapter === 'memory') {\n const result = this.db.query(sql, params);\n return { success: true, data: result as T };\n }\n\n return { success: false, error: 'Unsupported adapter' };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Insert a row into a table\n */\n async insert(\n table: string,\n data: Record<string, unknown>\n ): Promise<PipeResponse<{ lastInsertRowid?: number | bigint }>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n const columns = Object.keys(data);\n const values = Object.values(data);\n const placeholders = columns.map(() => '?').join(', ');\n const escapedTable = escapeIdentifier(table);\n const escapedColumns = columns.map(c => escapeIdentifier(c)).join(', ');\n const sql = `INSERT INTO ${escapedTable} (${escapedColumns}) VALUES (${placeholders})`;\n\n let result: { lastInsertRowid?: number | bigint } = {};\n\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n result = stmt.run(...values);\n } else if (this.config.adapter === 'postgres') {\n result = await this.db.insert(table, data);\n } else if (this.config.adapter === 'memory') {\n result = this.db.insert(table, data);\n }\n\n // Emit insert event\n const event: DatabaseEvent = {\n type: 'insert',\n table,\n data,\n };\n this.emit('insert', event);\n this.emit('change', event);\n\n return { success: true, data: result };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Update rows in a table\n */\n async update(\n table: string,\n where: Record<string, unknown>,\n data: Record<string, unknown>\n ): Promise<PipeResponse<{ changes?: number }>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n const escapedTable = escapeIdentifier(table);\n const setClauses = Object.keys(data)\n .map((key) => `${escapeIdentifier(key)} = ?`)\n .join(', ');\n const whereClauses = Object.keys(where)\n .map((key) => `${escapeIdentifier(key)} = ?`)\n .join(' AND ');\n const sql = `UPDATE ${escapedTable} SET ${setClauses} WHERE ${whereClauses}`;\n const params = [...Object.values(data), ...Object.values(where)];\n\n let result: { changes?: number } = {};\n\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n result = stmt.run(...params);\n } else if (this.config.adapter === 'postgres') {\n result = await this.db.update(table, where, data);\n } else if (this.config.adapter === 'memory') {\n result = this.db.update(table, where, data);\n }\n\n // Emit update event\n const event: DatabaseEvent = {\n type: 'update',\n table,\n data,\n oldData: where,\n };\n this.emit('update', event);\n this.emit('change', event);\n\n return { success: true, data: result };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Delete rows from a table\n */\n async delete(\n table: string,\n where: Record<string, unknown>\n ): Promise<PipeResponse<{ changes?: number }>> {\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n try {\n const escapedTable = escapeIdentifier(table);\n const whereClauses = Object.keys(where)\n .map((key) => `${escapeIdentifier(key)} = ?`)\n .join(' AND ');\n const sql = `DELETE FROM ${escapedTable} WHERE ${whereClauses}`;\n const params = Object.values(where);\n\n let result: { changes?: number } = {};\n\n if (this.config.adapter === 'sqlite') {\n const stmt = this.db.prepare(sql);\n result = stmt.run(...params);\n } else if (this.config.adapter === 'postgres') {\n result = await this.db.delete(table, where);\n } else if (this.config.adapter === 'memory') {\n result = this.db.delete(table, where);\n }\n\n // Emit delete event\n const event: DatabaseEvent = {\n type: 'delete',\n table,\n data: where,\n };\n this.emit('delete', event);\n this.emit('change', event);\n\n return { success: true, data: result };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, error: message };\n }\n }\n\n /**\n * Register an event handler\n */\n on(event: DatabaseEventType | 'change' | 'connected' | 'disconnected', handler: DatabaseEventHandler): void {\n const handlers = this.eventHandlers.get(event) ?? [];\n handlers.push(handler);\n this.eventHandlers.set(event, handlers);\n }\n\n /**\n * Remove an event handler\n */\n off(event: DatabaseEventType | 'change' | 'connected' | 'disconnected', handler: DatabaseEventHandler): void {\n const handlers = this.eventHandlers.get(event) ?? [];\n const index = handlers.indexOf(handler);\n if (index !== -1) {\n handlers.splice(index, 1);\n }\n }\n\n /**\n * Emit an event\n */\n private emit(event: string, data: DatabaseEvent): void {\n const handlers = this.eventHandlers.get(event) ?? [];\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`Database handler error for \"${event}\":`, error);\n }\n }\n }\n}\n\n/**\n * Simple in-memory database for testing and development\n * Supports basic SQL operations: SELECT with WHERE, ORDER BY, LIMIT\n *\n * Limitations:\n * - No JOIN support\n * - No complex expressions in WHERE (only simple equality)\n * - No aggregate functions\n * - For production, use SQLite or PostgreSQL\n */\nclass MemoryDatabase {\n private tables: Map<string, Record<string, unknown>[]> = new Map();\n private autoIncrements: Map<string, number> = new Map();\n\n query(sql: string, params: unknown[]): Record<string, unknown>[] {\n // Parse SELECT queries with basic WHERE, ORDER BY, LIMIT support\n const selectMatch = sql.match(\n /SELECT\\s+(\\*|[\\w,\\s]+)\\s+FROM\\s+[\"']?(\\w+)[\"']?(?:\\s+WHERE\\s+(.+?))?(?:\\s+ORDER\\s+BY\\s+([\\w\\s,]+?)(?:\\s+(ASC|DESC))?)?(?:\\s+LIMIT\\s+(\\d+))?(?:\\s+OFFSET\\s+(\\d+))?$/i\n );\n\n if (selectMatch) {\n const [, columns, table, whereClause, orderBy, orderDir, limitStr, offsetStr] = selectMatch;\n let rows = [...(this.tables.get(table!) ?? [])];\n\n // Apply WHERE clause\n if (whereClause) {\n const where = this.parseWhereClause(whereClause, params);\n rows = rows.filter((row) => this.matchesWhere(row, where));\n }\n\n // Apply ORDER BY\n if (orderBy) {\n const col = orderBy.trim();\n const direction = orderDir?.toUpperCase() === 'DESC' ? -1 : 1;\n rows.sort((a, b) => {\n const aVal = a[col];\n const bVal = b[col];\n if (aVal === bVal) return 0;\n if (aVal === null || aVal === undefined) return direction;\n if (bVal === null || bVal === undefined) return -direction;\n return (aVal < bVal ? -1 : 1) * direction;\n });\n }\n\n // Apply OFFSET\n if (offsetStr) {\n const offset = parseInt(offsetStr, 10);\n rows = rows.slice(offset);\n }\n\n // Apply LIMIT\n if (limitStr) {\n const limit = parseInt(limitStr, 10);\n rows = rows.slice(0, limit);\n }\n\n // Select specific columns if not *\n if (columns !== '*') {\n const cols = columns!.split(',').map((c) => c.trim());\n rows = rows.map((row) => {\n const result: Record<string, unknown> = {};\n for (const col of cols) {\n result[col] = row[col];\n }\n return result;\n });\n }\n\n return rows;\n }\n\n // Fallback for unsupported queries\n console.warn(`MemoryDatabase: Unsupported query: ${sql}`);\n return [];\n }\n\n /**\n * Parse a simple WHERE clause into key-value pairs\n * Supports: col = ? AND col2 = ?\n */\n private parseWhereClause(\n whereClause: string,\n params: unknown[]\n ): Record<string, unknown> {\n const where: Record<string, unknown> = {};\n let paramIndex = 0;\n\n // Split by AND (case insensitive)\n const conditions = whereClause.split(/\\s+AND\\s+/i);\n\n for (const condition of conditions) {\n // Match: column = ? or \"column\" = ?\n const match = condition.match(/[\"']?(\\w+)[\"']?\\s*=\\s*\\?/);\n if (match) {\n where[match[1]!] = params[paramIndex++];\n }\n }\n\n return where;\n }\n\n insert(table: string, data: Record<string, unknown>): { lastInsertRowid: number } {\n if (!this.tables.has(table)) {\n this.tables.set(table, []);\n }\n\n const id = (this.autoIncrements.get(table) ?? 0) + 1;\n this.autoIncrements.set(table, id);\n\n const row = { id, ...data };\n this.tables.get(table)!.push(row);\n\n return { lastInsertRowid: id };\n }\n\n update(\n table: string,\n where: Record<string, unknown>,\n data: Record<string, unknown>\n ): { changes: number } {\n const rows = this.tables.get(table) ?? [];\n let changes = 0;\n\n for (const row of rows) {\n if (this.matchesWhere(row, where)) {\n Object.assign(row, data);\n changes++;\n }\n }\n\n return { changes };\n }\n\n delete(table: string, where: Record<string, unknown>): { changes: number } {\n const rows = this.tables.get(table) ?? [];\n const initialLength = rows.length;\n\n const remaining = rows.filter((row) => !this.matchesWhere(row, where));\n this.tables.set(table, remaining);\n\n return { changes: initialLength - remaining.length };\n }\n\n private matchesWhere(\n row: Record<string, unknown>,\n where: Record<string, unknown>\n ): boolean {\n for (const [key, value] of Object.entries(where)) {\n if (row[key] !== value) {\n return false;\n }\n }\n return true;\n }\n}\n\n/**\n * PostgreSQL wrapper for consistent interface with other adapters\n */\nclass PostgresWrapper {\n private pool: PgPool;\n\n constructor(pool: PgPool) {\n this.pool = pool;\n }\n\n async query(sql: string, params: unknown[]): Promise<Record<string, unknown>[]> {\n // Convert ? placeholders to $1, $2, etc for pg\n let paramIndex = 0;\n const pgSql = sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const result = await this.pool.query(pgSql, params);\n return result.rows as Record<string, unknown>[];\n }\n\n async insert(\n table: string,\n data: Record<string, unknown>\n ): Promise<{ lastInsertRowid?: number }> {\n const columns = Object.keys(data);\n const values = Object.values(data);\n const placeholders = columns.map((_, i) => `$${i + 1}`).join(', ');\n const escapedTable = escapeIdentifier(table);\n const escapedColumns = columns.map(c => escapeIdentifier(c)).join(', ');\n\n const result = await this.pool.query(\n `INSERT INTO ${escapedTable} (${escapedColumns}) VALUES (${placeholders}) RETURNING id`,\n values\n );\n\n const row = result.rows[0] as Record<string, unknown> | undefined;\n return { lastInsertRowid: row?.id as number | undefined };\n }\n\n async update(\n table: string,\n where: Record<string, unknown>,\n data: Record<string, unknown>\n ): Promise<{ changes: number }> {\n const escapedTable = escapeIdentifier(table);\n const setClauses = Object.keys(data)\n .map((key, i) => `${escapeIdentifier(key)} = $${i + 1}`)\n .join(', ');\n const whereClauses = Object.keys(where)\n .map((key, i) => `${escapeIdentifier(key)} = $${Object.keys(data).length + i + 1}`)\n .join(' AND ');\n\n const params = [...Object.values(data), ...Object.values(where)];\n const result = await this.pool.query(\n `UPDATE ${escapedTable} SET ${setClauses} WHERE ${whereClauses}`,\n params\n );\n\n return { changes: result.rowCount ?? 0 };\n }\n\n async delete(\n table: string,\n where: Record<string, unknown>\n ): Promise<{ changes: number }> {\n const escapedTable = escapeIdentifier(table);\n const whereClauses = Object.keys(where)\n .map((key, i) => `${escapeIdentifier(key)} = $${i + 1}`)\n .join(' AND ');\n\n const result = await this.pool.query(\n `DELETE FROM ${escapedTable} WHERE ${whereClauses}`,\n Object.values(where)\n );\n\n return { changes: result.rowCount ?? 0 };\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n\n/**\n * Create a database pipe\n */\nexport function createDatabasePipe(options: DatabasePipeOptions): DatabasePipe {\n return new DatabasePipe(options);\n}\n"],"mappings":"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","names":[]}
|