Skip to content

Commit 0ae4e55

Browse files
committed
Fix common js / esm interop problem with sqlite3
1 parent e4153fa commit 0ae4e55

File tree

1 file changed

+45
-18
lines changed

1 file changed

+45
-18
lines changed

src/index.ts

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
ListToolsRequestSchema,
66
ToolSchema,
77
} from '@modelcontextprotocol/sdk/types.js';
8-
import { Database } from 'sqlite3';
8+
import sqlite3 from 'sqlite3';
99
import { z } from 'zod';
1010
import { zodToJsonSchema } from 'zod-to-json-schema';
1111
import path from 'path';
@@ -44,33 +44,60 @@ const AppendInsightArgsSchema = z.object({
4444
.describe('Business insight discovered from data analysis'),
4545
});
4646

47+
interface RunResult {
48+
affectedRows: number;
49+
}
50+
51+
/**
52+
* Wrapper for sqlite3.Database that bridges CommonJS and ESM modules.
53+
* This abstraction is necessary because:
54+
* 1. sqlite3 is a CommonJS module while we're using ESM (type: "module")
55+
* 2. The module interop requires careful handling of the Database import
56+
* 3. We need to promisify the callback-based API to work better with async/await
57+
*/
58+
class DatabaseWrapper {
59+
private readonly db: sqlite3.Database;
60+
61+
constructor(filename: string) {
62+
this.db = new sqlite3.Database(filename);
63+
}
64+
65+
query(sql: string, params: any[] = []): Promise<any[]> {
66+
return new Promise((resolve, reject) => {
67+
this.db.all(sql, params, (err: Error | null, rows: any[]) => {
68+
if (err) reject(err);
69+
else resolve(rows);
70+
});
71+
});
72+
}
73+
74+
execute(sql: string, params: any[] = []): Promise<RunResult[]> {
75+
return new Promise((resolve, reject) => {
76+
this.db.run(
77+
sql,
78+
params,
79+
function (this: sqlite3.RunResult, err: Error | null) {
80+
if (err) reject(err);
81+
else resolve([{ affectedRows: this.changes }]);
82+
},
83+
);
84+
});
85+
}
86+
}
87+
4788
class SqliteDatabase {
48-
private readonly db: Database;
89+
private readonly db: DatabaseWrapper;
4990
private readonly insights: string[] = [];
5091

5192
constructor(dbPath: string) {
52-
this.db = new Database(dbPath);
93+
this.db = new DatabaseWrapper(dbPath);
5394
}
5495

5596
private async query<T>(
5697
sql: string,
5798
params: any[] = [],
5899
): Promise<T[]> {
59-
return new Promise((resolve, reject) => {
60-
const isSelect = sql.trim().toUpperCase().startsWith('SELECT');
61-
62-
if (isSelect) {
63-
this.db.all(sql, params, (err, rows) => {
64-
if (err) reject(err);
65-
else resolve(rows as T[]);
66-
});
67-
} else {
68-
this.db.run(sql, params, function (err) {
69-
if (err) reject(err);
70-
else resolve([{ affectedRows: this.changes } as any]);
71-
});
72-
}
73-
});
100+
return this.db.query(sql, params);
74101
}
75102

76103
synthesizeMemo(): string {

0 commit comments

Comments
 (0)