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,748 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native SQLite Adapter using better-sqlite3
|
|
3
|
+
*
|
|
4
|
+
* Provides synchronous, native SQLite access with full FTS5, window functions,
|
|
5
|
+
* and SpatiaLite support.
|
|
6
|
+
*/
|
|
7
|
+
import Database from "better-sqlite3";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { DatabaseAdapter } from "../DatabaseAdapter.js";
|
|
11
|
+
import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
import { logger, ERROR_CODES } from "../../utils/logger.js";
|
|
13
|
+
// Import shared tools from sql.js adapter
|
|
14
|
+
import { getCoreTools } from "../sqlite/tools/core.js";
|
|
15
|
+
import { getJsonOperationTools } from "../sqlite/tools/json-operations.js";
|
|
16
|
+
import { getJsonHelperTools } from "../sqlite/tools/json-helpers.js";
|
|
17
|
+
import { getTextTools } from "../sqlite/tools/text.js";
|
|
18
|
+
import { getFtsTools } from "../sqlite/tools/fts.js";
|
|
19
|
+
import { getStatsTools } from "../sqlite/tools/stats.js";
|
|
20
|
+
import { getVirtualTools } from "../sqlite/tools/virtual.js";
|
|
21
|
+
import { getVectorTools } from "../sqlite/tools/vector.js";
|
|
22
|
+
import { getGeoTools } from "../sqlite/tools/geo.js";
|
|
23
|
+
import { getAdminTools } from "../sqlite/tools/admin.js";
|
|
24
|
+
import { getResourceDefinitions } from "../sqlite/resources.js";
|
|
25
|
+
import { getPromptDefinitions } from "../sqlite/prompts.js";
|
|
26
|
+
import { isJsonbSupportedVersion, setJsonbSupported, } from "../sqlite/json-utils.js";
|
|
27
|
+
// Import native-specific tools
|
|
28
|
+
import { getTransactionTools } from "./tools/transactions.js";
|
|
29
|
+
import { getWindowTools } from "./tools/window.js";
|
|
30
|
+
import { getSpatialiteTools, isSpatialiteLoaded } from "./tools/spatialite.js";
|
|
31
|
+
const log = logger.child("NATIVE_SQLITE");
|
|
32
|
+
/**
|
|
33
|
+
* Native SQLite Adapter using better-sqlite3
|
|
34
|
+
*/
|
|
35
|
+
export class NativeSqliteAdapter extends DatabaseAdapter {
|
|
36
|
+
type = "sqlite";
|
|
37
|
+
name = "Native SQLite Adapter (better-sqlite3)";
|
|
38
|
+
version = "1.0.0";
|
|
39
|
+
/**
|
|
40
|
+
* Check if this adapter uses native (better-sqlite3) backend.
|
|
41
|
+
* Returns true for native adapter.
|
|
42
|
+
*/
|
|
43
|
+
isNativeBackend() {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the configured database file path.
|
|
48
|
+
* Returns the user-configured path, not internal WASM virtual filesystem paths.
|
|
49
|
+
*/
|
|
50
|
+
getConfiguredPath() {
|
|
51
|
+
const config = this.config;
|
|
52
|
+
return config?.filePath ?? config?.connectionString ?? ":memory:";
|
|
53
|
+
}
|
|
54
|
+
db = null;
|
|
55
|
+
/**
|
|
56
|
+
* Connect to a SQLite database using better-sqlite3
|
|
57
|
+
*/
|
|
58
|
+
connect(config) {
|
|
59
|
+
if (config.type !== "sqlite") {
|
|
60
|
+
throw new Error(`Invalid database type: expected 'sqlite', got '${config.type}'`);
|
|
61
|
+
}
|
|
62
|
+
const sqliteConfig = config;
|
|
63
|
+
this.config = sqliteConfig;
|
|
64
|
+
try {
|
|
65
|
+
const filePath = sqliteConfig.filePath ?? sqliteConfig.connectionString ?? ":memory:";
|
|
66
|
+
// Create database connection
|
|
67
|
+
this.db = new Database(filePath, {
|
|
68
|
+
readonly: false,
|
|
69
|
+
fileMustExist: false,
|
|
70
|
+
});
|
|
71
|
+
log.info(`Connected to SQLite database (native): ${filePath}`, {
|
|
72
|
+
code: "SQLITE_CONNECT",
|
|
73
|
+
});
|
|
74
|
+
// Apply options
|
|
75
|
+
this.applyOptions(sqliteConfig.options);
|
|
76
|
+
// Enable WAL mode by default for file-based databases
|
|
77
|
+
if (filePath !== ":memory:" && !sqliteConfig.options?.walMode) {
|
|
78
|
+
try {
|
|
79
|
+
this.db.pragma("journal_mode = WAL");
|
|
80
|
+
log.info("Enabled WAL mode for better concurrency", {
|
|
81
|
+
code: "SQLITE_WAL",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// WAL mode may not be available
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Detect JSONB support based on SQLite version
|
|
89
|
+
try {
|
|
90
|
+
const versionResult = this.db
|
|
91
|
+
.prepare("SELECT sqlite_version()")
|
|
92
|
+
.get();
|
|
93
|
+
const version = versionResult?.["sqlite_version()"] ?? "0.0.0";
|
|
94
|
+
const jsonbSupported = isJsonbSupportedVersion(version);
|
|
95
|
+
setJsonbSupported(jsonbSupported);
|
|
96
|
+
if (jsonbSupported) {
|
|
97
|
+
log.info(`JSONB support enabled (SQLite ${version})`, {
|
|
98
|
+
code: "SQLITE_JSONB",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
setJsonbSupported(false);
|
|
104
|
+
}
|
|
105
|
+
this.connected = true;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
109
|
+
log.error(`Failed to connect to native SQLite: ${message}`, {
|
|
110
|
+
code: ERROR_CODES.DB.CONNECT_FAILED.full,
|
|
111
|
+
});
|
|
112
|
+
throw new Error(`Native SQLite connection failed: ${message}`);
|
|
113
|
+
}
|
|
114
|
+
return Promise.resolve();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Apply SQLite PRAGMA options
|
|
118
|
+
*/
|
|
119
|
+
applyOptions(options) {
|
|
120
|
+
if (!this.db || !options)
|
|
121
|
+
return;
|
|
122
|
+
if (options.walMode) {
|
|
123
|
+
this.db.pragma("journal_mode = WAL");
|
|
124
|
+
}
|
|
125
|
+
if (options.foreignKeys !== undefined) {
|
|
126
|
+
this.db.pragma(`foreign_keys = ${options.foreignKeys ? "ON" : "OFF"}`);
|
|
127
|
+
}
|
|
128
|
+
if (options.busyTimeout !== undefined) {
|
|
129
|
+
this.db.pragma(`busy_timeout = ${options.busyTimeout}`);
|
|
130
|
+
}
|
|
131
|
+
if (options.cacheSize !== undefined) {
|
|
132
|
+
this.db.pragma(`cache_size = ${options.cacheSize}`);
|
|
133
|
+
}
|
|
134
|
+
if (options.spatialite) {
|
|
135
|
+
// Compute absolute path to extensions directory
|
|
136
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
137
|
+
const __dirname = path.dirname(__filename);
|
|
138
|
+
const extensionsDir = path.resolve(__dirname, "../../../extensions");
|
|
139
|
+
const spatialitePaths = [
|
|
140
|
+
process.env["SPATIALITE_PATH"],
|
|
141
|
+
// Absolute paths to local extensions
|
|
142
|
+
path.join(extensionsDir, "mod_spatialite-5.1.0-win-amd64", "mod_spatialite"),
|
|
143
|
+
path.join(extensionsDir, "mod_spatialite-5.1.0-win-amd64", "mod_spatialite.dll"),
|
|
144
|
+
// System paths
|
|
145
|
+
"mod_spatialite",
|
|
146
|
+
"mod_spatialite.dll",
|
|
147
|
+
"/usr/lib/x86_64-linux-gnu/mod_spatialite.so",
|
|
148
|
+
"/usr/local/lib/mod_spatialite.so",
|
|
149
|
+
"/usr/local/lib/mod_spatialite.dylib",
|
|
150
|
+
].filter((p) => Boolean(p));
|
|
151
|
+
// On Windows, SpatiaLite DLL has many dependencies (libgeos, libproj, etc.)
|
|
152
|
+
// These must be in PATH for Windows to find them when loading the extension.
|
|
153
|
+
// Prepend the extension directory to PATH before attempting to load.
|
|
154
|
+
const envSpatialitePath = process.env["SPATIALITE_PATH"];
|
|
155
|
+
if (envSpatialitePath && process.platform === "win32") {
|
|
156
|
+
const spatialiteExtDir = path.dirname(envSpatialitePath);
|
|
157
|
+
const currentPath = process.env["PATH"] ?? "";
|
|
158
|
+
if (!currentPath.includes(spatialiteExtDir)) {
|
|
159
|
+
process.env["PATH"] = spatialiteExtDir + ";" + currentPath;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let loaded = false;
|
|
163
|
+
for (const extPath of spatialitePaths) {
|
|
164
|
+
try {
|
|
165
|
+
this.db.loadExtension(extPath);
|
|
166
|
+
log.info(`Loaded SpatiaLite extension from ${extPath}`, {
|
|
167
|
+
code: "SQLITE_EXTENSION",
|
|
168
|
+
});
|
|
169
|
+
loaded = true;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Try next path
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!loaded) {
|
|
177
|
+
log.warning("SpatiaLite extension not available. Set SPATIALITE_PATH env var.", { code: "SQLITE_EXTENSION" });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (options.csv) {
|
|
181
|
+
// Compute absolute path to extensions directory
|
|
182
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
183
|
+
const __dirname = path.dirname(__filename);
|
|
184
|
+
const extensionsDir = path.resolve(__dirname, "../../../extensions");
|
|
185
|
+
const csvPaths = [
|
|
186
|
+
process.env["CSV_EXTENSION_PATH"],
|
|
187
|
+
// sqlite-xsv extension with absolute paths
|
|
188
|
+
path.join(extensionsDir, "xsv0.dll"),
|
|
189
|
+
path.join(extensionsDir, "xsv0"),
|
|
190
|
+
// System paths
|
|
191
|
+
"xsv0",
|
|
192
|
+
"xsv0.dll",
|
|
193
|
+
"csv",
|
|
194
|
+
"csv.dll",
|
|
195
|
+
"csv.so",
|
|
196
|
+
"/usr/local/lib/csv.so",
|
|
197
|
+
"/usr/local/lib/csv.dylib",
|
|
198
|
+
].filter((p) => Boolean(p));
|
|
199
|
+
let loaded = false;
|
|
200
|
+
for (const extPath of csvPaths) {
|
|
201
|
+
try {
|
|
202
|
+
this.db.loadExtension(extPath);
|
|
203
|
+
log.info(`Loaded CSV extension from ${extPath}`, {
|
|
204
|
+
code: "SQLITE_EXTENSION",
|
|
205
|
+
});
|
|
206
|
+
loaded = true;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Try next path
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (!loaded) {
|
|
214
|
+
log.warning("CSV extension not available. Set CSV_EXTENSION_PATH env var.", { code: "SQLITE_EXTENSION" });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Disconnect from the database
|
|
220
|
+
*/
|
|
221
|
+
disconnect() {
|
|
222
|
+
if (this.db) {
|
|
223
|
+
this.db.close();
|
|
224
|
+
this.db = null;
|
|
225
|
+
this.connected = false;
|
|
226
|
+
log.info("Disconnected from native SQLite database", {
|
|
227
|
+
code: "SQLITE_DISCONNECT",
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
return Promise.resolve();
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get health status
|
|
234
|
+
*/
|
|
235
|
+
getHealth() {
|
|
236
|
+
if (!this.db || !this.connected) {
|
|
237
|
+
return Promise.resolve({
|
|
238
|
+
connected: false,
|
|
239
|
+
latencyMs: 0,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const start = Date.now();
|
|
243
|
+
try {
|
|
244
|
+
this.db.prepare("SELECT 1").get();
|
|
245
|
+
return Promise.resolve({
|
|
246
|
+
connected: true,
|
|
247
|
+
latencyMs: Date.now() - start,
|
|
248
|
+
details: {
|
|
249
|
+
backend: "better-sqlite3",
|
|
250
|
+
fts5: this.hasFts5(),
|
|
251
|
+
spatialite: isSpatialiteLoaded(this),
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return Promise.resolve({
|
|
257
|
+
connected: false,
|
|
258
|
+
latencyMs: Date.now() - start,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Check if FTS5 is available
|
|
264
|
+
*/
|
|
265
|
+
hasFts5() {
|
|
266
|
+
if (!this.db)
|
|
267
|
+
return false;
|
|
268
|
+
try {
|
|
269
|
+
this.db.exec("CREATE VIRTUAL TABLE IF NOT EXISTS _fts5_test USING fts5(content)");
|
|
270
|
+
this.db.exec("DROP TABLE IF EXISTS _fts5_test");
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Normalize parameters for SQLite binding
|
|
279
|
+
* Converts booleans to integers since SQLite doesn't have native boolean type
|
|
280
|
+
*/
|
|
281
|
+
normalizeParams(params) {
|
|
282
|
+
if (!params)
|
|
283
|
+
return undefined;
|
|
284
|
+
return params.map((p) => {
|
|
285
|
+
if (typeof p === "boolean")
|
|
286
|
+
return p ? 1 : 0;
|
|
287
|
+
return p;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Execute a read query
|
|
292
|
+
*/
|
|
293
|
+
executeReadQuery(sql, params) {
|
|
294
|
+
this.ensureConnected();
|
|
295
|
+
const start = Date.now();
|
|
296
|
+
try {
|
|
297
|
+
const db = this.ensureDb();
|
|
298
|
+
const stmt = db.prepare(sql);
|
|
299
|
+
const normalizedParams = this.normalizeParams(params);
|
|
300
|
+
const rows = normalizedParams
|
|
301
|
+
? stmt.all(...normalizedParams)
|
|
302
|
+
: stmt.all();
|
|
303
|
+
return Promise.resolve({
|
|
304
|
+
rows: rows,
|
|
305
|
+
columns: stmt
|
|
306
|
+
.columns()
|
|
307
|
+
.map((c) => ({ name: c.name, type: c.type ?? "unknown" })),
|
|
308
|
+
executionTimeMs: Date.now() - start,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
313
|
+
throw new Error(`Query failed: ${message}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Execute a write query
|
|
318
|
+
*/
|
|
319
|
+
executeWriteQuery(sql, params) {
|
|
320
|
+
this.ensureConnected();
|
|
321
|
+
const start = Date.now();
|
|
322
|
+
try {
|
|
323
|
+
const db = this.ensureDb();
|
|
324
|
+
const stmt = db.prepare(sql);
|
|
325
|
+
const normalizedParams = this.normalizeParams(params);
|
|
326
|
+
const info = normalizedParams
|
|
327
|
+
? stmt.run(...normalizedParams)
|
|
328
|
+
: stmt.run();
|
|
329
|
+
return Promise.resolve({
|
|
330
|
+
rows: [],
|
|
331
|
+
rowsAffected: info.changes,
|
|
332
|
+
executionTimeMs: Date.now() - start,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
337
|
+
throw new Error(`Write query failed: ${message}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Execute any query
|
|
342
|
+
*/
|
|
343
|
+
executeQuery(sql, params) {
|
|
344
|
+
const trimmed = sql.trim().toUpperCase();
|
|
345
|
+
if (trimmed.startsWith("SELECT") ||
|
|
346
|
+
trimmed.startsWith("PRAGMA") ||
|
|
347
|
+
trimmed.startsWith("EXPLAIN")) {
|
|
348
|
+
return this.executeReadQuery(sql, params);
|
|
349
|
+
}
|
|
350
|
+
return this.executeWriteQuery(sql, params);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Get schema information
|
|
354
|
+
*/
|
|
355
|
+
async getSchema() {
|
|
356
|
+
this.ensureConnected();
|
|
357
|
+
const tables = await this.listTables();
|
|
358
|
+
return {
|
|
359
|
+
tables,
|
|
360
|
+
indexes: [],
|
|
361
|
+
views: [],
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* List all tables
|
|
366
|
+
*/
|
|
367
|
+
listTables() {
|
|
368
|
+
this.ensureConnected();
|
|
369
|
+
const db = this.ensureDb();
|
|
370
|
+
const result = db
|
|
371
|
+
.prepare(`
|
|
372
|
+
SELECT name, type, sql
|
|
373
|
+
FROM sqlite_master
|
|
374
|
+
WHERE type IN ('table', 'view')
|
|
375
|
+
AND name NOT LIKE 'sqlite_%'
|
|
376
|
+
ORDER BY name
|
|
377
|
+
`)
|
|
378
|
+
.all();
|
|
379
|
+
// Build tables with column info from PRAGMA table_info()
|
|
380
|
+
// Filter out FTS5 virtual tables and shadow tables
|
|
381
|
+
const tables = result
|
|
382
|
+
.filter((row) => {
|
|
383
|
+
// Skip FTS5 virtual tables (end with "_fts") and shadow tables (contain "_fts_")
|
|
384
|
+
if (row.name.endsWith("_fts") || row.name.includes("_fts_")) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
})
|
|
389
|
+
.map((row) => {
|
|
390
|
+
const columns = db
|
|
391
|
+
.prepare(`PRAGMA table_info("${row.name}")`)
|
|
392
|
+
.all();
|
|
393
|
+
return {
|
|
394
|
+
name: row.name,
|
|
395
|
+
type: row.type,
|
|
396
|
+
columns: columns.map((c) => ({
|
|
397
|
+
name: c.name,
|
|
398
|
+
type: c.type,
|
|
399
|
+
nullable: c.notnull === 0,
|
|
400
|
+
primaryKey: c.pk > 0,
|
|
401
|
+
})),
|
|
402
|
+
};
|
|
403
|
+
});
|
|
404
|
+
return Promise.resolve(tables);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Describe a table
|
|
408
|
+
*/
|
|
409
|
+
describeTable(tableName) {
|
|
410
|
+
this.ensureConnected();
|
|
411
|
+
const db = this.ensureDb();
|
|
412
|
+
const columns = db.prepare(`PRAGMA table_info("${tableName}")`).all();
|
|
413
|
+
// Check if table exists (PRAGMA returns empty for non-existent tables)
|
|
414
|
+
if (columns.length === 0) {
|
|
415
|
+
throw new Error(`Table '${tableName}' does not exist`);
|
|
416
|
+
}
|
|
417
|
+
return Promise.resolve({
|
|
418
|
+
name: tableName,
|
|
419
|
+
type: "table",
|
|
420
|
+
columns: columns.map((c) => ({
|
|
421
|
+
name: c.name,
|
|
422
|
+
type: c.type,
|
|
423
|
+
nullable: c.notnull === 0 ? true : false,
|
|
424
|
+
primaryKey: c.pk > 0 ? true : false,
|
|
425
|
+
})),
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* List schemas (SQLite only has one)
|
|
430
|
+
*/
|
|
431
|
+
listSchemas() {
|
|
432
|
+
return Promise.resolve(["main"]);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Get all indexes in the database
|
|
436
|
+
* Required by sqlite_indexes resource
|
|
437
|
+
*/
|
|
438
|
+
getAllIndexes() {
|
|
439
|
+
this.ensureConnected();
|
|
440
|
+
const db = this.ensureDb();
|
|
441
|
+
// Get all user-created indexes from sqlite_master
|
|
442
|
+
const indexes = db
|
|
443
|
+
.prepare(`SELECT name, tbl_name, sql
|
|
444
|
+
FROM sqlite_master
|
|
445
|
+
WHERE type = 'index' AND sql IS NOT NULL
|
|
446
|
+
ORDER BY tbl_name, name`)
|
|
447
|
+
.all();
|
|
448
|
+
// Build index info with column details
|
|
449
|
+
return indexes.map((idx) => {
|
|
450
|
+
// Get columns for this index
|
|
451
|
+
const indexInfo = db
|
|
452
|
+
.prepare(`PRAGMA index_info("${idx.name}")`)
|
|
453
|
+
.all();
|
|
454
|
+
return {
|
|
455
|
+
name: idx.name,
|
|
456
|
+
tableName: idx.tbl_name,
|
|
457
|
+
columns: indexInfo.map((col) => col.name),
|
|
458
|
+
unique: idx.sql?.toUpperCase().includes("UNIQUE") ?? false,
|
|
459
|
+
};
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Get capabilities
|
|
464
|
+
*/
|
|
465
|
+
getCapabilities() {
|
|
466
|
+
return {
|
|
467
|
+
json: true,
|
|
468
|
+
fullTextSearch: true,
|
|
469
|
+
vector: true,
|
|
470
|
+
geospatial: true,
|
|
471
|
+
transactions: true,
|
|
472
|
+
preparedStatements: true,
|
|
473
|
+
connectionPooling: false, // better-sqlite3 is single-connection
|
|
474
|
+
windowFunctions: true,
|
|
475
|
+
spatialite: true,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Get supported tool groups
|
|
480
|
+
*/
|
|
481
|
+
getSupportedToolGroups() {
|
|
482
|
+
return ["core", "json", "text", "stats", "vector", "admin", "geo"];
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Get all tool definitions
|
|
486
|
+
*/
|
|
487
|
+
getToolDefinitions() {
|
|
488
|
+
// Type assertion needed due to interface compatibility
|
|
489
|
+
const self = this;
|
|
490
|
+
return [
|
|
491
|
+
...getCoreTools(self),
|
|
492
|
+
...getJsonOperationTools(self),
|
|
493
|
+
...getJsonHelperTools(self),
|
|
494
|
+
...getTextTools(self),
|
|
495
|
+
...getFtsTools(self),
|
|
496
|
+
...getStatsTools(self),
|
|
497
|
+
...getVirtualTools(self),
|
|
498
|
+
...getVectorTools(self),
|
|
499
|
+
...getGeoTools(self),
|
|
500
|
+
...getAdminTools(self),
|
|
501
|
+
// Native-only tools
|
|
502
|
+
...getTransactionTools(this),
|
|
503
|
+
...getWindowTools(this),
|
|
504
|
+
...getSpatialiteTools(this),
|
|
505
|
+
];
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Get resource definitions
|
|
509
|
+
*/
|
|
510
|
+
getResourceDefinitions() {
|
|
511
|
+
return getResourceDefinitions(this);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Get prompt definitions
|
|
515
|
+
*/
|
|
516
|
+
getPromptDefinitions() {
|
|
517
|
+
return getPromptDefinitions(this);
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Register a tool with the MCP server
|
|
521
|
+
* Uses modern registerTool() API for MCP 2025-11-25 compliance
|
|
522
|
+
*/
|
|
523
|
+
registerTool(server, tool) {
|
|
524
|
+
// Build tool options for registerTool()
|
|
525
|
+
const toolOptions = {
|
|
526
|
+
description: tool.description,
|
|
527
|
+
};
|
|
528
|
+
// Pass full inputSchema (not just .shape) for proper validation
|
|
529
|
+
if (tool.inputSchema !== undefined) {
|
|
530
|
+
toolOptions["inputSchema"] = tool.inputSchema;
|
|
531
|
+
}
|
|
532
|
+
// MCP 2025-11-25: Pass outputSchema for structured responses
|
|
533
|
+
if (tool.outputSchema !== undefined) {
|
|
534
|
+
toolOptions["outputSchema"] = tool.outputSchema;
|
|
535
|
+
}
|
|
536
|
+
// MCP 2025-11-25: Pass annotations for behavioral hints
|
|
537
|
+
if (tool.annotations) {
|
|
538
|
+
toolOptions["annotations"] = tool.annotations;
|
|
539
|
+
}
|
|
540
|
+
// Track whether tool has outputSchema for response handling
|
|
541
|
+
const hasOutputSchema = Boolean(tool.outputSchema);
|
|
542
|
+
server.registerTool(tool.name, toolOptions, async (args, extra) => {
|
|
543
|
+
try {
|
|
544
|
+
// Extract progressToken from extra._meta (SDK passes RequestHandlerExtra)
|
|
545
|
+
const extraMeta = extra;
|
|
546
|
+
const progressToken = extraMeta?._meta?.progressToken;
|
|
547
|
+
// Create context with progress support
|
|
548
|
+
const context = this.createContext(undefined, server.server, progressToken);
|
|
549
|
+
const result = await tool.handler(args, context);
|
|
550
|
+
// MCP 2025-11-25: Return structuredContent if outputSchema present
|
|
551
|
+
if (hasOutputSchema) {
|
|
552
|
+
return {
|
|
553
|
+
content: [
|
|
554
|
+
{
|
|
555
|
+
type: "text",
|
|
556
|
+
text: JSON.stringify(result, null, 2),
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
structuredContent: result,
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
// Standard text content response
|
|
563
|
+
return {
|
|
564
|
+
content: [
|
|
565
|
+
{
|
|
566
|
+
type: "text",
|
|
567
|
+
text: typeof result === "string"
|
|
568
|
+
? result
|
|
569
|
+
: JSON.stringify(result, null, 2),
|
|
570
|
+
},
|
|
571
|
+
],
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
return {
|
|
576
|
+
content: [
|
|
577
|
+
{
|
|
578
|
+
type: "text",
|
|
579
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
isError: true,
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Register a resource with the MCP server
|
|
589
|
+
* Handles both static resources and URI templates
|
|
590
|
+
*/
|
|
591
|
+
registerResource(server, resource) {
|
|
592
|
+
// Check if URI contains template placeholders like {tableName}
|
|
593
|
+
const isTemplate = /\{[^}]+\}/.test(resource.uri);
|
|
594
|
+
if (isTemplate) {
|
|
595
|
+
// Create ResourceTemplate for parameterized URIs
|
|
596
|
+
// list: undefined signals no enumeration callback for this template
|
|
597
|
+
const template = new ResourceTemplate(resource.uri, { list: undefined });
|
|
598
|
+
server.registerResource(resource.name, template, {
|
|
599
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
600
|
+
description: resource.description,
|
|
601
|
+
},
|
|
602
|
+
// Callback receives URL and extracted template variables
|
|
603
|
+
async (resourceUri, _variables) => {
|
|
604
|
+
// Pass full URI to handler so it can extract variables
|
|
605
|
+
const content = await resource.handler(resourceUri.toString(), {
|
|
606
|
+
timestamp: new Date(),
|
|
607
|
+
requestId: crypto.randomUUID(),
|
|
608
|
+
});
|
|
609
|
+
return {
|
|
610
|
+
contents: [
|
|
611
|
+
{
|
|
612
|
+
uri: resourceUri.toString(),
|
|
613
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
614
|
+
text: typeof content === "string"
|
|
615
|
+
? content
|
|
616
|
+
: JSON.stringify(content, null, 2),
|
|
617
|
+
},
|
|
618
|
+
],
|
|
619
|
+
};
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
// Static resource registration
|
|
624
|
+
server.registerResource(resource.name, resource.uri, {
|
|
625
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
626
|
+
description: resource.description,
|
|
627
|
+
}, async (resourceUri) => {
|
|
628
|
+
const content = await resource.handler(resourceUri.toString(), {
|
|
629
|
+
timestamp: new Date(),
|
|
630
|
+
requestId: crypto.randomUUID(),
|
|
631
|
+
});
|
|
632
|
+
return {
|
|
633
|
+
contents: [
|
|
634
|
+
{
|
|
635
|
+
uri: resourceUri.toString(),
|
|
636
|
+
mimeType: resource.mimeType ?? "application/json",
|
|
637
|
+
text: typeof content === "string"
|
|
638
|
+
? content
|
|
639
|
+
: JSON.stringify(content, null, 2),
|
|
640
|
+
},
|
|
641
|
+
],
|
|
642
|
+
};
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Register a prompt with the MCP server
|
|
648
|
+
*/
|
|
649
|
+
registerPrompt(server, prompt) {
|
|
650
|
+
server.registerPrompt(prompt.name, { description: prompt.description }, async (args) => {
|
|
651
|
+
const result = await prompt.handler(args, {
|
|
652
|
+
timestamp: new Date(),
|
|
653
|
+
requestId: crypto.randomUUID(),
|
|
654
|
+
});
|
|
655
|
+
// Type-safe message construction
|
|
656
|
+
const messages = Array.isArray(result)
|
|
657
|
+
? result
|
|
658
|
+
: [
|
|
659
|
+
{
|
|
660
|
+
role: "assistant",
|
|
661
|
+
content: {
|
|
662
|
+
type: "text",
|
|
663
|
+
text: typeof result === "string"
|
|
664
|
+
? result
|
|
665
|
+
: JSON.stringify(result),
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
];
|
|
669
|
+
return { messages };
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Ensure database is connected
|
|
674
|
+
*/
|
|
675
|
+
ensureConnected() {
|
|
676
|
+
if (!this.db || !this.connected) {
|
|
677
|
+
throw new Error("Not connected to database");
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Ensure database is connected and return database instance
|
|
682
|
+
*/
|
|
683
|
+
ensureDb() {
|
|
684
|
+
if (!this.db || !this.connected) {
|
|
685
|
+
throw new Error("Not connected to database");
|
|
686
|
+
}
|
|
687
|
+
return this.db;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Get the raw database instance (for tools)
|
|
691
|
+
*/
|
|
692
|
+
getDatabase() {
|
|
693
|
+
return this.ensureDb();
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Execute raw SQL and return results (for tools)
|
|
697
|
+
*/
|
|
698
|
+
rawQuery(sql, params) {
|
|
699
|
+
return this.executeQuery(sql, params);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Begin a transaction
|
|
703
|
+
*/
|
|
704
|
+
beginTransaction() {
|
|
705
|
+
const db = this.ensureDb();
|
|
706
|
+
db.exec("BEGIN TRANSACTION");
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Commit a transaction
|
|
710
|
+
*/
|
|
711
|
+
commitTransaction() {
|
|
712
|
+
const db = this.ensureDb();
|
|
713
|
+
db.exec("COMMIT");
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Rollback a transaction
|
|
717
|
+
*/
|
|
718
|
+
rollbackTransaction() {
|
|
719
|
+
const db = this.ensureDb();
|
|
720
|
+
db.exec("ROLLBACK");
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Create a savepoint
|
|
724
|
+
*/
|
|
725
|
+
savepoint(name) {
|
|
726
|
+
const db = this.ensureDb();
|
|
727
|
+
db.exec(`SAVEPOINT "${name}"`);
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Release a savepoint
|
|
731
|
+
*/
|
|
732
|
+
releaseSavepoint(name) {
|
|
733
|
+
const db = this.ensureDb();
|
|
734
|
+
db.exec(`RELEASE SAVEPOINT "${name}"`);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Rollback to a savepoint
|
|
738
|
+
*/
|
|
739
|
+
rollbackToSavepoint(name) {
|
|
740
|
+
const db = this.ensureDb();
|
|
741
|
+
db.exec(`ROLLBACK TO SAVEPOINT "${name}"`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
// Factory function
|
|
745
|
+
export function createNativeSqliteAdapter() {
|
|
746
|
+
return new NativeSqliteAdapter();
|
|
747
|
+
}
|
|
748
|
+
//# sourceMappingURL=NativeSqliteAdapter.js.map
|