db-mcp 1.0.1
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/LICENSE +21 -0
- package/README.md +860 -0
- package/dist/adapters/DatabaseAdapter.d.ts +141 -0
- package/dist/adapters/DatabaseAdapter.d.ts.map +1 -0
- package/dist/adapters/DatabaseAdapter.js +131 -0
- package/dist/adapters/DatabaseAdapter.js.map +1 -0
- package/dist/adapters/sqlite/SchemaManager.d.ts +58 -0
- package/dist/adapters/sqlite/SchemaManager.d.ts.map +1 -0
- package/dist/adapters/sqlite/SchemaManager.js +187 -0
- package/dist/adapters/sqlite/SchemaManager.js.map +1 -0
- package/dist/adapters/sqlite/SqliteAdapter.d.ts +161 -0
- package/dist/adapters/sqlite/SqliteAdapter.d.ts.map +1 -0
- package/dist/adapters/sqlite/SqliteAdapter.js +741 -0
- package/dist/adapters/sqlite/SqliteAdapter.js.map +1 -0
- package/dist/adapters/sqlite/index.d.ts +9 -0
- package/dist/adapters/sqlite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/index.js +8 -0
- package/dist/adapters/sqlite/index.js.map +1 -0
- package/dist/adapters/sqlite/json-utils.d.ts +100 -0
- package/dist/adapters/sqlite/json-utils.d.ts.map +1 -0
- package/dist/adapters/sqlite/json-utils.js +274 -0
- package/dist/adapters/sqlite/json-utils.js.map +1 -0
- package/dist/adapters/sqlite/output-schemas.d.ts +1187 -0
- package/dist/adapters/sqlite/output-schemas.d.ts.map +1 -0
- package/dist/adapters/sqlite/output-schemas.js +1337 -0
- package/dist/adapters/sqlite/output-schemas.js.map +1 -0
- package/dist/adapters/sqlite/prompts.d.ts +13 -0
- package/dist/adapters/sqlite/prompts.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts.js +605 -0
- package/dist/adapters/sqlite/prompts.js.map +1 -0
- package/dist/adapters/sqlite/resources.d.ts +13 -0
- package/dist/adapters/sqlite/resources.d.ts.map +1 -0
- package/dist/adapters/sqlite/resources.js +251 -0
- package/dist/adapters/sqlite/resources.js.map +1 -0
- package/dist/adapters/sqlite/tools/admin.d.ts +14 -0
- package/dist/adapters/sqlite/tools/admin.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin.js +788 -0
- package/dist/adapters/sqlite/tools/admin.js.map +1 -0
- package/dist/adapters/sqlite/tools/core.d.ts +25 -0
- package/dist/adapters/sqlite/tools/core.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core.js +359 -0
- package/dist/adapters/sqlite/tools/core.js.map +1 -0
- package/dist/adapters/sqlite/tools/fts.d.ts +13 -0
- package/dist/adapters/sqlite/tools/fts.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/fts.js +347 -0
- package/dist/adapters/sqlite/tools/fts.js.map +1 -0
- package/dist/adapters/sqlite/tools/geo.d.ts +14 -0
- package/dist/adapters/sqlite/tools/geo.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/geo.js +252 -0
- package/dist/adapters/sqlite/tools/geo.js.map +1 -0
- package/dist/adapters/sqlite/tools/index.d.ts +30 -0
- package/dist/adapters/sqlite/tools/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/index.js +61 -0
- package/dist/adapters/sqlite/tools/index.js.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers.d.ts +14 -0
- package/dist/adapters/sqlite/tools/json-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers.js +477 -0
- package/dist/adapters/sqlite/tools/json-helpers.js.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations.d.ts +14 -0
- package/dist/adapters/sqlite/tools/json-operations.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations.js +839 -0
- package/dist/adapters/sqlite/tools/json-operations.js.map +1 -0
- package/dist/adapters/sqlite/tools/stats.d.ts +15 -0
- package/dist/adapters/sqlite/tools/stats.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats.js +1219 -0
- package/dist/adapters/sqlite/tools/stats.js.map +1 -0
- package/dist/adapters/sqlite/tools/text.d.ts +14 -0
- package/dist/adapters/sqlite/tools/text.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text.js +1141 -0
- package/dist/adapters/sqlite/tools/text.js.map +1 -0
- package/dist/adapters/sqlite/tools/vector.d.ts +14 -0
- package/dist/adapters/sqlite/tools/vector.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector.js +613 -0
- package/dist/adapters/sqlite/tools/vector.js.map +1 -0
- package/dist/adapters/sqlite/tools/virtual.d.ts +13 -0
- package/dist/adapters/sqlite/tools/virtual.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual.js +930 -0
- package/dist/adapters/sqlite/tools/virtual.js.map +1 -0
- package/dist/adapters/sqlite/types.d.ts +207 -0
- package/dist/adapters/sqlite/types.d.ts.map +1 -0
- package/dist/adapters/sqlite/types.js +186 -0
- package/dist/adapters/sqlite/types.js.map +1 -0
- package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts +163 -0
- package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/NativeSqliteAdapter.js +748 -0
- package/dist/adapters/sqlite-native/NativeSqliteAdapter.js.map +1 -0
- package/dist/adapters/sqlite-native/index.d.ts +11 -0
- package/dist/adapters/sqlite-native/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/index.js +11 -0
- package/dist/adapters/sqlite-native/index.js.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite.d.ts +19 -0
- package/dist/adapters/sqlite-native/tools/spatialite.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite.js +628 -0
- package/dist/adapters/sqlite-native/tools/spatialite.js.map +1 -0
- package/dist/adapters/sqlite-native/tools/transactions.d.ts +12 -0
- package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/transactions.js +255 -0
- package/dist/adapters/sqlite-native/tools/transactions.js.map +1 -0
- package/dist/adapters/sqlite-native/tools/window.d.ts +12 -0
- package/dist/adapters/sqlite-native/tools/window.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/window.js +370 -0
- package/dist/adapters/sqlite-native/tools/window.js.map +1 -0
- package/dist/auth/AuthorizationServerDiscovery.d.ts +90 -0
- package/dist/auth/AuthorizationServerDiscovery.d.ts.map +1 -0
- package/dist/auth/AuthorizationServerDiscovery.js +204 -0
- package/dist/auth/AuthorizationServerDiscovery.js.map +1 -0
- package/dist/auth/OAuthResourceServer.d.ts +65 -0
- package/dist/auth/OAuthResourceServer.d.ts.map +1 -0
- package/dist/auth/OAuthResourceServer.js +121 -0
- package/dist/auth/OAuthResourceServer.js.map +1 -0
- package/dist/auth/TokenValidator.d.ts +60 -0
- package/dist/auth/TokenValidator.d.ts.map +1 -0
- package/dist/auth/TokenValidator.js +235 -0
- package/dist/auth/TokenValidator.js.map +1 -0
- package/dist/auth/errors.d.ts +74 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/errors.js +133 -0
- package/dist/auth/errors.js.map +1 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +15 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +81 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +291 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/scopes.d.ts +136 -0
- package/dist/auth/scopes.d.ts.map +1 -0
- package/dist/auth/scopes.js +349 -0
- package/dist/auth/scopes.js.map +1 -0
- package/dist/auth/types.d.ts +257 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +8 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +236 -0
- package/dist/cli.js.map +1 -0
- package/dist/constants/ServerInstructions.d.ts +45 -0
- package/dist/constants/ServerInstructions.d.ts.map +1 -0
- package/dist/constants/ServerInstructions.js +356 -0
- package/dist/constants/ServerInstructions.js.map +1 -0
- package/dist/filtering/ToolConstants.d.ts +34 -0
- package/dist/filtering/ToolConstants.d.ts.map +1 -0
- package/dist/filtering/ToolConstants.js +174 -0
- package/dist/filtering/ToolConstants.js.map +1 -0
- package/dist/filtering/ToolFilter.d.ts +82 -0
- package/dist/filtering/ToolFilter.d.ts.map +1 -0
- package/dist/filtering/ToolFilter.js +296 -0
- package/dist/filtering/ToolFilter.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/server/McpServer.d.ts +61 -0
- package/dist/server/McpServer.d.ts.map +1 -0
- package/dist/server/McpServer.js +270 -0
- package/dist/server/McpServer.js.map +1 -0
- package/dist/transports/http.d.ts +134 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +516 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/index.d.ts +5 -0
- package/dist/transports/index.d.ts.map +1 -0
- package/dist/transports/index.js +5 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/types/index.d.ts +380 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +68 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/annotations.d.ts +44 -0
- package/dist/utils/annotations.d.ts.map +1 -0
- package/dist/utils/annotations.js +77 -0
- package/dist/utils/annotations.js.map +1 -0
- package/dist/utils/errors.d.ts +155 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +329 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/identifiers.d.ts +121 -0
- package/dist/utils/identifiers.d.ts.map +1 -0
- package/dist/utils/identifiers.js +319 -0
- package/dist/utils/identifiers.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/insightsManager.d.ts +39 -0
- package/dist/utils/insightsManager.d.ts.map +1 -0
- package/dist/utils/insightsManager.js +63 -0
- package/dist/utils/insightsManager.js.map +1 -0
- package/dist/utils/logger.d.ts +189 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +394 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/progress-utils.d.ts +54 -0
- package/dist/utils/progress-utils.d.ts.map +1 -0
- package/dist/utils/progress-utils.js +74 -0
- package/dist/utils/progress-utils.js.map +1 -0
- package/dist/utils/resourceAnnotations.d.ts +36 -0
- package/dist/utils/resourceAnnotations.d.ts.map +1 -0
- package/dist/utils/resourceAnnotations.js +57 -0
- package/dist/utils/resourceAnnotations.js.map +1 -0
- package/dist/utils/where-clause.d.ts +41 -0
- package/dist/utils/where-clause.d.ts.map +1 -0
- package/dist/utils/where-clause.js +116 -0
- package/dist/utils/where-clause.js.map +1 -0
- package/package.json +83 -0
- package/server.json +53 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite Adapter
|
|
3
|
+
*
|
|
4
|
+
* MCP adapter for SQLite databases using sql.js (WebAssembly).
|
|
5
|
+
* Provides 73 tools for database operations, JSON, text processing,
|
|
6
|
+
* statistics, vector search, and geospatial features.
|
|
7
|
+
*/
|
|
8
|
+
import initSqlJs from "sql.js";
|
|
9
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
import { DatabaseAdapter } from "../DatabaseAdapter.js";
|
|
11
|
+
import { createModuleLogger, ERROR_CODES } from "../../utils/logger.js";
|
|
12
|
+
import { QueryError, ConnectionError, ConfigurationError, } from "../../utils/errors.js";
|
|
13
|
+
import { SchemaManager } from "./SchemaManager.js";
|
|
14
|
+
// Tool definitions from modular files
|
|
15
|
+
import { getAllToolDefinitions } from "./tools/index.js";
|
|
16
|
+
import { getResourceDefinitions } from "./resources.js";
|
|
17
|
+
import { getPromptDefinitions } from "./prompts.js";
|
|
18
|
+
import { isJsonbSupportedVersion, setJsonbSupported } from "./json-utils.js";
|
|
19
|
+
// Module logger
|
|
20
|
+
const log = createModuleLogger("SQLITE");
|
|
21
|
+
/**
|
|
22
|
+
* SQLite Database Adapter
|
|
23
|
+
*
|
|
24
|
+
* Implements the DatabaseAdapter interface for SQLite using sql.js.
|
|
25
|
+
* Supports file-based and in-memory databases.
|
|
26
|
+
*/
|
|
27
|
+
export class SqliteAdapter extends DatabaseAdapter {
|
|
28
|
+
type = "sqlite";
|
|
29
|
+
name = "SQLite Adapter";
|
|
30
|
+
version = "1.0.0";
|
|
31
|
+
/**
|
|
32
|
+
* Check if this adapter uses native (better-sqlite3) backend.
|
|
33
|
+
* Returns false for WASM/sql.js adapter.
|
|
34
|
+
*/
|
|
35
|
+
isNativeBackend() {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the configured database file path.
|
|
40
|
+
* Returns the user-configured path, not internal WASM virtual filesystem paths.
|
|
41
|
+
*/
|
|
42
|
+
getConfiguredPath() {
|
|
43
|
+
return this.config?.filePath ?? this.config?.connectionString ?? ":memory:";
|
|
44
|
+
}
|
|
45
|
+
db = null;
|
|
46
|
+
config = null;
|
|
47
|
+
sqlJsInstance = null;
|
|
48
|
+
schemaManager = null;
|
|
49
|
+
/**
|
|
50
|
+
* Connect to a SQLite database
|
|
51
|
+
*/
|
|
52
|
+
async connect(config) {
|
|
53
|
+
if (config.type !== "sqlite") {
|
|
54
|
+
throw new ConfigurationError(`Invalid database type: expected 'sqlite', got '${config.type}'`, "DB_TYPE_MISMATCH");
|
|
55
|
+
}
|
|
56
|
+
this.config = config;
|
|
57
|
+
try {
|
|
58
|
+
// Initialize sql.js
|
|
59
|
+
this.sqlJsInstance = await initSqlJs();
|
|
60
|
+
const filePath = this.config.filePath ?? this.config.connectionString ?? ":memory:";
|
|
61
|
+
if (filePath === ":memory:") {
|
|
62
|
+
// Create in-memory database
|
|
63
|
+
this.db = new this.sqlJsInstance.Database();
|
|
64
|
+
log.info("Connected to in-memory SQLite database", {
|
|
65
|
+
code: "SQLITE_CONNECT",
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// For file-based databases, we need to read the file
|
|
70
|
+
// sql.js works in-memory but can load/save to files
|
|
71
|
+
try {
|
|
72
|
+
const fs = await import("fs");
|
|
73
|
+
if (fs.existsSync(filePath)) {
|
|
74
|
+
const buffer = fs.readFileSync(filePath);
|
|
75
|
+
this.db = new this.sqlJsInstance.Database(buffer);
|
|
76
|
+
log.info(`Connected to SQLite database: ${filePath}`, {
|
|
77
|
+
code: "SQLITE_CONNECT",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Create new database
|
|
82
|
+
this.db = new this.sqlJsInstance.Database();
|
|
83
|
+
log.info(`Created new SQLite database: ${filePath}`, {
|
|
84
|
+
code: "SQLITE_CONNECT",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Browser environment or no file access - create in-memory
|
|
90
|
+
this.db = new this.sqlJsInstance.Database();
|
|
91
|
+
log.warning("File access unavailable, using in-memory database", {
|
|
92
|
+
code: "SQLITE_FALLBACK",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Apply options
|
|
97
|
+
this.applyOptions(this.config.options);
|
|
98
|
+
// Enable WAL mode by default for file-based databases (better concurrency)
|
|
99
|
+
// Only if not already configured and not in-memory
|
|
100
|
+
if (filePath !== ":memory:" && !this.config.options?.walMode) {
|
|
101
|
+
try {
|
|
102
|
+
this.db.run("PRAGMA journal_mode = WAL");
|
|
103
|
+
log.info("Enabled WAL mode for better concurrency", {
|
|
104
|
+
code: "SQLITE_WAL",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// WAL mode may not be supported (e.g., sql.js limitations)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Detect JSONB support based on SQLite version
|
|
112
|
+
try {
|
|
113
|
+
const versionResult = this.db.exec("SELECT sqlite_version()");
|
|
114
|
+
const version = versionResult[0]?.values[0]?.[0] ?? "0.0.0";
|
|
115
|
+
const jsonbSupported = isJsonbSupportedVersion(version);
|
|
116
|
+
setJsonbSupported(jsonbSupported);
|
|
117
|
+
if (jsonbSupported) {
|
|
118
|
+
log.info(`JSONB support enabled (SQLite ${version})`, {
|
|
119
|
+
code: "SQLITE_JSONB",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
setJsonbSupported(false);
|
|
125
|
+
}
|
|
126
|
+
// Initialize SchemaManager with this adapter as the executor
|
|
127
|
+
this.schemaManager = new SchemaManager(this);
|
|
128
|
+
this.connected = true;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
132
|
+
log.error(`Failed to connect to SQLite: ${message}`, {
|
|
133
|
+
code: ERROR_CODES.DB.CONNECT_FAILED.full,
|
|
134
|
+
});
|
|
135
|
+
throw new ConnectionError(`SQLite connection failed: ${message}`, "DB_CONNECT_FAILED", {
|
|
136
|
+
cause: error instanceof Error ? error : undefined,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Apply SQLite PRAGMA options
|
|
142
|
+
*/
|
|
143
|
+
applyOptions(options) {
|
|
144
|
+
if (!this.db || !options)
|
|
145
|
+
return;
|
|
146
|
+
if (options.walMode) {
|
|
147
|
+
this.db.run("PRAGMA journal_mode = WAL");
|
|
148
|
+
}
|
|
149
|
+
if (options.foreignKeys !== undefined) {
|
|
150
|
+
this.db.run(`PRAGMA foreign_keys = ${options.foreignKeys ? "ON" : "OFF"}`);
|
|
151
|
+
}
|
|
152
|
+
if (options.busyTimeout !== undefined) {
|
|
153
|
+
this.db.run(`PRAGMA busy_timeout = ${options.busyTimeout}`);
|
|
154
|
+
}
|
|
155
|
+
if (options.cacheSize !== undefined) {
|
|
156
|
+
this.db.run(`PRAGMA cache_size = ${options.cacheSize}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Disconnect from the database
|
|
161
|
+
*/
|
|
162
|
+
async disconnect() {
|
|
163
|
+
if (this.db) {
|
|
164
|
+
// Save to file if configured
|
|
165
|
+
if (this.config?.filePath && this.config.filePath !== ":memory:") {
|
|
166
|
+
try {
|
|
167
|
+
const fs = await import("fs");
|
|
168
|
+
const data = this.db.export();
|
|
169
|
+
fs.writeFileSync(this.config.filePath, Buffer.from(data));
|
|
170
|
+
log.info(`Saved database to: ${this.config.filePath}`, {
|
|
171
|
+
code: "SQLITE_DISCONNECT",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
log.warning("Could not save database to file", {
|
|
176
|
+
code: "SQLITE_SAVE_FAILED",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
this.db.close();
|
|
181
|
+
this.db = null;
|
|
182
|
+
this.connected = false;
|
|
183
|
+
log.info("Disconnected from SQLite database", {
|
|
184
|
+
code: "SQLITE_DISCONNECT",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get database health status
|
|
190
|
+
*/
|
|
191
|
+
getHealth() {
|
|
192
|
+
if (!this.db) {
|
|
193
|
+
return Promise.resolve({ connected: false, error: "Not connected" });
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const start = Date.now();
|
|
197
|
+
const result = this.db.exec("SELECT sqlite_version() as version");
|
|
198
|
+
const latencyMs = Date.now() - start;
|
|
199
|
+
const version = result[0]?.values[0]?.[0] ?? "unknown";
|
|
200
|
+
return Promise.resolve({
|
|
201
|
+
connected: true,
|
|
202
|
+
latencyMs,
|
|
203
|
+
version,
|
|
204
|
+
details: {
|
|
205
|
+
filePath: this.config?.filePath ??
|
|
206
|
+
this.config?.connectionString ??
|
|
207
|
+
":memory:",
|
|
208
|
+
walMode: this.config?.options?.walMode ?? false,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
return Promise.resolve({
|
|
214
|
+
connected: false,
|
|
215
|
+
error: error instanceof Error ? error.message : String(error),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Normalize parameters for SQLite binding
|
|
221
|
+
* Converts booleans to integers since SQLite doesn't have native boolean type
|
|
222
|
+
*/
|
|
223
|
+
normalizeParams(params) {
|
|
224
|
+
if (!params)
|
|
225
|
+
return undefined;
|
|
226
|
+
return params.map((p) => {
|
|
227
|
+
if (typeof p === "boolean")
|
|
228
|
+
return p ? 1 : 0;
|
|
229
|
+
return p;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Execute a read-only query
|
|
234
|
+
*/
|
|
235
|
+
executeReadQuery(sql, params) {
|
|
236
|
+
this.ensureConnected();
|
|
237
|
+
this.validateQuery(sql, true);
|
|
238
|
+
const db = this.ensureDb();
|
|
239
|
+
const start = Date.now();
|
|
240
|
+
try {
|
|
241
|
+
const normalizedParams = this.normalizeParams(params);
|
|
242
|
+
const results = normalizedParams
|
|
243
|
+
? db.exec(sql, normalizedParams)
|
|
244
|
+
: db.exec(sql);
|
|
245
|
+
if (results.length === 0) {
|
|
246
|
+
return Promise.resolve({
|
|
247
|
+
rows: [],
|
|
248
|
+
executionTimeMs: Date.now() - start,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
const firstResult = results[0];
|
|
252
|
+
if (!firstResult) {
|
|
253
|
+
return Promise.resolve({
|
|
254
|
+
rows: [],
|
|
255
|
+
executionTimeMs: Date.now() - start,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const columns = firstResult.columns.map((name) => ({
|
|
259
|
+
name,
|
|
260
|
+
type: "unknown",
|
|
261
|
+
}));
|
|
262
|
+
const rows = firstResult.values.map((row) => {
|
|
263
|
+
const obj = {};
|
|
264
|
+
firstResult.columns.forEach((col, i) => {
|
|
265
|
+
obj[col] = row[i];
|
|
266
|
+
});
|
|
267
|
+
return obj;
|
|
268
|
+
});
|
|
269
|
+
return Promise.resolve({
|
|
270
|
+
rows,
|
|
271
|
+
columns,
|
|
272
|
+
executionTimeMs: Date.now() - start,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
277
|
+
log.error(`Query failed: ${message}`, {
|
|
278
|
+
code: ERROR_CODES.DB.QUERY_FAILED.full,
|
|
279
|
+
});
|
|
280
|
+
throw new QueryError(`Query execution failed: ${message}`, "DB_QUERY_FAILED", {
|
|
281
|
+
sql,
|
|
282
|
+
cause: error instanceof Error ? error : undefined,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Execute a write query
|
|
288
|
+
*/
|
|
289
|
+
executeWriteQuery(sql, params, skipValidation = false) {
|
|
290
|
+
this.ensureConnected();
|
|
291
|
+
if (!skipValidation) {
|
|
292
|
+
this.validateQuery(sql, false);
|
|
293
|
+
}
|
|
294
|
+
const db = this.ensureDb();
|
|
295
|
+
const start = Date.now();
|
|
296
|
+
try {
|
|
297
|
+
const normalizedParams = this.normalizeParams(params);
|
|
298
|
+
if (normalizedParams) {
|
|
299
|
+
db.run(sql, normalizedParams);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
db.run(sql);
|
|
303
|
+
}
|
|
304
|
+
const changes = db.getRowsModified();
|
|
305
|
+
// Auto-invalidate schema cache on DDL operations
|
|
306
|
+
const normalizedSql = sql.trim().toUpperCase();
|
|
307
|
+
if (normalizedSql.startsWith("CREATE") ||
|
|
308
|
+
normalizedSql.startsWith("ALTER") ||
|
|
309
|
+
normalizedSql.startsWith("DROP")) {
|
|
310
|
+
this.clearSchemaCache();
|
|
311
|
+
}
|
|
312
|
+
return Promise.resolve({
|
|
313
|
+
rowsAffected: changes,
|
|
314
|
+
executionTimeMs: Date.now() - start,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
319
|
+
log.error(`Write query failed: ${message}`, {
|
|
320
|
+
code: ERROR_CODES.DB.QUERY_FAILED.full,
|
|
321
|
+
});
|
|
322
|
+
throw new QueryError(`Write query failed: ${message}`, "DB_WRITE_FAILED", {
|
|
323
|
+
sql,
|
|
324
|
+
cause: error instanceof Error ? error : undefined,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Execute any query (for admin operations)
|
|
330
|
+
*/
|
|
331
|
+
executeQuery(sql, params) {
|
|
332
|
+
this.ensureConnected();
|
|
333
|
+
const db = this.ensureDb();
|
|
334
|
+
const start = Date.now();
|
|
335
|
+
try {
|
|
336
|
+
const normalizedParams = this.normalizeParams(params);
|
|
337
|
+
const results = normalizedParams
|
|
338
|
+
? db.exec(sql, normalizedParams)
|
|
339
|
+
: db.exec(sql);
|
|
340
|
+
if (results.length === 0) {
|
|
341
|
+
// Auto-invalidate schema cache on DDL operations
|
|
342
|
+
const normalizedSql = sql.trim().toUpperCase();
|
|
343
|
+
if (normalizedSql.startsWith("CREATE") ||
|
|
344
|
+
normalizedSql.startsWith("ALTER") ||
|
|
345
|
+
normalizedSql.startsWith("DROP")) {
|
|
346
|
+
this.clearSchemaCache();
|
|
347
|
+
}
|
|
348
|
+
return Promise.resolve({
|
|
349
|
+
rowsAffected: db.getRowsModified(),
|
|
350
|
+
executionTimeMs: Date.now() - start,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
const firstResult = results[0];
|
|
354
|
+
if (!firstResult) {
|
|
355
|
+
return Promise.resolve({
|
|
356
|
+
rowsAffected: db.getRowsModified(),
|
|
357
|
+
executionTimeMs: Date.now() - start,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
const rows = firstResult.values.map((row) => {
|
|
361
|
+
const obj = {};
|
|
362
|
+
firstResult.columns.forEach((col, i) => {
|
|
363
|
+
obj[col] = row[i];
|
|
364
|
+
});
|
|
365
|
+
return obj;
|
|
366
|
+
});
|
|
367
|
+
// Auto-invalidate schema cache on DDL operations
|
|
368
|
+
const normalizedSql = sql.trim().toUpperCase();
|
|
369
|
+
if (normalizedSql.startsWith("CREATE") ||
|
|
370
|
+
normalizedSql.startsWith("ALTER") ||
|
|
371
|
+
normalizedSql.startsWith("DROP")) {
|
|
372
|
+
this.clearSchemaCache();
|
|
373
|
+
}
|
|
374
|
+
return Promise.resolve({
|
|
375
|
+
rows,
|
|
376
|
+
executionTimeMs: Date.now() - start,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
381
|
+
throw new Error(`Query failed: ${message}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Get full database schema (cached via SchemaManager)
|
|
386
|
+
*/
|
|
387
|
+
async getSchema() {
|
|
388
|
+
this.ensureConnected();
|
|
389
|
+
if (this.schemaManager) {
|
|
390
|
+
return this.schemaManager.getSchema();
|
|
391
|
+
}
|
|
392
|
+
// Fallback if SchemaManager not initialized
|
|
393
|
+
const tables = await this.listTables();
|
|
394
|
+
const indexes = await this.getIndexes();
|
|
395
|
+
return { tables, indexes };
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* List all tables (cached via SchemaManager)
|
|
399
|
+
*/
|
|
400
|
+
async listTables() {
|
|
401
|
+
this.ensureConnected();
|
|
402
|
+
if (this.schemaManager) {
|
|
403
|
+
return this.schemaManager.listTables();
|
|
404
|
+
}
|
|
405
|
+
// Fallback if SchemaManager not initialized
|
|
406
|
+
const result = await this.executeReadQuery(`SELECT name, type FROM sqlite_master
|
|
407
|
+
WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
|
|
408
|
+
ORDER BY name`);
|
|
409
|
+
const tables = [];
|
|
410
|
+
for (const row of result.rows ?? []) {
|
|
411
|
+
const name = row["name"];
|
|
412
|
+
const type = row["type"];
|
|
413
|
+
const tableInfo = await this.describeTable(name);
|
|
414
|
+
tables.push({ ...tableInfo, type });
|
|
415
|
+
}
|
|
416
|
+
return tables;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Describe a table's structure (cached via SchemaManager)
|
|
420
|
+
*/
|
|
421
|
+
async describeTable(tableName) {
|
|
422
|
+
this.ensureConnected();
|
|
423
|
+
if (this.schemaManager) {
|
|
424
|
+
return this.schemaManager.describeTable(tableName);
|
|
425
|
+
}
|
|
426
|
+
// Fallback if SchemaManager not initialized
|
|
427
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
|
|
428
|
+
throw new Error("Invalid table name");
|
|
429
|
+
}
|
|
430
|
+
const result = await this.executeReadQuery(`PRAGMA table_info("${tableName}")`);
|
|
431
|
+
const columns = (result.rows ?? []).map((row) => ({
|
|
432
|
+
name: row["name"],
|
|
433
|
+
type: row["type"],
|
|
434
|
+
nullable: row["notnull"] === 0,
|
|
435
|
+
primaryKey: row["pk"] === 1,
|
|
436
|
+
defaultValue: row["dflt_value"],
|
|
437
|
+
}));
|
|
438
|
+
const countResult = await this.executeReadQuery(`SELECT COUNT(*) as count FROM "${tableName}"`);
|
|
439
|
+
const rowCount = countResult.rows?.[0]?.["count"] ?? 0;
|
|
440
|
+
return {
|
|
441
|
+
name: tableName,
|
|
442
|
+
type: "table",
|
|
443
|
+
columns,
|
|
444
|
+
rowCount,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* List available schemas (SQLite has only 'main')
|
|
449
|
+
*/
|
|
450
|
+
listSchemas() {
|
|
451
|
+
return Promise.resolve(["main"]);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Get indexes, optionally for a specific table (cached via SchemaManager)
|
|
455
|
+
*/
|
|
456
|
+
async getIndexes(table) {
|
|
457
|
+
this.ensureConnected();
|
|
458
|
+
if (this.schemaManager) {
|
|
459
|
+
if (table) {
|
|
460
|
+
return this.schemaManager.getTableIndexes(table);
|
|
461
|
+
}
|
|
462
|
+
return this.schemaManager.getAllIndexes();
|
|
463
|
+
}
|
|
464
|
+
// Fallback if SchemaManager not initialized
|
|
465
|
+
let sql = `SELECT name, tbl_name, sql FROM sqlite_master
|
|
466
|
+
WHERE type = 'index' AND sql IS NOT NULL`;
|
|
467
|
+
if (table) {
|
|
468
|
+
sql += ` AND tbl_name = '${table.replace(/'/g, "''")}'`;
|
|
469
|
+
}
|
|
470
|
+
const result = await this.executeReadQuery(sql);
|
|
471
|
+
const indexes = [];
|
|
472
|
+
for (const row of result.rows ?? []) {
|
|
473
|
+
const indexName = row["name"];
|
|
474
|
+
const tableName = row["tbl_name"];
|
|
475
|
+
const sqlDef = row["sql"];
|
|
476
|
+
// Get column info for this index via PRAGMA index_info
|
|
477
|
+
let columns = [];
|
|
478
|
+
try {
|
|
479
|
+
const indexInfo = await this.executeReadQuery(`PRAGMA index_info("${indexName}")`);
|
|
480
|
+
columns = (indexInfo.rows ?? []).map((col) => col["name"]);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
// If PRAGMA fails, fall back to empty columns
|
|
484
|
+
columns = [];
|
|
485
|
+
}
|
|
486
|
+
indexes.push({
|
|
487
|
+
name: indexName,
|
|
488
|
+
tableName,
|
|
489
|
+
columns,
|
|
490
|
+
unique: sqlDef?.toUpperCase().includes("UNIQUE") ?? false,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return indexes;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Get all indexes in a single query (cached via SchemaManager)
|
|
497
|
+
* Performance optimization: eliminates N+1 query pattern
|
|
498
|
+
*/
|
|
499
|
+
async getAllIndexes() {
|
|
500
|
+
return this.getIndexes();
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Clear the schema metadata cache
|
|
504
|
+
* Call after DDL operations or when fresh data is needed
|
|
505
|
+
*/
|
|
506
|
+
clearSchemaCache() {
|
|
507
|
+
if (this.schemaManager) {
|
|
508
|
+
this.schemaManager.clearCache();
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get adapter capabilities
|
|
513
|
+
*/
|
|
514
|
+
getCapabilities() {
|
|
515
|
+
return {
|
|
516
|
+
json: true,
|
|
517
|
+
fullTextSearch: true, // FTS5 support
|
|
518
|
+
vector: true, // Custom implementation
|
|
519
|
+
geospatial: false, // SpatiaLite not bundled
|
|
520
|
+
transactions: true,
|
|
521
|
+
preparedStatements: true,
|
|
522
|
+
connectionPooling: false, // sql.js is single-connection
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Get supported tool groups
|
|
527
|
+
*/
|
|
528
|
+
getSupportedToolGroups() {
|
|
529
|
+
return ["core", "json", "text", "stats", "vector", "admin", "geo"];
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Get all tool definitions
|
|
533
|
+
*/
|
|
534
|
+
getToolDefinitions() {
|
|
535
|
+
return getAllToolDefinitions(this);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Get resource definitions
|
|
539
|
+
*/
|
|
540
|
+
getResourceDefinitions() {
|
|
541
|
+
return getResourceDefinitions(this);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Get prompt definitions
|
|
545
|
+
*/
|
|
546
|
+
getPromptDefinitions() {
|
|
547
|
+
return getPromptDefinitions(this);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Get adapter info for metadata resource
|
|
551
|
+
*/
|
|
552
|
+
getInfo() {
|
|
553
|
+
return {
|
|
554
|
+
type: this.type,
|
|
555
|
+
name: this.name,
|
|
556
|
+
version: this.version,
|
|
557
|
+
connected: this.connected,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Register a single tool with the MCP server
|
|
562
|
+
* Uses modern registerTool() API for MCP 2025-11-25 compliance
|
|
563
|
+
*/
|
|
564
|
+
registerTool(server, tool) {
|
|
565
|
+
// Build tool options for registerTool()
|
|
566
|
+
const toolOptions = {
|
|
567
|
+
description: tool.description,
|
|
568
|
+
};
|
|
569
|
+
// Pass full inputSchema (not just .shape) for proper validation
|
|
570
|
+
if (tool.inputSchema !== undefined) {
|
|
571
|
+
toolOptions["inputSchema"] = tool.inputSchema;
|
|
572
|
+
}
|
|
573
|
+
// MCP 2025-11-25: Pass outputSchema for structured responses
|
|
574
|
+
if (tool.outputSchema !== undefined) {
|
|
575
|
+
toolOptions["outputSchema"] = tool.outputSchema;
|
|
576
|
+
}
|
|
577
|
+
// MCP 2025-11-25: Pass annotations for behavioral hints
|
|
578
|
+
if (tool.annotations) {
|
|
579
|
+
toolOptions["annotations"] = tool.annotations;
|
|
580
|
+
}
|
|
581
|
+
// Track whether tool has outputSchema for response handling
|
|
582
|
+
const hasOutputSchema = Boolean(tool.outputSchema);
|
|
583
|
+
server.registerTool(tool.name, toolOptions, async (args, extra) => {
|
|
584
|
+
try {
|
|
585
|
+
// Extract progressToken from extra._meta (SDK passes RequestHandlerExtra)
|
|
586
|
+
const extraMeta = extra;
|
|
587
|
+
const progressToken = extraMeta?._meta?.progressToken;
|
|
588
|
+
// Create context with progress support
|
|
589
|
+
const context = this.createContext(undefined, server.server, progressToken);
|
|
590
|
+
const result = await tool.handler(args, context);
|
|
591
|
+
// MCP 2025-11-25: Return structuredContent if outputSchema present
|
|
592
|
+
if (hasOutputSchema) {
|
|
593
|
+
return {
|
|
594
|
+
content: [
|
|
595
|
+
{
|
|
596
|
+
type: "text",
|
|
597
|
+
text: JSON.stringify(result, null, 2),
|
|
598
|
+
},
|
|
599
|
+
],
|
|
600
|
+
structuredContent: result,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
// Standard text content response
|
|
604
|
+
return {
|
|
605
|
+
content: [
|
|
606
|
+
{
|
|
607
|
+
type: "text",
|
|
608
|
+
text: typeof result === "string"
|
|
609
|
+
? result
|
|
610
|
+
: JSON.stringify(result, null, 2),
|
|
611
|
+
},
|
|
612
|
+
],
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
return {
|
|
617
|
+
content: [
|
|
618
|
+
{
|
|
619
|
+
type: "text",
|
|
620
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
621
|
+
},
|
|
622
|
+
],
|
|
623
|
+
isError: true,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Register a single resource with the MCP server
|
|
630
|
+
* Handles both static resources and URI templates
|
|
631
|
+
*/
|
|
632
|
+
registerResource(server, resource) {
|
|
633
|
+
// Check if URI contains template placeholders like {tableName}
|
|
634
|
+
const isTemplate = /\{[^}]+\}/.test(resource.uri);
|
|
635
|
+
if (isTemplate) {
|
|
636
|
+
// Create ResourceTemplate for parameterized URIs
|
|
637
|
+
// list: undefined signals no enumeration callback for this template
|
|
638
|
+
const template = new ResourceTemplate(resource.uri, { list: undefined });
|
|
639
|
+
server.registerResource(resource.name, template, {
|
|
640
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
641
|
+
description: resource.description,
|
|
642
|
+
},
|
|
643
|
+
// Callback receives URL and extracted template variables
|
|
644
|
+
async (resourceUri, _variables) => {
|
|
645
|
+
// Pass full URI to handler so it can extract variables
|
|
646
|
+
const context = this.createContext();
|
|
647
|
+
const content = await resource.handler(resourceUri.toString(), context);
|
|
648
|
+
return {
|
|
649
|
+
contents: [
|
|
650
|
+
{
|
|
651
|
+
uri: resourceUri.toString(),
|
|
652
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
653
|
+
text: typeof content === "string"
|
|
654
|
+
? content
|
|
655
|
+
: JSON.stringify(content, null, 2),
|
|
656
|
+
},
|
|
657
|
+
],
|
|
658
|
+
};
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
// Static resource registration
|
|
663
|
+
server.registerResource(resource.name, resource.uri, {
|
|
664
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
665
|
+
description: resource.description,
|
|
666
|
+
}, async (resourceUri) => {
|
|
667
|
+
const context = this.createContext();
|
|
668
|
+
const content = await resource.handler(resourceUri.toString(), context);
|
|
669
|
+
return {
|
|
670
|
+
contents: [
|
|
671
|
+
{
|
|
672
|
+
uri: resourceUri.toString(),
|
|
673
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
674
|
+
text: typeof content === "string"
|
|
675
|
+
? content
|
|
676
|
+
: JSON.stringify(content, null, 2),
|
|
677
|
+
},
|
|
678
|
+
],
|
|
679
|
+
};
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Register a single prompt with the MCP server
|
|
685
|
+
*/
|
|
686
|
+
registerPrompt(server, prompt) {
|
|
687
|
+
server.registerPrompt(prompt.name, { description: prompt.description }, async (args) => {
|
|
688
|
+
const context = this.createContext();
|
|
689
|
+
const result = await prompt.handler(args, context);
|
|
690
|
+
// Type-safe message construction
|
|
691
|
+
const messages = Array.isArray(result)
|
|
692
|
+
? result
|
|
693
|
+
: [
|
|
694
|
+
{
|
|
695
|
+
role: "assistant",
|
|
696
|
+
content: {
|
|
697
|
+
type: "text",
|
|
698
|
+
text: typeof result === "string"
|
|
699
|
+
? result
|
|
700
|
+
: JSON.stringify(result),
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
];
|
|
704
|
+
return { messages };
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Ensure database is connected
|
|
709
|
+
*/
|
|
710
|
+
ensureConnected() {
|
|
711
|
+
if (!this.db || !this.connected) {
|
|
712
|
+
throw new Error("Not connected to database");
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Ensure database is connected and return the database instance
|
|
717
|
+
*/
|
|
718
|
+
ensureDb() {
|
|
719
|
+
if (!this.db || !this.connected) {
|
|
720
|
+
throw new Error("Not connected to database");
|
|
721
|
+
}
|
|
722
|
+
return this.db;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Get the raw database instance (for tools)
|
|
726
|
+
*/
|
|
727
|
+
getDatabase() {
|
|
728
|
+
return this.ensureDb();
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Execute raw SQL and return results (for tools)
|
|
732
|
+
*/
|
|
733
|
+
rawQuery(sql, params) {
|
|
734
|
+
return this.executeQuery(sql, params);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
// Factory function
|
|
738
|
+
export function createSqliteAdapter() {
|
|
739
|
+
return new SqliteAdapter();
|
|
740
|
+
}
|
|
741
|
+
//# sourceMappingURL=SqliteAdapter.js.map
|