@jungjaehoon/mama-core 1.1.2 → 1.1.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.
Files changed (67) hide show
  1. package/dist/config-loader.d.ts +61 -0
  2. package/dist/config-loader.js +187 -0
  3. package/dist/db-adapter/base-adapter.d.ts +76 -0
  4. package/dist/db-adapter/base-adapter.js +11 -0
  5. package/dist/db-adapter/index.d.ts +24 -0
  6. package/dist/db-adapter/index.js +29 -0
  7. package/dist/db-adapter/sqlite-adapter.d.ts +73 -0
  8. package/dist/db-adapter/sqlite-adapter.js +330 -0
  9. package/dist/db-adapter/statement.d.ts +119 -0
  10. package/dist/db-adapter/statement.js +113 -0
  11. package/dist/db-manager.d.ts +252 -0
  12. package/dist/db-manager.js +622 -0
  13. package/dist/debug-logger.d.ts +32 -0
  14. package/dist/debug-logger.js +83 -0
  15. package/dist/decision-formatter.d.ts +172 -0
  16. package/dist/decision-formatter.js +894 -0
  17. package/dist/decision-tracker.d.ts +218 -0
  18. package/dist/decision-tracker.js +531 -0
  19. package/dist/embedding-cache.d.ts +83 -0
  20. package/dist/embedding-cache.js +182 -0
  21. package/dist/embedding-client.d.ts +43 -0
  22. package/dist/embedding-client.js +132 -0
  23. package/dist/embedding-server/index.d.ts +65 -0
  24. package/dist/embedding-server/index.js +397 -0
  25. package/dist/embedding-server/mobile/auth.d.ts +53 -0
  26. package/dist/embedding-server/mobile/auth.js +140 -0
  27. package/dist/embedding-server/mobile/daemon.d.ts +128 -0
  28. package/dist/embedding-server/mobile/daemon.js +303 -0
  29. package/dist/embedding-server/mobile/output-parser.d.ts +115 -0
  30. package/dist/embedding-server/mobile/output-parser.js +241 -0
  31. package/dist/embedding-server/mobile/session-api.d.ts +57 -0
  32. package/dist/embedding-server/mobile/session-api.js +261 -0
  33. package/dist/embedding-server/mobile/session-manager.d.ts +135 -0
  34. package/dist/embedding-server/mobile/session-manager.js +333 -0
  35. package/dist/embedding-server/mobile/websocket-handler.d.ts +127 -0
  36. package/dist/embedding-server/mobile/websocket-handler.js +435 -0
  37. package/dist/embeddings.d.ts +75 -0
  38. package/dist/embeddings.js +262 -0
  39. package/dist/errors.d.ts +131 -0
  40. package/dist/errors.js +225 -0
  41. package/dist/index.d.ts +32 -0
  42. package/dist/index.js +193 -0
  43. package/dist/mama-api.d.ts +954 -0
  44. package/dist/mama-api.js +2210 -0
  45. package/dist/memory-inject.d.ts +24 -0
  46. package/dist/memory-inject.js +116 -0
  47. package/dist/memory-store.d.ts +103 -0
  48. package/dist/memory-store.js +129 -0
  49. package/dist/notification-manager.d.ts +7 -0
  50. package/dist/notification-manager.js +12 -0
  51. package/dist/ollama-client.d.ts +51 -0
  52. package/dist/ollama-client.js +308 -0
  53. package/dist/outcome-tracker.d.ts +165 -0
  54. package/dist/outcome-tracker.js +315 -0
  55. package/dist/progress-indicator.d.ts +48 -0
  56. package/dist/progress-indicator.js +82 -0
  57. package/dist/query-intent.d.ts +27 -0
  58. package/dist/query-intent.js +144 -0
  59. package/dist/relevance-scorer.d.ts +124 -0
  60. package/dist/relevance-scorer.js +243 -0
  61. package/dist/test-utils.d.ts +66 -0
  62. package/dist/test-utils.js +166 -0
  63. package/dist/tier-validator.d.ts +55 -0
  64. package/dist/tier-validator.js +216 -0
  65. package/dist/time-formatter.d.ts +25 -0
  66. package/dist/time-formatter.js +93 -0
  67. package/package.json +3 -2
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ /**
3
+ * SQLite Database Adapter
4
+ *
5
+ * Implements DatabaseAdapter interface using better-sqlite3 + sqlite-vec
6
+ * This is the current production implementation extracted from memory-store.js
7
+ *
8
+ * @module sqlite-adapter
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.SQLiteAdapter = void 0;
15
+ const path_1 = __importDefault(require("path"));
16
+ const os_1 = __importDefault(require("os"));
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
19
+ const base_adapter_js_1 = require("./base-adapter.js");
20
+ const statement_js_1 = require("./statement.js");
21
+ const debug_logger_js_1 = require("../debug-logger.js");
22
+ const embeddings_js_1 = require("../embeddings.js");
23
+ // Try to load sqlite-vec
24
+ let sqliteVec = null;
25
+ try {
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ sqliteVec = require('sqlite-vec');
28
+ }
29
+ catch {
30
+ // Defer logging until connect() so we have logger context initialized
31
+ sqliteVec = null;
32
+ }
33
+ // Database paths
34
+ const LEGACY_DB_PATH = path_1.default.join(os_1.default.homedir(), '.spinelift', 'memories.db');
35
+ // Default to ~/.claude/mama-memory.db for Claude Code/Desktop compatibility
36
+ const DEFAULT_DB_PATH = path_1.default.join(os_1.default.homedir(), '.claude', 'mama-memory.db');
37
+ class SQLiteAdapter extends base_adapter_js_1.DatabaseAdapter {
38
+ config;
39
+ db = null;
40
+ _vectorSearchEnabled = false;
41
+ constructor(config = {}) {
42
+ super();
43
+ this.config = config;
44
+ }
45
+ /**
46
+ * Check if vector search is enabled
47
+ */
48
+ get vectorSearchEnabled() {
49
+ return this._vectorSearchEnabled;
50
+ }
51
+ /**
52
+ * Get database path with backward compatibility
53
+ */
54
+ getDbPath() {
55
+ // Support both MAMA_DB_PATH and MAMA_DATABASE_PATH for backward compatibility
56
+ const envPath = process.env.MAMA_DB_PATH || process.env.MAMA_DATABASE_PATH;
57
+ const configPath = this.config.dbPath;
58
+ // Expand ${HOME} or ~ in environment variable
59
+ let expandedEnvPath = envPath;
60
+ if (envPath) {
61
+ expandedEnvPath = envPath.replace(/\$\{HOME\}/g, os_1.default.homedir()).replace(/^~/, os_1.default.homedir());
62
+ }
63
+ // Priority: config > env > default
64
+ const targetPath = configPath || expandedEnvPath || DEFAULT_DB_PATH;
65
+ // Backward compatibility: Check legacy path if not explicitly set
66
+ if (!configPath && !envPath && fs_1.default.existsSync(LEGACY_DB_PATH)) {
67
+ (0, debug_logger_js_1.info)('[sqlite-adapter] Found legacy database at ~/.spinelift/memories.db, using it for backward compatibility');
68
+ return LEGACY_DB_PATH;
69
+ }
70
+ return targetPath;
71
+ }
72
+ /**
73
+ * Connect to SQLite database
74
+ */
75
+ connect() {
76
+ if (this.db) {
77
+ return this.db;
78
+ }
79
+ const dbPath = this.getDbPath();
80
+ const dbDir = path_1.default.dirname(dbPath);
81
+ // Ensure directory exists
82
+ if (!fs_1.default.existsSync(dbDir)) {
83
+ fs_1.default.mkdirSync(dbDir, { recursive: true });
84
+ (0, debug_logger_js_1.info)(`[sqlite-adapter] Created database directory: ${dbDir}`);
85
+ }
86
+ // Open database
87
+ this.db = new better_sqlite3_1.default(dbPath, { verbose: undefined });
88
+ (0, debug_logger_js_1.info)(`[sqlite-adapter] Opened database at: ${dbPath}`);
89
+ // Production configuration
90
+ this.db.pragma('journal_mode = WAL');
91
+ this.db.pragma('busy_timeout = 5000');
92
+ this.db.pragma('synchronous = NORMAL');
93
+ this.db.pragma('cache_size = -64000'); // 64MB cache
94
+ this.db.pragma('temp_store = MEMORY');
95
+ this.db.pragma('foreign_keys = ON');
96
+ // Load sqlite-vec extension (graceful degradation if unavailable)
97
+ if (sqliteVec) {
98
+ try {
99
+ sqliteVec.load(this.db);
100
+ this._vectorSearchEnabled = true;
101
+ (0, debug_logger_js_1.info)('[sqlite-adapter] Loaded sqlite-vec extension');
102
+ }
103
+ catch (err) {
104
+ this._vectorSearchEnabled = false;
105
+ const message = err instanceof Error ? err.message : String(err);
106
+ (0, debug_logger_js_1.warn)(`[sqlite-adapter] sqlite-vec unavailable (Tier 2 fallback): ${message}`);
107
+ }
108
+ }
109
+ else {
110
+ this._vectorSearchEnabled = false;
111
+ (0, debug_logger_js_1.warn)('[sqlite-adapter] sqlite-vec package not installed; vector search disabled');
112
+ }
113
+ return this.db;
114
+ }
115
+ /**
116
+ * Disconnect from database
117
+ */
118
+ disconnect() {
119
+ if (this.db) {
120
+ this.db.close();
121
+ this.db = null;
122
+ (0, debug_logger_js_1.info)('[sqlite-adapter] Disconnected from database');
123
+ }
124
+ }
125
+ /**
126
+ * Check if connected
127
+ */
128
+ isConnected() {
129
+ return this.db !== null && this.db.open;
130
+ }
131
+ /**
132
+ * Prepare a SQL statement
133
+ */
134
+ prepare(sql) {
135
+ if (!this.isConnected() || !this.db) {
136
+ throw new Error('Database not connected');
137
+ }
138
+ const stmt = this.db.prepare(sql);
139
+ return new statement_js_1.SQLiteStatement(stmt);
140
+ }
141
+ /**
142
+ * Execute raw SQL
143
+ */
144
+ exec(sql) {
145
+ if (!this.isConnected() || !this.db) {
146
+ throw new Error('Database not connected');
147
+ }
148
+ this.db.exec(sql);
149
+ }
150
+ /**
151
+ * Execute function in transaction
152
+ */
153
+ transaction(fn) {
154
+ if (!this.isConnected() || !this.db) {
155
+ throw new Error('Database not connected');
156
+ }
157
+ const txn = this.db.transaction(fn);
158
+ return txn();
159
+ }
160
+ /**
161
+ * Vector similarity search using sqlite-vec (vec0 virtual table)
162
+ */
163
+ vectorSearch(embedding, limit = 5) {
164
+ if (!this.isConnected()) {
165
+ throw new Error('Database not connected');
166
+ }
167
+ if (!this._vectorSearchEnabled) {
168
+ return null;
169
+ }
170
+ const embeddingJson = JSON.stringify(Array.from(embedding));
171
+ const stmt = this.prepare(`
172
+ SELECT
173
+ rowid,
174
+ embedding,
175
+ distance
176
+ FROM vss_memories
177
+ WHERE embedding MATCH vec_f32(?)
178
+ LIMIT ?
179
+ `);
180
+ const queryVector = embedding instanceof Float32Array ? embedding : Float32Array.from(embedding);
181
+ const results = stmt.all(embeddingJson, Math.max(limit, 1));
182
+ return results
183
+ .map((row) => {
184
+ const candidate = bufferToVector(row.embedding);
185
+ if (!candidate) {
186
+ return null;
187
+ }
188
+ const similarity = (0, embeddings_js_1.cosineSimilarity)(candidate, queryVector);
189
+ return {
190
+ rowid: row.rowid,
191
+ similarity,
192
+ distance: 1 - similarity,
193
+ };
194
+ })
195
+ .filter((r) => r !== null);
196
+ }
197
+ /**
198
+ * Insert vector embedding
199
+ */
200
+ insertEmbedding(rowid, embedding) {
201
+ if (!this.isConnected()) {
202
+ throw new Error('Database not connected');
203
+ }
204
+ if (!this._vectorSearchEnabled) {
205
+ return null;
206
+ }
207
+ const embeddingJson = JSON.stringify(Array.from(embedding));
208
+ // CRITICAL FIX: sqlite-vec virtual tables accept rowid as literal but not via ? placeholder
209
+ // Using template literal with Number() cast for safety (prevents SQL injection)
210
+ const safeRowid = Number(rowid);
211
+ if (!Number.isInteger(safeRowid) || safeRowid < 1) {
212
+ throw new Error(`Invalid rowid: ${rowid}`);
213
+ }
214
+ const stmt = this.prepare(`
215
+ INSERT OR REPLACE INTO vss_memories(rowid, embedding)
216
+ VALUES (${safeRowid}, ?)
217
+ `);
218
+ return stmt.run(embeddingJson);
219
+ }
220
+ /**
221
+ * Get last inserted row ID
222
+ */
223
+ getLastInsertRowid() {
224
+ if (!this.isConnected() || !this.db) {
225
+ throw new Error('Database not connected');
226
+ }
227
+ // better-sqlite3 provides this via Database instance
228
+ const result = this.db.prepare('SELECT last_insert_rowid() as rowid').get();
229
+ return result.rowid;
230
+ }
231
+ /**
232
+ * Run migrations
233
+ */
234
+ runMigrations(migrationsDir) {
235
+ if (!this.isConnected()) {
236
+ throw new Error('Database not connected');
237
+ }
238
+ // Check if schema_version table exists
239
+ const tables = this.prepare(`
240
+ SELECT name FROM sqlite_master
241
+ WHERE type='table' AND name='schema_version'
242
+ `).all();
243
+ let currentVersion = 0;
244
+ if (tables.length > 0) {
245
+ const version = this.prepare('SELECT MAX(version) as version FROM schema_version').get();
246
+ currentVersion = version?.version || 0;
247
+ }
248
+ (0, debug_logger_js_1.info)(`[sqlite-adapter] Current schema version: ${currentVersion}`);
249
+ // Get all migration files
250
+ const migrationFiles = fs_1.default
251
+ .readdirSync(migrationsDir)
252
+ .filter((file) => file.endsWith('.sql'))
253
+ .sort();
254
+ // Apply migrations
255
+ for (const file of migrationFiles) {
256
+ const versionMatch = file.match(/^(\d+)-/);
257
+ if (!versionMatch) {
258
+ continue;
259
+ }
260
+ const version = parseInt(versionMatch[1], 10);
261
+ if (version <= currentVersion) {
262
+ continue;
263
+ }
264
+ const migrationPath = path_1.default.join(migrationsDir, file);
265
+ const migrationSQL = fs_1.default.readFileSync(migrationPath, 'utf8');
266
+ (0, debug_logger_js_1.info)(`[sqlite-adapter] Applying migration: ${file}`);
267
+ try {
268
+ this.exec('BEGIN TRANSACTION');
269
+ this.exec(migrationSQL);
270
+ this.exec('COMMIT');
271
+ // Record migration in schema_version table (outside transaction for idempotency)
272
+ this.prepare('INSERT OR IGNORE INTO schema_version (version) VALUES (?)').run(version);
273
+ (0, debug_logger_js_1.info)(`[sqlite-adapter] Migration ${file} applied successfully`);
274
+ }
275
+ catch (err) {
276
+ this.exec('ROLLBACK');
277
+ const message = err instanceof Error ? err.message : String(err);
278
+ // Handle duplicate column errors as idempotent (migration 003)
279
+ if (message.includes('duplicate column')) {
280
+ (0, debug_logger_js_1.warn)(`[sqlite-adapter] Migration ${file} skipped (duplicate column - already applied)`);
281
+ // Record migration as applied
282
+ this.prepare('INSERT OR IGNORE INTO schema_version (version) VALUES (?)').run(version);
283
+ continue;
284
+ }
285
+ if (message.includes('no such table')) {
286
+ // Only skip if this migration contains an ALTER TABLE (adding column to optional table)
287
+ // Note: migrationSQL may contain comments, so check if ALTER TABLE exists anywhere
288
+ const hasAlterTable = migrationSQL.toUpperCase().includes('ALTER TABLE');
289
+ if (!hasAlterTable) {
290
+ (0, debug_logger_js_1.error)(`[sqlite-adapter] Migration ${file} failed (missing required table):`, err);
291
+ throw new Error(`Migration ${file} failed: ${message}`);
292
+ }
293
+ (0, debug_logger_js_1.warn)(`[sqlite-adapter] Migration ${file} skipped: ALTER TABLE on non-existent table (${message})`);
294
+ this.prepare('INSERT OR IGNORE INTO schema_version (version) VALUES (?)').run(version);
295
+ continue;
296
+ }
297
+ (0, debug_logger_js_1.error)(`[sqlite-adapter] Migration ${file} failed:`, err);
298
+ throw new Error(`Migration ${file} failed: ${message}`);
299
+ }
300
+ }
301
+ // Create vss_memories table if not exists
302
+ if (this._vectorSearchEnabled) {
303
+ const vssTables = this.prepare(`
304
+ SELECT name FROM sqlite_master
305
+ WHERE type='table' AND name='vss_memories'
306
+ `).all();
307
+ if (vssTables.length === 0) {
308
+ (0, debug_logger_js_1.info)('[sqlite-adapter] Creating vss_memories virtual table via sqlite-vec');
309
+ this.exec(`
310
+ CREATE VIRTUAL TABLE vss_memories USING vec0(
311
+ embedding float[384]
312
+ )
313
+ `);
314
+ }
315
+ }
316
+ else {
317
+ (0, debug_logger_js_1.warn)('[sqlite-adapter] Skipping vss_memories creation (sqlite-vec unavailable)');
318
+ }
319
+ }
320
+ }
321
+ exports.SQLiteAdapter = SQLiteAdapter;
322
+ exports.default = SQLiteAdapter;
323
+ function bufferToVector(buffer) {
324
+ if (!buffer) {
325
+ return null;
326
+ }
327
+ const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
328
+ return new Float32Array(arrayBuffer);
329
+ }
330
+ //# sourceMappingURL=sqlite-adapter.js.map
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Unified Statement Interface
3
+ *
4
+ * Wraps database-specific prepared statements to provide consistent API
5
+ * Compatible with better-sqlite3 and pg
6
+ *
7
+ * @module statement
8
+ */
9
+ /**
10
+ * Run result from statement execution
11
+ */
12
+ export interface RunResult {
13
+ changes: number;
14
+ lastInsertRowid: number | bigint;
15
+ }
16
+ /**
17
+ * Prepared statement interface
18
+ * Common interface used across all database modules
19
+ */
20
+ export interface PreparedStatement {
21
+ run: (...args: unknown[]) => RunResult;
22
+ get: (...args: unknown[]) => unknown;
23
+ all: (...args: unknown[]) => unknown[];
24
+ }
25
+ /**
26
+ * better-sqlite3 native statement type
27
+ */
28
+ interface BetterSQLiteStatement {
29
+ all: (...params: unknown[]) => unknown[];
30
+ get: (...params: unknown[]) => unknown;
31
+ run: (...params: unknown[]) => {
32
+ changes: number;
33
+ lastInsertRowid: number | bigint;
34
+ };
35
+ }
36
+ /**
37
+ * pg client type
38
+ */
39
+ interface PgClient {
40
+ query: (sql: string, params: unknown[]) => Promise<{
41
+ rows: unknown[];
42
+ rowCount: number | null;
43
+ }>;
44
+ }
45
+ /**
46
+ * Base statement interface
47
+ * All statement wrappers must implement these methods
48
+ */
49
+ export declare abstract class Statement {
50
+ /**
51
+ * Execute statement and return all rows
52
+ * @param params - Query parameters
53
+ * @returns All matching rows
54
+ */
55
+ abstract all(...params: unknown[]): object[];
56
+ /**
57
+ * Execute statement and return first row
58
+ * @param params - Query parameters
59
+ * @returns First matching row or undefined
60
+ */
61
+ abstract get(...params: unknown[]): object | undefined;
62
+ /**
63
+ * Execute statement without returning rows
64
+ * @param params - Query parameters
65
+ * @returns Execution info (changes, lastInsertRowid)
66
+ */
67
+ abstract run(...params: unknown[]): RunResult;
68
+ /**
69
+ * Release statement resources
70
+ */
71
+ finalize(): void;
72
+ }
73
+ /**
74
+ * SQLite statement wrapper (better-sqlite3)
75
+ */
76
+ export declare class SQLiteStatement extends Statement {
77
+ private stmt;
78
+ constructor(stmt: BetterSQLiteStatement);
79
+ all(...params: unknown[]): object[];
80
+ get(...params: unknown[]): object | undefined;
81
+ run(...params: unknown[]): RunResult;
82
+ finalize(): void;
83
+ }
84
+ /**
85
+ * PostgreSQL statement wrapper (pg)
86
+ *
87
+ * Maps pg's async query interface to synchronous-like API
88
+ * Note: This requires careful handling in the adapter
89
+ */
90
+ export declare class PostgreSQLStatement extends Statement {
91
+ private client;
92
+ private sql;
93
+ constructor(client: PgClient, sql: string);
94
+ /**
95
+ * Convert SQLite ? placeholders to PostgreSQL $1, $2, ...
96
+ * @param sql - SQL with ? placeholders
97
+ * @returns SQL with $N placeholders
98
+ *
99
+ * Note: This naive implementation replaces all '?' characters.
100
+ * It does not handle '?' inside SQL string literals or comments.
101
+ * For production use with complex SQL, consider a proper SQL parser.
102
+ */
103
+ static convertPlaceholders(sql: string): string;
104
+ all(..._params: unknown[]): object[];
105
+ get(..._params: unknown[]): object | undefined;
106
+ run(..._params: unknown[]): RunResult;
107
+ allAsync(...params: unknown[]): Promise<unknown[]>;
108
+ getAsync(...params: unknown[]): Promise<unknown>;
109
+ /**
110
+ * Execute statement asynchronously without returning rows
111
+ *
112
+ * Note: lastInsertRowid requires the SQL to include 'RETURNING id'.
113
+ * PostgreSQL does not have SQLite's last_insert_rowid() equivalent.
114
+ */
115
+ runAsync(...params: unknown[]): Promise<RunResult>;
116
+ finalize(): void;
117
+ }
118
+ export {};
119
+ //# sourceMappingURL=statement.d.ts.map
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * Unified Statement Interface
4
+ *
5
+ * Wraps database-specific prepared statements to provide consistent API
6
+ * Compatible with better-sqlite3 and pg
7
+ *
8
+ * @module statement
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.PostgreSQLStatement = exports.SQLiteStatement = exports.Statement = void 0;
12
+ /**
13
+ * Base statement interface
14
+ * All statement wrappers must implement these methods
15
+ */
16
+ class Statement {
17
+ /**
18
+ * Release statement resources
19
+ */
20
+ finalize() {
21
+ // Optional: Some drivers don't require cleanup
22
+ }
23
+ }
24
+ exports.Statement = Statement;
25
+ /**
26
+ * SQLite statement wrapper (better-sqlite3)
27
+ */
28
+ class SQLiteStatement extends Statement {
29
+ stmt;
30
+ constructor(stmt) {
31
+ super();
32
+ this.stmt = stmt;
33
+ }
34
+ all(...params) {
35
+ return this.stmt.all(...params);
36
+ }
37
+ get(...params) {
38
+ return this.stmt.get(...params);
39
+ }
40
+ run(...params) {
41
+ return this.stmt.run(...params);
42
+ }
43
+ finalize() {
44
+ // better-sqlite3 statements don't need explicit cleanup
45
+ }
46
+ }
47
+ exports.SQLiteStatement = SQLiteStatement;
48
+ /**
49
+ * PostgreSQL statement wrapper (pg)
50
+ *
51
+ * Maps pg's async query interface to synchronous-like API
52
+ * Note: This requires careful handling in the adapter
53
+ */
54
+ class PostgreSQLStatement extends Statement {
55
+ client;
56
+ sql;
57
+ constructor(client, sql) {
58
+ super();
59
+ this.client = client;
60
+ this.sql = sql;
61
+ }
62
+ /**
63
+ * Convert SQLite ? placeholders to PostgreSQL $1, $2, ...
64
+ * @param sql - SQL with ? placeholders
65
+ * @returns SQL with $N placeholders
66
+ *
67
+ * Note: This naive implementation replaces all '?' characters.
68
+ * It does not handle '?' inside SQL string literals or comments.
69
+ * For production use with complex SQL, consider a proper SQL parser.
70
+ */
71
+ static convertPlaceholders(sql) {
72
+ let index = 0;
73
+ return sql.replace(/\?/g, () => `$${++index}`);
74
+ }
75
+ // Note: PostgreSQL methods are async but the interface expects sync
76
+ // In practice, these would need to be wrapped or the adapter would handle async
77
+ all(..._params) {
78
+ // This is a simplified sync interface - actual pg usage would be async
79
+ throw new Error('PostgreSQLStatement requires async usage - use allAsync() instead');
80
+ }
81
+ get(..._params) {
82
+ throw new Error('PostgreSQLStatement requires async usage - use getAsync() instead');
83
+ }
84
+ run(..._params) {
85
+ throw new Error('PostgreSQLStatement requires async usage - use runAsync() instead');
86
+ }
87
+ async allAsync(...params) {
88
+ const result = await this.client.query(this.sql, params);
89
+ return result.rows;
90
+ }
91
+ async getAsync(...params) {
92
+ const result = await this.client.query(this.sql, params);
93
+ return result.rows[0];
94
+ }
95
+ /**
96
+ * Execute statement asynchronously without returning rows
97
+ *
98
+ * Note: lastInsertRowid requires the SQL to include 'RETURNING id'.
99
+ * PostgreSQL does not have SQLite's last_insert_rowid() equivalent.
100
+ */
101
+ async runAsync(...params) {
102
+ const result = await this.client.query(this.sql, params);
103
+ return {
104
+ changes: result.rowCount ?? 0,
105
+ lastInsertRowid: result.rows[0]?.id ?? 0,
106
+ };
107
+ }
108
+ finalize() {
109
+ // pg statements don't need explicit cleanup
110
+ }
111
+ }
112
+ exports.PostgreSQLStatement = PostgreSQLStatement;
113
+ //# sourceMappingURL=statement.js.map