@sleep2agi/commhub-server 0.5.0-preview.15 → 0.5.0-preview.16
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/package.json +1 -1
- package/src/db-adapter.ts +72 -0
package/package.json
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Adapter Interface — async-first, supports SQLite and PostgreSQL
|
|
3
|
+
*
|
|
4
|
+
* SQLite adapter: wraps bun:sqlite sync calls in Promise (zero overhead)
|
|
5
|
+
* PostgreSQL adapter: uses bun:sql native async
|
|
6
|
+
*
|
|
7
|
+
* All callers use await — sync SQLite just resolves immediately.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface QueryResult {
|
|
11
|
+
changes: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DbAdapter {
|
|
15
|
+
/** Execute a write query (INSERT/UPDATE/DELETE) */
|
|
16
|
+
run(sql: string, params?: any[]): QueryResult;
|
|
17
|
+
|
|
18
|
+
/** Query a single row */
|
|
19
|
+
get<T = any>(sql: string, ...params: any[]): T | null;
|
|
20
|
+
|
|
21
|
+
/** Query multiple rows */
|
|
22
|
+
all<T = any>(sql: string, ...params: any[]): T[];
|
|
23
|
+
|
|
24
|
+
/** Execute raw SQL (DDL) */
|
|
25
|
+
exec(sql: string): void;
|
|
26
|
+
|
|
27
|
+
/** Run a function inside a transaction */
|
|
28
|
+
transaction<T>(fn: () => T): T;
|
|
29
|
+
|
|
30
|
+
/** Close connection */
|
|
31
|
+
close(): void;
|
|
32
|
+
|
|
33
|
+
/** Dialect identifier */
|
|
34
|
+
readonly dialect: 'sqlite' | 'postgres';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Phase 1 strategy:
|
|
39
|
+
*
|
|
40
|
+
* Current code is sync (bun:sqlite). We keep it sync for now.
|
|
41
|
+
* All DB access goes through the adapter interface above.
|
|
42
|
+
*
|
|
43
|
+
* When we add PostgreSQL (Phase 2), the adapter interface
|
|
44
|
+
* will change to async. At that point we'll update callers
|
|
45
|
+
* in a single pass. The unified call sites from Phase 1
|
|
46
|
+
* make that pass mechanical rather than archaeological.
|
|
47
|
+
*
|
|
48
|
+
* Why not async-first now?
|
|
49
|
+
* - bun:sqlite is sync, wrapping in Promise adds noise
|
|
50
|
+
* - All MCP tool handlers are already async, so the future
|
|
51
|
+
* migration is: db.run() → await db.run(), straightforward
|
|
52
|
+
* - 750+ lines of tools.ts would need gratuitous await for zero benefit today
|
|
53
|
+
*
|
|
54
|
+
* The contract: every DB call goes through adapter methods,
|
|
55
|
+
* never through raw db.query() or db.run() on the bun:sqlite object.
|
|
56
|
+
* This is what makes Phase 2 feasible.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/** SQL helpers for cross-dialect compatibility */
|
|
60
|
+
export function sqlNow(dialect: 'sqlite' | 'postgres'): string {
|
|
61
|
+
return dialect === 'postgres' ? 'NOW()' : "datetime('now')";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function sqlAddSeconds(dialect: 'sqlite' | 'postgres', seconds: number | string): string {
|
|
65
|
+
return dialect === 'postgres'
|
|
66
|
+
? `NOW() + INTERVAL '${seconds} seconds'`
|
|
67
|
+
: `datetime('now', '+${seconds} seconds')`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function sqlPlaceholder(dialect: 'sqlite' | 'postgres', index: number): string {
|
|
71
|
+
return dialect === 'postgres' ? `$${index}` : `?${index}`;
|
|
72
|
+
}
|