@blockspool/sqlite 0.3.2 → 0.3.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/adapter.d.ts +94 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +508 -0
- package/dist/adapter.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/test/adapter-coverage.test.d.ts +2 -0
- package/dist/test/adapter-coverage.test.d.ts.map +1 -0
- package/dist/test/adapter-coverage.test.js +207 -0
- package/dist/test/adapter-coverage.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite adapter implementation
|
|
3
|
+
*
|
|
4
|
+
* Uses better-sqlite3 for synchronous, fast SQLite operations.
|
|
5
|
+
* This is the zero-config adapter for individual developers.
|
|
6
|
+
*
|
|
7
|
+
* Key differences from Postgres:
|
|
8
|
+
* - Synchronous API (better-sqlite3 is sync)
|
|
9
|
+
* - WAL mode for better concurrency
|
|
10
|
+
* - Single-writer pattern (SQLite limitation)
|
|
11
|
+
* - No RETURNING * in older SQLite versions
|
|
12
|
+
* - Different parameter placeholder syntax ($1 → ?)
|
|
13
|
+
*/
|
|
14
|
+
import type { DatabaseAdapter, DatabaseConfig, MigrationResult, QueryLogConfig, QueryResult, QueryStats, TransactionClient } from '@blockspool/core/db';
|
|
15
|
+
/**
|
|
16
|
+
* SQLite adapter for BlockSpool
|
|
17
|
+
*
|
|
18
|
+
* Features:
|
|
19
|
+
* - WAL mode for better concurrency
|
|
20
|
+
* - Auto-creates database directory
|
|
21
|
+
* - Converts Postgres-style $1 params to SQLite ? params
|
|
22
|
+
* - Embedded migrations
|
|
23
|
+
*/
|
|
24
|
+
export declare class SQLiteAdapter implements DatabaseAdapter {
|
|
25
|
+
private config;
|
|
26
|
+
readonly name = "sqlite";
|
|
27
|
+
private db;
|
|
28
|
+
private dbPath;
|
|
29
|
+
private logConfig;
|
|
30
|
+
private stats;
|
|
31
|
+
constructor(config: DatabaseConfig);
|
|
32
|
+
get connected(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Parse database path from various URL formats
|
|
35
|
+
*/
|
|
36
|
+
private parsePath;
|
|
37
|
+
/**
|
|
38
|
+
* Ensure the database directory exists
|
|
39
|
+
*/
|
|
40
|
+
private ensureDirectory;
|
|
41
|
+
/**
|
|
42
|
+
* Get or create the database connection
|
|
43
|
+
*/
|
|
44
|
+
private getDb;
|
|
45
|
+
/**
|
|
46
|
+
* Convert Postgres-style $1, $2 params to SQLite ? params
|
|
47
|
+
*
|
|
48
|
+
* Note: This is a simple conversion that assumes params are used in order.
|
|
49
|
+
* For complex queries with out-of-order params, this would need enhancement.
|
|
50
|
+
*/
|
|
51
|
+
private convertParams;
|
|
52
|
+
/**
|
|
53
|
+
* Extract query type for statistics
|
|
54
|
+
*/
|
|
55
|
+
private getQueryType;
|
|
56
|
+
/**
|
|
57
|
+
* Update statistics after a query
|
|
58
|
+
*/
|
|
59
|
+
private recordStats;
|
|
60
|
+
/**
|
|
61
|
+
* Log query if configured
|
|
62
|
+
*/
|
|
63
|
+
private logQuery;
|
|
64
|
+
query<T = Record<string, unknown>>(text: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
65
|
+
/**
|
|
66
|
+
* Extract table name from INSERT/UPDATE/DELETE statement
|
|
67
|
+
*/
|
|
68
|
+
private extractTableName;
|
|
69
|
+
withTransaction<T>(fn: (client: TransactionClient) => Promise<T>): Promise<T>;
|
|
70
|
+
migrate(options?: {
|
|
71
|
+
dryRun?: boolean;
|
|
72
|
+
target?: string;
|
|
73
|
+
verbose?: boolean;
|
|
74
|
+
}): Promise<MigrationResult>;
|
|
75
|
+
/**
|
|
76
|
+
* Get core migrations for SQLite schema
|
|
77
|
+
*
|
|
78
|
+
* These are simplified versions of the Postgres migrations,
|
|
79
|
+
* adapted for SQLite syntax.
|
|
80
|
+
*/
|
|
81
|
+
private getCoreMigrations;
|
|
82
|
+
close(): Promise<void>;
|
|
83
|
+
configureLogging(config: Partial<QueryLogConfig>): void;
|
|
84
|
+
getStats(): Readonly<QueryStats>;
|
|
85
|
+
resetStats(): void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a SQLite adapter
|
|
89
|
+
*
|
|
90
|
+
* @param config - Database configuration
|
|
91
|
+
* @returns Initialized SQLite adapter
|
|
92
|
+
*/
|
|
93
|
+
export declare function createSQLiteAdapter(config: DatabaseConfig): Promise<SQLiteAdapter>;
|
|
94
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,WAAW,EACX,UAAU,EACV,iBAAiB,EAClB,MAAM,qBAAqB,CAAC;AAY7B;;;;;;;;GAQG;AACH,qBAAa,aAAc,YAAW,eAAe;IAgBvC,OAAO,CAAC,MAAM;IAf1B,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,EAAE,CAAkC;IAC5C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAIf;IACF,OAAO,CAAC,KAAK,CAKX;gBAEkB,MAAM,EAAE,cAAc;IAK1C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACH,OAAO,CAAC,SAAS;IAWjB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,KAAK;IAmBb;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAmBrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACH,OAAO,CAAC,WAAW;IAanB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAaV,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IA8C1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAalB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA2B7E,OAAO,CAAC,OAAO,CAAC,EAAE;QACtB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,GAAG,OAAO,CAAC,eAAe,CAAC;IAyD5B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA2LnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAIvD,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC;IAIhC,UAAU,IAAI,IAAI;CAQnB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAKxF"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite adapter implementation
|
|
3
|
+
*
|
|
4
|
+
* Uses better-sqlite3 for synchronous, fast SQLite operations.
|
|
5
|
+
* This is the zero-config adapter for individual developers.
|
|
6
|
+
*
|
|
7
|
+
* Key differences from Postgres:
|
|
8
|
+
* - Synchronous API (better-sqlite3 is sync)
|
|
9
|
+
* - WAL mode for better concurrency
|
|
10
|
+
* - Single-writer pattern (SQLite limitation)
|
|
11
|
+
* - No RETURNING * in older SQLite versions
|
|
12
|
+
* - Different parameter placeholder syntax ($1 → ?)
|
|
13
|
+
*/
|
|
14
|
+
import Database from 'better-sqlite3';
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
/**
|
|
18
|
+
* SQLite adapter for BlockSpool
|
|
19
|
+
*
|
|
20
|
+
* Features:
|
|
21
|
+
* - WAL mode for better concurrency
|
|
22
|
+
* - Auto-creates database directory
|
|
23
|
+
* - Converts Postgres-style $1 params to SQLite ? params
|
|
24
|
+
* - Embedded migrations
|
|
25
|
+
*/
|
|
26
|
+
export class SQLiteAdapter {
|
|
27
|
+
config;
|
|
28
|
+
name = 'sqlite';
|
|
29
|
+
db = null;
|
|
30
|
+
dbPath;
|
|
31
|
+
logConfig = {
|
|
32
|
+
logAll: false,
|
|
33
|
+
slowQueryThresholdMs: 50, // Lower threshold for SQLite (it's faster)
|
|
34
|
+
logParams: false,
|
|
35
|
+
};
|
|
36
|
+
stats = {
|
|
37
|
+
totalQueries: 0,
|
|
38
|
+
totalErrors: 0,
|
|
39
|
+
totalDurationMs: 0,
|
|
40
|
+
byType: {},
|
|
41
|
+
};
|
|
42
|
+
constructor(config) {
|
|
43
|
+
this.config = config;
|
|
44
|
+
// Parse database path from URL
|
|
45
|
+
this.dbPath = this.parsePath(config.url);
|
|
46
|
+
}
|
|
47
|
+
get connected() {
|
|
48
|
+
return this.db !== null && this.db.open;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parse database path from various URL formats
|
|
52
|
+
*/
|
|
53
|
+
parsePath(url) {
|
|
54
|
+
if (url.startsWith('sqlite://')) {
|
|
55
|
+
return url.slice('sqlite://'.length);
|
|
56
|
+
}
|
|
57
|
+
if (url.startsWith('file:')) {
|
|
58
|
+
return url.slice('file:'.length);
|
|
59
|
+
}
|
|
60
|
+
// Assume it's a direct path
|
|
61
|
+
return url;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Ensure the database directory exists
|
|
65
|
+
*/
|
|
66
|
+
ensureDirectory() {
|
|
67
|
+
const dir = path.dirname(this.dbPath);
|
|
68
|
+
if (!fs.existsSync(dir)) {
|
|
69
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get or create the database connection
|
|
74
|
+
*/
|
|
75
|
+
getDb() {
|
|
76
|
+
if (!this.db) {
|
|
77
|
+
this.ensureDirectory();
|
|
78
|
+
this.db = new Database(this.dbPath);
|
|
79
|
+
// Enable WAL mode for better concurrency
|
|
80
|
+
if (this.config.walMode !== false) {
|
|
81
|
+
this.db.pragma('journal_mode = WAL');
|
|
82
|
+
}
|
|
83
|
+
// Other performance pragmas
|
|
84
|
+
this.db.pragma('synchronous = NORMAL');
|
|
85
|
+
this.db.pragma('cache_size = -64000'); // 64MB cache
|
|
86
|
+
this.db.pragma('foreign_keys = ON');
|
|
87
|
+
}
|
|
88
|
+
return this.db;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Convert Postgres-style $1, $2 params to SQLite ? params
|
|
92
|
+
*
|
|
93
|
+
* Note: This is a simple conversion that assumes params are used in order.
|
|
94
|
+
* For complex queries with out-of-order params, this would need enhancement.
|
|
95
|
+
*/
|
|
96
|
+
convertParams(text, params) {
|
|
97
|
+
if (!params || params.length === 0) {
|
|
98
|
+
return { sql: text, values: [] };
|
|
99
|
+
}
|
|
100
|
+
// Replace $1, $2, etc. with ?
|
|
101
|
+
// Track which params are used and in what order
|
|
102
|
+
const usedParams = [];
|
|
103
|
+
const sql = text.replace(/\$(\d+)/g, (_, num) => {
|
|
104
|
+
usedParams.push(parseInt(num, 10) - 1);
|
|
105
|
+
return '?';
|
|
106
|
+
});
|
|
107
|
+
// Reorder params based on usage
|
|
108
|
+
const values = usedParams.map((idx) => params[idx]);
|
|
109
|
+
return { sql, values };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Extract query type for statistics
|
|
113
|
+
*/
|
|
114
|
+
getQueryType(text) {
|
|
115
|
+
const trimmed = text.trim().toUpperCase();
|
|
116
|
+
if (trimmed.startsWith('SELECT'))
|
|
117
|
+
return 'SELECT';
|
|
118
|
+
if (trimmed.startsWith('INSERT'))
|
|
119
|
+
return 'INSERT';
|
|
120
|
+
if (trimmed.startsWith('UPDATE'))
|
|
121
|
+
return 'UPDATE';
|
|
122
|
+
if (trimmed.startsWith('DELETE'))
|
|
123
|
+
return 'DELETE';
|
|
124
|
+
if (trimmed.startsWith('BEGIN') || trimmed.startsWith('COMMIT') || trimmed.startsWith('ROLLBACK')) {
|
|
125
|
+
return 'TRANSACTION';
|
|
126
|
+
}
|
|
127
|
+
if (trimmed.startsWith('CREATE') || trimmed.startsWith('ALTER') || trimmed.startsWith('DROP')) {
|
|
128
|
+
return 'DDL';
|
|
129
|
+
}
|
|
130
|
+
return 'OTHER';
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Update statistics after a query
|
|
134
|
+
*/
|
|
135
|
+
recordStats(type, durationMs, isError) {
|
|
136
|
+
this.stats.totalQueries++;
|
|
137
|
+
this.stats.totalDurationMs += durationMs;
|
|
138
|
+
if (isError)
|
|
139
|
+
this.stats.totalErrors++;
|
|
140
|
+
if (!this.stats.byType[type]) {
|
|
141
|
+
this.stats.byType[type] = { count: 0, errors: 0, durationMs: 0 };
|
|
142
|
+
}
|
|
143
|
+
this.stats.byType[type].count++;
|
|
144
|
+
this.stats.byType[type].durationMs += durationMs;
|
|
145
|
+
if (isError)
|
|
146
|
+
this.stats.byType[type].errors++;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Log query if configured
|
|
150
|
+
*/
|
|
151
|
+
logQuery(text, params, durationMs) {
|
|
152
|
+
const shouldLog = this.logConfig.logAll || durationMs >= this.logConfig.slowQueryThresholdMs;
|
|
153
|
+
if (shouldLog) {
|
|
154
|
+
const paramInfo = this.logConfig.logParams && params?.length
|
|
155
|
+
? ` params=${JSON.stringify(params)}`
|
|
156
|
+
: '';
|
|
157
|
+
const slowTag = durationMs >= this.logConfig.slowQueryThresholdMs ? ' [SLOW]' : '';
|
|
158
|
+
console.log(`[sqlite]${slowTag} ${durationMs}ms: ${text.slice(0, 100)}${paramInfo}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async query(text, params) {
|
|
162
|
+
const db = this.getDb();
|
|
163
|
+
const queryType = this.getQueryType(text);
|
|
164
|
+
const { sql, values } = this.convertParams(text, params);
|
|
165
|
+
const start = Date.now();
|
|
166
|
+
try {
|
|
167
|
+
let rows = [];
|
|
168
|
+
let rowCount = null;
|
|
169
|
+
// Use run() for INSERT/UPDATE/DELETE, all() for SELECT and PRAGMA queries that return data
|
|
170
|
+
if (queryType === 'SELECT' || text.trim().toUpperCase().includes('RETURNING') || text.trim().toUpperCase().startsWith('PRAGMA')) {
|
|
171
|
+
const stmt = db.prepare(sql);
|
|
172
|
+
rows = stmt.all(...values);
|
|
173
|
+
rowCount = rows.length;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const stmt = db.prepare(sql);
|
|
177
|
+
const result = stmt.run(...values);
|
|
178
|
+
rowCount = result.changes;
|
|
179
|
+
// Handle RETURNING clause simulation for INSERT
|
|
180
|
+
if (queryType === 'INSERT' && result.lastInsertRowid) {
|
|
181
|
+
// Try to fetch the inserted row if there's a RETURNING clause
|
|
182
|
+
const returningMatch = text.match(/RETURNING\s+(.+?)(?:;|\s*$)/i);
|
|
183
|
+
if (returningMatch) {
|
|
184
|
+
const tableName = this.extractTableName(text);
|
|
185
|
+
if (tableName) {
|
|
186
|
+
const fetchStmt = db.prepare(`SELECT * FROM ${tableName} WHERE rowid = ?`);
|
|
187
|
+
rows = [fetchStmt.get(result.lastInsertRowid)].filter(Boolean);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const durationMs = Date.now() - start;
|
|
193
|
+
this.recordStats(queryType, durationMs, false);
|
|
194
|
+
this.logQuery(text, params, durationMs);
|
|
195
|
+
return { rows, rowCount };
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
const durationMs = Date.now() - start;
|
|
199
|
+
this.recordStats(queryType, durationMs, true);
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Extract table name from INSERT/UPDATE/DELETE statement
|
|
205
|
+
*/
|
|
206
|
+
extractTableName(sql) {
|
|
207
|
+
const insertMatch = sql.match(/INSERT\s+INTO\s+["']?(\w+)["']?/i);
|
|
208
|
+
if (insertMatch)
|
|
209
|
+
return insertMatch[1];
|
|
210
|
+
const updateMatch = sql.match(/UPDATE\s+["']?(\w+)["']?/i);
|
|
211
|
+
if (updateMatch)
|
|
212
|
+
return updateMatch[1];
|
|
213
|
+
const deleteMatch = sql.match(/DELETE\s+FROM\s+["']?(\w+)["']?/i);
|
|
214
|
+
if (deleteMatch)
|
|
215
|
+
return deleteMatch[1];
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
async withTransaction(fn) {
|
|
219
|
+
const db = this.getDb();
|
|
220
|
+
// SQLite transactions are synchronous with better-sqlite3
|
|
221
|
+
// But we wrap in async for interface compatibility
|
|
222
|
+
const txClient = {
|
|
223
|
+
query: async (text, params) => {
|
|
224
|
+
return this.query(text, params);
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
try {
|
|
228
|
+
db.exec('BEGIN IMMEDIATE'); // IMMEDIATE for write transactions
|
|
229
|
+
const result = await fn(txClient);
|
|
230
|
+
db.exec('COMMIT');
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
db.exec('ROLLBACK');
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async migrate(options) {
|
|
239
|
+
const db = this.getDb();
|
|
240
|
+
// Create migrations table if not exists
|
|
241
|
+
db.exec(`
|
|
242
|
+
CREATE TABLE IF NOT EXISTS _migrations (
|
|
243
|
+
id TEXT PRIMARY KEY,
|
|
244
|
+
checksum TEXT NOT NULL,
|
|
245
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
246
|
+
)
|
|
247
|
+
`);
|
|
248
|
+
// For now, run embedded core migrations
|
|
249
|
+
const migrations = this.getCoreMigrations();
|
|
250
|
+
const applied = [];
|
|
251
|
+
const skipped = [];
|
|
252
|
+
for (const migration of migrations) {
|
|
253
|
+
// Check if already applied
|
|
254
|
+
const existing = db.prepare('SELECT id FROM _migrations WHERE id = ?').get(migration.id);
|
|
255
|
+
if (existing) {
|
|
256
|
+
skipped.push(migration.id);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (options?.dryRun) {
|
|
260
|
+
if (options.verbose) {
|
|
261
|
+
console.log(`[sqlite] Would apply: ${migration.id}`);
|
|
262
|
+
}
|
|
263
|
+
applied.push(migration.id);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
// Apply migration
|
|
267
|
+
if (options?.verbose) {
|
|
268
|
+
console.log(`[sqlite] Applying: ${migration.id}`);
|
|
269
|
+
}
|
|
270
|
+
db.exec(migration.up);
|
|
271
|
+
db.prepare('INSERT INTO _migrations (id, checksum) VALUES (?, ?)').run(migration.id, migration.checksum);
|
|
272
|
+
applied.push(migration.id);
|
|
273
|
+
if (options?.target && migration.id === options.target) {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
applied,
|
|
279
|
+
skipped,
|
|
280
|
+
dryRun: options?.dryRun ?? false,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get core migrations for SQLite schema
|
|
285
|
+
*
|
|
286
|
+
* These are simplified versions of the Postgres migrations,
|
|
287
|
+
* adapted for SQLite syntax.
|
|
288
|
+
*/
|
|
289
|
+
getCoreMigrations() {
|
|
290
|
+
return [
|
|
291
|
+
{
|
|
292
|
+
id: '001_initial',
|
|
293
|
+
up: `
|
|
294
|
+
-- Projects table
|
|
295
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
296
|
+
id TEXT PRIMARY KEY,
|
|
297
|
+
name TEXT NOT NULL,
|
|
298
|
+
repo_url TEXT,
|
|
299
|
+
root_path TEXT NOT NULL,
|
|
300
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
301
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
-- Tickets table
|
|
305
|
+
CREATE TABLE IF NOT EXISTS tickets (
|
|
306
|
+
id TEXT PRIMARY KEY,
|
|
307
|
+
project_id TEXT NOT NULL REFERENCES projects(id),
|
|
308
|
+
title TEXT NOT NULL,
|
|
309
|
+
description TEXT,
|
|
310
|
+
status TEXT NOT NULL DEFAULT 'backlog',
|
|
311
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
312
|
+
shard TEXT,
|
|
313
|
+
category TEXT,
|
|
314
|
+
allowed_paths TEXT, -- JSON array
|
|
315
|
+
forbidden_paths TEXT, -- JSON array
|
|
316
|
+
verification_commands TEXT, -- JSON array
|
|
317
|
+
max_retries INTEGER DEFAULT 3,
|
|
318
|
+
retry_count INTEGER DEFAULT 0,
|
|
319
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
320
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
CREATE INDEX IF NOT EXISTS idx_tickets_project_status ON tickets(project_id, status);
|
|
324
|
+
CREATE INDEX IF NOT EXISTS idx_tickets_shard ON tickets(shard);
|
|
325
|
+
|
|
326
|
+
-- Runs table
|
|
327
|
+
CREATE TABLE IF NOT EXISTS runs (
|
|
328
|
+
id TEXT PRIMARY KEY,
|
|
329
|
+
ticket_id TEXT REFERENCES tickets(id),
|
|
330
|
+
project_id TEXT NOT NULL REFERENCES projects(id),
|
|
331
|
+
type TEXT NOT NULL DEFAULT 'worker',
|
|
332
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
333
|
+
iteration INTEGER NOT NULL DEFAULT 1,
|
|
334
|
+
max_iterations INTEGER NOT NULL DEFAULT 10,
|
|
335
|
+
started_at TEXT,
|
|
336
|
+
completed_at TEXT,
|
|
337
|
+
error TEXT,
|
|
338
|
+
metadata TEXT,
|
|
339
|
+
pr_url TEXT,
|
|
340
|
+
pr_number INTEGER,
|
|
341
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
CREATE INDEX IF NOT EXISTS idx_runs_ticket ON runs(ticket_id);
|
|
345
|
+
CREATE INDEX IF NOT EXISTS idx_runs_project ON runs(project_id);
|
|
346
|
+
CREATE INDEX IF NOT EXISTS idx_runs_type ON runs(type);
|
|
347
|
+
|
|
348
|
+
-- Leases table
|
|
349
|
+
CREATE TABLE IF NOT EXISTS leases (
|
|
350
|
+
id TEXT PRIMARY KEY,
|
|
351
|
+
ticket_id TEXT NOT NULL REFERENCES tickets(id),
|
|
352
|
+
run_id TEXT NOT NULL REFERENCES runs(id),
|
|
353
|
+
agent_id TEXT NOT NULL,
|
|
354
|
+
status TEXT NOT NULL DEFAULT 'issued',
|
|
355
|
+
expires_at TEXT NOT NULL,
|
|
356
|
+
heartbeat_at TEXT,
|
|
357
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
CREATE INDEX IF NOT EXISTS idx_leases_ticket ON leases(ticket_id);
|
|
361
|
+
CREATE INDEX IF NOT EXISTS idx_leases_status ON leases(status);
|
|
362
|
+
|
|
363
|
+
-- Run events table
|
|
364
|
+
CREATE TABLE IF NOT EXISTS run_events (
|
|
365
|
+
id TEXT PRIMARY KEY,
|
|
366
|
+
run_id TEXT NOT NULL REFERENCES runs(id),
|
|
367
|
+
type TEXT NOT NULL,
|
|
368
|
+
data TEXT, -- JSON
|
|
369
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
CREATE INDEX IF NOT EXISTS idx_run_events_run ON run_events(run_id);
|
|
373
|
+
|
|
374
|
+
-- Artifacts table
|
|
375
|
+
CREATE TABLE IF NOT EXISTS artifacts (
|
|
376
|
+
id TEXT PRIMARY KEY,
|
|
377
|
+
run_id TEXT NOT NULL REFERENCES runs(id),
|
|
378
|
+
type TEXT NOT NULL,
|
|
379
|
+
name TEXT NOT NULL,
|
|
380
|
+
content TEXT,
|
|
381
|
+
path TEXT,
|
|
382
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
CREATE INDEX IF NOT EXISTS idx_artifacts_run ON artifacts(run_id);
|
|
386
|
+
|
|
387
|
+
-- Learnings table
|
|
388
|
+
CREATE TABLE IF NOT EXISTS learnings (
|
|
389
|
+
id TEXT PRIMARY KEY,
|
|
390
|
+
project_id TEXT NOT NULL REFERENCES projects(id),
|
|
391
|
+
ticket_id TEXT REFERENCES tickets(id),
|
|
392
|
+
run_id TEXT REFERENCES runs(id),
|
|
393
|
+
content TEXT NOT NULL,
|
|
394
|
+
source TEXT NOT NULL,
|
|
395
|
+
promoted INTEGER DEFAULT 0,
|
|
396
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
CREATE INDEX IF NOT EXISTS idx_learnings_project ON learnings(project_id);
|
|
400
|
+
`,
|
|
401
|
+
checksum: 'initial-001-v1',
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
id: '002_run_steps',
|
|
405
|
+
up: `
|
|
406
|
+
-- Run steps table for QA loop and future step-based runs
|
|
407
|
+
-- Each step is a command/action within a run
|
|
408
|
+
-- Supports retry attempts with full history
|
|
409
|
+
CREATE TABLE IF NOT EXISTS run_steps (
|
|
410
|
+
id TEXT PRIMARY KEY,
|
|
411
|
+
run_id TEXT NOT NULL REFERENCES runs(id) ON DELETE CASCADE,
|
|
412
|
+
|
|
413
|
+
attempt INTEGER NOT NULL DEFAULT 1,
|
|
414
|
+
ordinal INTEGER NOT NULL,
|
|
415
|
+
|
|
416
|
+
name TEXT NOT NULL,
|
|
417
|
+
kind TEXT NOT NULL DEFAULT 'command',
|
|
418
|
+
|
|
419
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
420
|
+
|
|
421
|
+
cmd TEXT,
|
|
422
|
+
cwd TEXT,
|
|
423
|
+
timeout_ms INTEGER,
|
|
424
|
+
|
|
425
|
+
exit_code INTEGER,
|
|
426
|
+
signal TEXT,
|
|
427
|
+
|
|
428
|
+
started_at_ms INTEGER,
|
|
429
|
+
ended_at_ms INTEGER,
|
|
430
|
+
duration_ms INTEGER,
|
|
431
|
+
|
|
432
|
+
stdout_path TEXT,
|
|
433
|
+
stderr_path TEXT,
|
|
434
|
+
stdout_bytes INTEGER NOT NULL DEFAULT 0,
|
|
435
|
+
stderr_bytes INTEGER NOT NULL DEFAULT 0,
|
|
436
|
+
stdout_truncated INTEGER NOT NULL DEFAULT 0,
|
|
437
|
+
stderr_truncated INTEGER NOT NULL DEFAULT 0,
|
|
438
|
+
stdout_tail TEXT,
|
|
439
|
+
stderr_tail TEXT,
|
|
440
|
+
|
|
441
|
+
error_message TEXT,
|
|
442
|
+
meta_json TEXT,
|
|
443
|
+
|
|
444
|
+
created_at_ms INTEGER NOT NULL,
|
|
445
|
+
updated_at_ms INTEGER NOT NULL,
|
|
446
|
+
|
|
447
|
+
CONSTRAINT run_steps_status_check CHECK (
|
|
448
|
+
status IN ('queued','running','success','failed','skipped','canceled')
|
|
449
|
+
),
|
|
450
|
+
CONSTRAINT run_steps_kind_check CHECK (
|
|
451
|
+
kind IN ('command','llm_fix','git','internal')
|
|
452
|
+
),
|
|
453
|
+
CONSTRAINT run_steps_stdout_trunc_check CHECK (stdout_truncated IN (0,1)),
|
|
454
|
+
CONSTRAINT run_steps_stderr_trunc_check CHECK (stderr_truncated IN (0,1))
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
-- Unique indexes for data integrity
|
|
458
|
+
CREATE UNIQUE INDEX IF NOT EXISTS run_steps_run_attempt_name_uniq
|
|
459
|
+
ON run_steps(run_id, attempt, name);
|
|
460
|
+
|
|
461
|
+
CREATE UNIQUE INDEX IF NOT EXISTS run_steps_run_attempt_ordinal_uniq
|
|
462
|
+
ON run_steps(run_id, attempt, ordinal);
|
|
463
|
+
|
|
464
|
+
-- Query indexes
|
|
465
|
+
CREATE INDEX IF NOT EXISTS run_steps_run_attempt_idx
|
|
466
|
+
ON run_steps(run_id, attempt);
|
|
467
|
+
|
|
468
|
+
CREATE INDEX IF NOT EXISTS run_steps_run_status_idx
|
|
469
|
+
ON run_steps(run_id, status);
|
|
470
|
+
`,
|
|
471
|
+
checksum: 'run-steps-002-v1',
|
|
472
|
+
},
|
|
473
|
+
];
|
|
474
|
+
}
|
|
475
|
+
async close() {
|
|
476
|
+
if (this.db) {
|
|
477
|
+
this.db.close();
|
|
478
|
+
this.db = null;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
configureLogging(config) {
|
|
482
|
+
this.logConfig = { ...this.logConfig, ...config };
|
|
483
|
+
}
|
|
484
|
+
getStats() {
|
|
485
|
+
return { ...this.stats };
|
|
486
|
+
}
|
|
487
|
+
resetStats() {
|
|
488
|
+
this.stats = {
|
|
489
|
+
totalQueries: 0,
|
|
490
|
+
totalErrors: 0,
|
|
491
|
+
totalDurationMs: 0,
|
|
492
|
+
byType: {},
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Create a SQLite adapter
|
|
498
|
+
*
|
|
499
|
+
* @param config - Database configuration
|
|
500
|
+
* @returns Initialized SQLite adapter
|
|
501
|
+
*/
|
|
502
|
+
export async function createSQLiteAdapter(config) {
|
|
503
|
+
const adapter = new SQLiteAdapter(config);
|
|
504
|
+
// Run migrations to ensure schema exists
|
|
505
|
+
await adapter.migrate({ verbose: false });
|
|
506
|
+
return adapter;
|
|
507
|
+
}
|
|
508
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAqBlC;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAa;IAgBJ;IAfX,IAAI,GAAG,QAAQ,CAAC;IACjB,EAAE,GAA6B,IAAI,CAAC;IACpC,MAAM,CAAS;IACf,SAAS,GAAmB;QAClC,MAAM,EAAE,KAAK;QACb,oBAAoB,EAAE,EAAE,EAAE,2CAA2C;QACrE,SAAS,EAAE,KAAK;KACjB,CAAC;IACM,KAAK,GAAkB;QAC7B,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;QACd,eAAe,EAAE,CAAC;QAClB,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,YAAoB,MAAsB;QAAtB,WAAM,GAAN,MAAM,CAAgB;QACxC,+BAA+B;QAC/B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED;;OAEG;IACK,SAAS,CAAC,GAAW;QAC3B,IAAI,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,4BAA4B;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK;QACX,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,IAAI,CAAC,eAAe,EAAE,CAAC;YAEvB,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAEpC,yCAAyC;YACzC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;gBAClC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACvC,CAAC;YAED,4BAA4B;YAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;YACvC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,aAAa;YACpD,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACK,aAAa,CAAC,IAAY,EAAE,MAAkB;QACpD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACnC,CAAC;QAED,8BAA8B;QAC9B,gDAAgD;QAChD,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;YAC9C,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACvC,OAAO,GAAG,CAAC;QACb,CAAC,CAAC,CAAC;QAEH,gCAAgC;QAChC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAEpD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,IAAY;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClD,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAClG,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9F,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,IAAY,EAAE,UAAkB,EAAE,OAAgB;QACpE,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,UAAU,CAAC;QACzC,IAAI,OAAO;YAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,IAAI,UAAU,CAAC;QACjD,IAAI,OAAO;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IAChD,CAAC;IAED;;OAEG;IACK,QAAQ,CAAC,IAAY,EAAE,MAA6B,EAAE,UAAkB;QAC9E,MAAM,SAAS,GACb,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;QAE7E,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,MAAM,EAAE,MAAM;gBAC1D,CAAC,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;gBACrC,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,OAAO,GAAG,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YACnF,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,IAAI,UAAU,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CACT,IAAY,EACZ,MAAkB;QAElB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,IAAI,IAAI,GAAQ,EAAE,CAAC;YACnB,IAAI,QAAQ,GAAkB,IAAI,CAAC;YAEnC,2FAA2F;YAC3F,IAAI,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChI,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC7B,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAQ,CAAC;gBAClC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBACnC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;gBAE1B,gDAAgD;gBAChD,IAAI,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;oBACrD,8DAA8D;oBAC9D,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;oBAClE,IAAI,cAAc,EAAE,CAAC;wBACnB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;wBAC9C,IAAI,SAAS,EAAE,CAAC;4BACd,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,iBAAiB,SAAS,kBAAkB,CAAC,CAAC;4BAC3E,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;wBACtE,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;YAC/C,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;YAExC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;YAC9C,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,GAAW;QAClC,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClE,IAAI,WAAW;YAAE,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;QAEvC,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3D,IAAI,WAAW;YAAE,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;QAEvC,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClE,IAAI,WAAW;YAAE,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;QAEvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,eAAe,CAAI,EAA6C;QACpE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAExB,0DAA0D;QAC1D,mDAAmD;QACnD,MAAM,QAAQ,GAAsB;YAClC,KAAK,EAAE,KAAK,EACV,IAAY,EACZ,MAAkB,EACO,EAAE;gBAC3B,OAAO,IAAI,CAAC,KAAK,CAAI,IAAI,EAAE,MAAM,CAAC,CAAC;YACrC,CAAC;SACF,CAAC;QAEF,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,mCAAmC;YAE/D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;YAElC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAClB,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACpB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAIb;QACC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAExB,wCAAwC;QACxC,EAAE,CAAC,IAAI,CAAC;;;;;;KAMP,CAAC,CAAC;QAEH,wCAAwC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,2BAA2B;YAC3B,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACzF,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;gBACpB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,OAAO,CAAC,GAAG,CAAC,yBAAyB,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;gBACvD,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,kBAAkB;YAClB,IAAI,OAAO,EAAE,OAAO,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,sBAAsB,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,CAAC;YAED,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACtB,EAAE,CAAC,OAAO,CAAC,sDAAsD,CAAC,CAAC,GAAG,CACpE,SAAS,CAAC,EAAE,EACZ,SAAS,CAAC,QAAQ,CACnB,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAE3B,IAAI,OAAO,EAAE,MAAM,IAAI,SAAS,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;gBACvD,MAAM;YACR,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO;YACP,OAAO;YACP,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,KAAK;SACjC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,iBAAiB;QACvB,OAAO;YACL;gBACE,EAAE,EAAE,aAAa;gBACjB,EAAE,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA2GH;gBACD,QAAQ,EAAE,gBAAgB;aAC3B;YACD;gBACE,EAAE,EAAE,eAAe;gBACnB,EAAE,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAiEH;gBACD,QAAQ,EAAE,kBAAkB;aAC7B;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IAED,gBAAgB,CAAC,MAA+B;QAC9C,IAAI,CAAC,SAAS,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC;IACpD,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,GAAG;YACX,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,CAAC;YAClB,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAsB;IAC9D,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,yCAAyC;IACzC,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @blockspool/sqlite
|
|
3
|
+
*
|
|
4
|
+
* SQLite adapter for BlockSpool.
|
|
5
|
+
* Use this for zero-config local development.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - No setup required - auto-creates database
|
|
9
|
+
* - WAL mode for concurrency
|
|
10
|
+
* - Works offline
|
|
11
|
+
* - Stores data in ~/.blockspool/data.db by default
|
|
12
|
+
*/
|
|
13
|
+
export { SQLiteAdapter, createSQLiteAdapter } from './adapter.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @blockspool/sqlite
|
|
3
|
+
*
|
|
4
|
+
* SQLite adapter for BlockSpool.
|
|
5
|
+
* Use this for zero-config local development.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - No setup required - auto-creates database
|
|
9
|
+
* - WAL mode for concurrency
|
|
10
|
+
* - Works offline
|
|
11
|
+
* - Stores data in ~/.blockspool/data.db by default
|
|
12
|
+
*/
|
|
13
|
+
export { SQLiteAdapter, createSQLiteAdapter } from './adapter.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-coverage.test.d.ts","sourceRoot":"","sources":["../../src/test/adapter-coverage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import { SQLiteAdapter, createSQLiteAdapter } from '../adapter.js';
|
|
6
|
+
let tmpDir;
|
|
7
|
+
let dbPath;
|
|
8
|
+
let adapter;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sqlite-test-'));
|
|
11
|
+
dbPath = path.join(tmpDir, 'test.sqlite');
|
|
12
|
+
adapter = new SQLiteAdapter({ url: dbPath });
|
|
13
|
+
});
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
await adapter.close();
|
|
16
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
17
|
+
});
|
|
18
|
+
describe('constructor and properties', () => {
|
|
19
|
+
it('sets name to sqlite', () => {
|
|
20
|
+
expect(adapter.name).toBe('sqlite');
|
|
21
|
+
});
|
|
22
|
+
it('connected is false before first query', () => {
|
|
23
|
+
expect(adapter.connected).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
it('connected is true after query', async () => {
|
|
26
|
+
await adapter.query('SELECT 1');
|
|
27
|
+
expect(adapter.connected).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('query', () => {
|
|
31
|
+
it('SELECT returns rows', async () => {
|
|
32
|
+
const result = await adapter.query('SELECT 1 as val');
|
|
33
|
+
expect(result.rows).toEqual([{ val: 1 }]);
|
|
34
|
+
expect(result.rowCount).toBe(1);
|
|
35
|
+
});
|
|
36
|
+
it('INSERT changes rowCount', async () => {
|
|
37
|
+
await adapter.query('CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT)');
|
|
38
|
+
const result = await adapter.query("INSERT INTO t1 (id, name) VALUES (1, 'alice')");
|
|
39
|
+
expect(result.rowCount).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
it('UPDATE changes rowCount', async () => {
|
|
42
|
+
await adapter.query('CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT)');
|
|
43
|
+
await adapter.query("INSERT INTO t2 (id, name) VALUES (1, 'alice')");
|
|
44
|
+
const result = await adapter.query("UPDATE t2 SET name = 'bob' WHERE id = 1");
|
|
45
|
+
expect(result.rowCount).toBe(1);
|
|
46
|
+
});
|
|
47
|
+
it('DELETE changes rowCount', async () => {
|
|
48
|
+
await adapter.query('CREATE TABLE t3 (id INTEGER PRIMARY KEY, name TEXT)');
|
|
49
|
+
await adapter.query("INSERT INTO t3 (id, name) VALUES (1, 'alice')");
|
|
50
|
+
const result = await adapter.query('DELETE FROM t3 WHERE id = 1');
|
|
51
|
+
expect(result.rowCount).toBe(1);
|
|
52
|
+
});
|
|
53
|
+
it('throws on invalid SQL', async () => {
|
|
54
|
+
await expect(adapter.query('NOT VALID SQL')).rejects.toThrow();
|
|
55
|
+
});
|
|
56
|
+
it('DDL queries work (CREATE TABLE)', async () => {
|
|
57
|
+
await adapter.query('CREATE TABLE ddl_test (id INTEGER PRIMARY KEY)');
|
|
58
|
+
const result = await adapter.query("SELECT name FROM sqlite_master WHERE type='table' AND name='ddl_test'");
|
|
59
|
+
expect(result.rows).toHaveLength(1);
|
|
60
|
+
});
|
|
61
|
+
it('multiple sequential queries work', async () => {
|
|
62
|
+
await adapter.query('CREATE TABLE seq (id INTEGER PRIMARY KEY, val TEXT)');
|
|
63
|
+
await adapter.query("INSERT INTO seq (id, val) VALUES (1, 'a')");
|
|
64
|
+
await adapter.query("INSERT INTO seq (id, val) VALUES (2, 'b')");
|
|
65
|
+
await adapter.query("INSERT INTO seq (id, val) VALUES (3, 'c')");
|
|
66
|
+
const result = await adapter.query('SELECT * FROM seq ORDER BY id');
|
|
67
|
+
expect(result.rows).toHaveLength(3);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('convertParams (tested via real queries)', () => {
|
|
71
|
+
it('converts $1 $2 to ?', async () => {
|
|
72
|
+
await adapter.query('CREATE TABLE cp (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)');
|
|
73
|
+
await adapter.query('INSERT INTO cp (id, name, age) VALUES ($1, $2, $3)', [1, 'alice', 30]);
|
|
74
|
+
const result = await adapter.query('SELECT * FROM cp WHERE id = $1', [1]);
|
|
75
|
+
expect(result.rows).toHaveLength(1);
|
|
76
|
+
expect(result.rows[0].name).toBe('alice');
|
|
77
|
+
expect(result.rows[0].age).toBe(30);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('getQueryType (tested via stats)', () => {
|
|
81
|
+
it('tracks SELECT, INSERT, UPDATE, DELETE, DDL, OTHER types', async () => {
|
|
82
|
+
adapter.resetStats();
|
|
83
|
+
await adapter.query('CREATE TABLE qt (id INTEGER PRIMARY KEY, v TEXT)');
|
|
84
|
+
await adapter.query("INSERT INTO qt (id, v) VALUES (1, 'x')");
|
|
85
|
+
await adapter.query('SELECT * FROM qt');
|
|
86
|
+
await adapter.query("UPDATE qt SET v = 'y' WHERE id = 1");
|
|
87
|
+
await adapter.query('DELETE FROM qt WHERE id = 1');
|
|
88
|
+
const stats = adapter.getStats();
|
|
89
|
+
expect(stats.byType['DDL']).toBeDefined();
|
|
90
|
+
expect(stats.byType['DDL'].count).toBeGreaterThanOrEqual(1);
|
|
91
|
+
expect(stats.byType['INSERT']).toBeDefined();
|
|
92
|
+
expect(stats.byType['SELECT']).toBeDefined();
|
|
93
|
+
expect(stats.byType['UPDATE']).toBeDefined();
|
|
94
|
+
expect(stats.byType['DELETE']).toBeDefined();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('extractTableName (tested via RETURNING clause)', () => {
|
|
98
|
+
it('handles INSERT with RETURNING', async () => {
|
|
99
|
+
await adapter.query('CREATE TABLE ret (id INTEGER PRIMARY KEY, name TEXT)');
|
|
100
|
+
const result = await adapter.query("INSERT INTO ret (id, name) VALUES (1, 'test') RETURNING *");
|
|
101
|
+
// RETURNING simulation should return the inserted row
|
|
102
|
+
expect(result.rows).toHaveLength(1);
|
|
103
|
+
expect(result.rows[0].name).toBe('test');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('migrate', () => {
|
|
107
|
+
it('creates tables', async () => {
|
|
108
|
+
await adapter.migrate();
|
|
109
|
+
const result = await adapter.query("SELECT name FROM sqlite_master WHERE type='table' AND name='projects'");
|
|
110
|
+
expect(result.rows).toHaveLength(1);
|
|
111
|
+
});
|
|
112
|
+
it('is idempotent (running twice does not error)', async () => {
|
|
113
|
+
await adapter.migrate();
|
|
114
|
+
await expect(adapter.migrate()).resolves.not.toThrow();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe('withTransaction', () => {
|
|
118
|
+
it('commits on success', async () => {
|
|
119
|
+
await adapter.query('CREATE TABLE tx1 (id INTEGER PRIMARY KEY, v TEXT)');
|
|
120
|
+
await adapter.withTransaction(async (client) => {
|
|
121
|
+
await client.query("INSERT INTO tx1 (id, v) VALUES (1, 'committed')");
|
|
122
|
+
});
|
|
123
|
+
const result = await adapter.query('SELECT * FROM tx1');
|
|
124
|
+
expect(result.rows).toHaveLength(1);
|
|
125
|
+
});
|
|
126
|
+
it('rolls back on error', async () => {
|
|
127
|
+
await adapter.query('CREATE TABLE tx2 (id INTEGER PRIMARY KEY, v TEXT)');
|
|
128
|
+
await expect(adapter.withTransaction(async (client) => {
|
|
129
|
+
await client.query("INSERT INTO tx2 (id, v) VALUES (1, 'should_rollback')");
|
|
130
|
+
throw new Error('fail');
|
|
131
|
+
})).rejects.toThrow('fail');
|
|
132
|
+
const result = await adapter.query('SELECT * FROM tx2');
|
|
133
|
+
expect(result.rows).toHaveLength(0);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('close', () => {
|
|
137
|
+
it('sets connected to false', async () => {
|
|
138
|
+
await adapter.query('SELECT 1');
|
|
139
|
+
expect(adapter.connected).toBe(true);
|
|
140
|
+
await adapter.close();
|
|
141
|
+
expect(adapter.connected).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('configureLogging', () => {
|
|
145
|
+
it('does not throw', () => {
|
|
146
|
+
expect(() => adapter.configureLogging({ logAll: true })).not.toThrow();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe('getStats and resetStats', () => {
|
|
150
|
+
it('getStats returns stats object', async () => {
|
|
151
|
+
await adapter.query('SELECT 1');
|
|
152
|
+
const stats = adapter.getStats();
|
|
153
|
+
expect(stats).toHaveProperty('totalQueries');
|
|
154
|
+
expect(stats).toHaveProperty('totalErrors');
|
|
155
|
+
expect(stats).toHaveProperty('totalDurationMs');
|
|
156
|
+
expect(stats).toHaveProperty('byType');
|
|
157
|
+
expect(stats.totalQueries).toBeGreaterThanOrEqual(1);
|
|
158
|
+
});
|
|
159
|
+
it('resetStats resets counters', async () => {
|
|
160
|
+
await adapter.query('SELECT 1');
|
|
161
|
+
adapter.resetStats();
|
|
162
|
+
const stats = adapter.getStats();
|
|
163
|
+
expect(stats.totalQueries).toBe(0);
|
|
164
|
+
expect(stats.totalErrors).toBe(0);
|
|
165
|
+
expect(stats.totalDurationMs).toBe(0);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe('WAL mode', () => {
|
|
169
|
+
it('is enabled by default', async () => {
|
|
170
|
+
await adapter.query('SELECT 1'); // triggers connection
|
|
171
|
+
const result = await adapter.query('PRAGMA journal_mode');
|
|
172
|
+
expect(result.rows[0].journal_mode).toBe('wal');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('parsePath', () => {
|
|
176
|
+
it('handles sqlite:// prefix', async () => {
|
|
177
|
+
const a = new SQLiteAdapter({ url: `sqlite://${dbPath}` });
|
|
178
|
+
await a.query('SELECT 1');
|
|
179
|
+
expect(a.connected).toBe(true);
|
|
180
|
+
await a.close();
|
|
181
|
+
});
|
|
182
|
+
it('handles file: prefix', async () => {
|
|
183
|
+
const p = path.join(tmpDir, 'file-test.sqlite');
|
|
184
|
+
const a = new SQLiteAdapter({ url: `file:${p}` });
|
|
185
|
+
await a.query('SELECT 1');
|
|
186
|
+
expect(a.connected).toBe(true);
|
|
187
|
+
await a.close();
|
|
188
|
+
});
|
|
189
|
+
it('handles raw path', async () => {
|
|
190
|
+
const p = path.join(tmpDir, 'raw-test.sqlite');
|
|
191
|
+
const a = new SQLiteAdapter({ url: p });
|
|
192
|
+
await a.query('SELECT 1');
|
|
193
|
+
expect(a.connected).toBe(true);
|
|
194
|
+
await a.close();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('createSQLiteAdapter', () => {
|
|
198
|
+
it('returns a migrated adapter', async () => {
|
|
199
|
+
const a = await createSQLiteAdapter({ url: path.join(tmpDir, 'factory.sqlite') });
|
|
200
|
+
expect(a.name).toBe('sqlite');
|
|
201
|
+
expect(a.connected).toBe(true);
|
|
202
|
+
const result = await a.query("SELECT name FROM sqlite_master WHERE type='table' AND name='projects'");
|
|
203
|
+
expect(result.rows).toHaveLength(1);
|
|
204
|
+
await a.close();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
//# sourceMappingURL=adapter-coverage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-coverage.test.js","sourceRoot":"","sources":["../../src/test/adapter-coverage.test.ts"],"names":[],"mappings":"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"}
|