admindb 2.1.0 → 2.1.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.
Files changed (178) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.ts +1 -69
  3. package/dist/app.js +1 -257
  4. package/dist/auth/config.d.ts +1 -19
  5. package/dist/auth/config.js +1 -147
  6. package/dist/auth/crypto.d.ts +1 -27
  7. package/dist/auth/crypto.js +1 -133
  8. package/dist/auth/index.d.ts +1 -5
  9. package/dist/auth/index.js +1 -22
  10. package/dist/auth/middleware.d.ts +1 -14
  11. package/dist/auth/middleware.js +1 -100
  12. package/dist/auth/routes.d.ts +1 -7
  13. package/dist/auth/routes.js +1 -78
  14. package/dist/auth/types.d.ts +1 -35
  15. package/dist/auth/types.js +1 -11
  16. package/dist/cli/args.d.ts +1 -45
  17. package/dist/cli/args.js +1 -328
  18. package/dist/cli/config.d.ts +1 -56
  19. package/dist/cli/config.js +1 -133
  20. package/dist/cli/index.d.ts +1 -4
  21. package/dist/cli/index.js +1 -21
  22. package/dist/cli/runner.d.ts +1 -1
  23. package/dist/cli/runner.js +1 -222
  24. package/dist/cli.d.ts +1 -2
  25. package/dist/cli.js +1 -5
  26. package/dist/data/datasets.d.ts +1 -17
  27. package/dist/data/datasets.js +1 -133
  28. package/dist/data/detector.d.ts +1 -30
  29. package/dist/data/detector.js +1 -472
  30. package/dist/data/engine.d.ts +1 -10
  31. package/dist/data/engine.js +1 -211
  32. package/dist/data/index.d.ts +1 -5
  33. package/dist/data/index.js +1 -22
  34. package/dist/data/strategies.d.ts +1 -30
  35. package/dist/data/strategies.js +1 -343
  36. package/dist/data/types.d.ts +1 -73
  37. package/dist/data/types.js +1 -8
  38. package/dist/db/database.d.ts +1 -119
  39. package/dist/db/database.js +1 -471
  40. package/dist/db/export.d.ts +1 -12
  41. package/dist/db/export.js +1 -42
  42. package/dist/db/filters.d.ts +1 -22
  43. package/dist/db/filters.js +1 -158
  44. package/dist/db/index.d.ts +1 -8
  45. package/dist/db/index.js +1 -25
  46. package/dist/db/introspection.d.ts +1 -6
  47. package/dist/db/introspection.js +1 -172
  48. package/dist/db/manager.d.ts +1 -81
  49. package/dist/db/manager.js +1 -397
  50. package/dist/db/migrations.d.ts +1 -5
  51. package/dist/db/migrations.js +1 -110
  52. package/dist/db/postgres.d.ts +1 -85
  53. package/dist/db/postgres.js +1 -745
  54. package/dist/db/types.d.ts +1 -206
  55. package/dist/db/types.js +1 -7
  56. package/dist/index.d.ts +1 -23
  57. package/dist/index.js +1 -66
  58. package/dist/public/js/api.js +1 -47
  59. package/dist/public/js/app.js +1 -262
  60. package/dist/public/js/browse.js +1 -1371
  61. package/dist/public/js/databases.js +1 -235
  62. package/dist/public/js/designer.js +1 -258
  63. package/dist/public/js/forms.js +1 -826
  64. package/dist/public/js/icons.js +1 -51
  65. package/dist/public/js/inspector.js +1 -638
  66. package/dist/public/js/query.js +1 -322
  67. package/dist/public/js/schema.js +1 -447
  68. package/dist/public/js/seed.js +1 -1090
  69. package/dist/routes/api/helpers.d.ts +1 -42
  70. package/dist/routes/api/helpers.js +1 -133
  71. package/dist/routes/api/import-export.d.ts +1 -3
  72. package/dist/routes/api/import-export.js +1 -85
  73. package/dist/routes/api/index.d.ts +1 -4
  74. package/dist/routes/api/index.js +1 -37
  75. package/dist/routes/api/query.d.ts +1 -3
  76. package/dist/routes/api/query.js +1 -76
  77. package/dist/routes/api/rows.d.ts +1 -3
  78. package/dist/routes/api/rows.js +1 -373
  79. package/dist/routes/api/seed.d.ts +1 -3
  80. package/dist/routes/api/seed.js +1 -82
  81. package/dist/routes/api/tables.d.ts +1 -3
  82. package/dist/routes/api/tables.js +1 -160
  83. package/dist/routes/databases.d.ts +1 -26
  84. package/dist/routes/databases.js +1 -230
  85. package/dist/routes/index.d.ts +1 -3
  86. package/dist/routes/index.js +1 -20
  87. package/dist/routes/pages.d.ts +1 -9
  88. package/dist/routes/pages.js +1 -390
  89. package/dist/serverless.d.ts +1 -40
  90. package/dist/serverless.js +1 -210
  91. package/dist/sql/classifier.d.ts +1 -19
  92. package/dist/sql/classifier.js +1 -37
  93. package/dist/sql/generator.d.ts +1 -81
  94. package/dist/sql/generator.js +1 -348
  95. package/dist/sql/index.d.ts +1 -2
  96. package/dist/sql/index.js +1 -19
  97. package/dist/types/api.d.ts +1 -412
  98. package/dist/types/api.js +1 -9
  99. package/dist/utils/colors.d.ts +1 -40
  100. package/dist/utils/colors.js +1 -64
  101. package/dist/utils/common.d.ts +1 -50
  102. package/dist/utils/common.js +1 -229
  103. package/dist/utils/csv.d.ts +1 -15
  104. package/dist/utils/csv.js +1 -80
  105. package/dist/utils/datatype.d.ts +1 -49
  106. package/dist/utils/datatype.js +1 -222
  107. package/dist/utils/icons.d.ts +1 -11
  108. package/dist/utils/icons.js +1 -72
  109. package/dist/utils/index.d.ts +1 -4
  110. package/dist/utils/index.js +1 -21
  111. package/dist/utils/logger.d.ts +1 -10
  112. package/dist/utils/logger.js +1 -40
  113. package/dist/views/layouts/main.hbs +0 -4
  114. package/dist/views/pages/databases.hbs +0 -18
  115. package/dist/views/pages/designer.hbs +0 -10
  116. package/dist/views/pages/error.hbs +0 -2
  117. package/dist/views/pages/form.hbs +0 -5
  118. package/dist/views/pages/home.hbs +0 -8
  119. package/dist/views/pages/login.hbs +0 -13
  120. package/dist/views/pages/query.hbs +0 -9
  121. package/dist/views/pages/schema.hbs +0 -20
  122. package/dist/views/pages/seed.hbs +0 -31
  123. package/dist/views/pages/table.hbs +0 -14
  124. package/dist/views/partials/icon.hbs +0 -1
  125. package/dist/views/partials/navbar.hbs +0 -6
  126. package/dist/views/partials/sidebar.hbs +0 -8
  127. package/package.json +3 -2
  128. package/dist/app.js.map +0 -1
  129. package/dist/auth/config.js.map +0 -1
  130. package/dist/auth/crypto.js.map +0 -1
  131. package/dist/auth/index.js.map +0 -1
  132. package/dist/auth/middleware.js.map +0 -1
  133. package/dist/auth/routes.js.map +0 -1
  134. package/dist/auth/types.js.map +0 -1
  135. package/dist/cli/args.js.map +0 -1
  136. package/dist/cli/config.js.map +0 -1
  137. package/dist/cli/index.js.map +0 -1
  138. package/dist/cli/runner.js.map +0 -1
  139. package/dist/cli.js.map +0 -1
  140. package/dist/data/datasets.js.map +0 -1
  141. package/dist/data/detector.js.map +0 -1
  142. package/dist/data/engine.js.map +0 -1
  143. package/dist/data/index.js.map +0 -1
  144. package/dist/data/strategies.js.map +0 -1
  145. package/dist/data/types.js.map +0 -1
  146. package/dist/db/database.js.map +0 -1
  147. package/dist/db/export.js.map +0 -1
  148. package/dist/db/filters.js.map +0 -1
  149. package/dist/db/index.js.map +0 -1
  150. package/dist/db/introspection.js.map +0 -1
  151. package/dist/db/manager.js.map +0 -1
  152. package/dist/db/migrations.js.map +0 -1
  153. package/dist/db/postgres.js.map +0 -1
  154. package/dist/db/types.js.map +0 -1
  155. package/dist/index.js.map +0 -1
  156. package/dist/public/css/input.css +0 -302
  157. package/dist/routes/api/helpers.js.map +0 -1
  158. package/dist/routes/api/import-export.js.map +0 -1
  159. package/dist/routes/api/index.js.map +0 -1
  160. package/dist/routes/api/query.js.map +0 -1
  161. package/dist/routes/api/rows.js.map +0 -1
  162. package/dist/routes/api/seed.js.map +0 -1
  163. package/dist/routes/api/tables.js.map +0 -1
  164. package/dist/routes/databases.js.map +0 -1
  165. package/dist/routes/index.js.map +0 -1
  166. package/dist/routes/pages.js.map +0 -1
  167. package/dist/serverless.js.map +0 -1
  168. package/dist/sql/classifier.js.map +0 -1
  169. package/dist/sql/generator.js.map +0 -1
  170. package/dist/sql/index.js.map +0 -1
  171. package/dist/types/api.js.map +0 -1
  172. package/dist/utils/colors.js.map +0 -1
  173. package/dist/utils/common.js.map +0 -1
  174. package/dist/utils/csv.js.map +0 -1
  175. package/dist/utils/datatype.js.map +0 -1
  176. package/dist/utils/icons.js.map +0 -1
  177. package/dist/utils/index.js.map +0 -1
  178. package/dist/utils/logger.js.map +0 -1
@@ -1,397 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DbManager = void 0;
7
- const node_fs_1 = require("node:fs");
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const database_1 = require("./database");
10
- const postgres_1 = require("./postgres");
11
- const logger_1 = require("../utils/logger");
12
- const common_1 = require("../utils/common");
13
- const DB_EXTENSIONS = ['.db', '.sqlite', '.sqlite3'];
14
- /**
15
- * Manages multiple SQLite database files and PostgreSQL database connections.
16
- *
17
- * Databases come from three sources:
18
- * - a `connections` map — named PostgreSQL or SQLite connection strings (e.g. from JSON config),
19
- * - a `dir` — every SQLite file with a known extension is scanned in,
20
- * - an explicit `files[]` array — specific file locations or connection strings.
21
- */
22
- class DbManager {
23
- logger;
24
- dir;
25
- createDir;
26
- readonlyMode;
27
- files = []; // targets (paths or URIs), registry order
28
- idByPath = new Map(); // target -> id
29
- pathById = new Map(); // id -> target
30
- nameById = new Map(); // id -> display name
31
- readonlyById = new Map(); // id -> readonly override
32
- openDbs = new Map(); // id -> db
33
- constructor(options, logger) {
34
- const opts = typeof options === 'string' ? { dir: options } : (options ?? {});
35
- this.logger = logger ?? (0, logger_1.createLogger)('info', 'admindb');
36
- this.dir = opts.dir ? node_path_1.default.resolve(opts.dir) : undefined;
37
- this.createDir = this.dir ?? process.cwd();
38
- this.readonlyMode = !!opts.readonly;
39
- if (this.dir)
40
- (0, node_fs_1.mkdirSync)(this.dir, { recursive: true });
41
- if (opts.connections) {
42
- this.registerConnections(opts.connections);
43
- }
44
- this.registerDirFiles();
45
- this.registerExplicitFiles(opts.files ?? []);
46
- }
47
- get directory() {
48
- return this.dir ?? this.createDir;
49
- }
50
- /** True when this manager opens every database read-only. */
51
- get isReadOnly() {
52
- return this.readonlyMode;
53
- }
54
- isDbFile(name) {
55
- const lower = String(name ?? '').toLowerCase();
56
- return DB_EXTENSIONS.some((ext) => lower.endsWith(ext));
57
- }
58
- registerConnections(conns) {
59
- for (const [name, target] of Object.entries(conns ?? {})) {
60
- if (!name || !target)
61
- continue;
62
- const cleanTarget = String(target).trim();
63
- if (!cleanTarget)
64
- continue;
65
- this.addNamedTarget(name.trim(), cleanTarget);
66
- }
67
- }
68
- registerDirFiles() {
69
- if (!this.dir)
70
- return;
71
- let names = [];
72
- try {
73
- names = (0, node_fs_1.readdirSync)(this.dir)
74
- .filter((n) => this.isDbFile(n))
75
- .sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
76
- }
77
- catch (err) {
78
- this.logger.warn(`Failed to list database directory ${this.dir}: ${(0, common_1.errorMessage)(err)}`);
79
- }
80
- for (const name of names)
81
- this.addFile(node_path_1.default.join(this.dir, name));
82
- }
83
- registerExplicitFiles(files) {
84
- for (const f of files ?? []) {
85
- const raw = String(f ?? '').trim();
86
- if (!raw)
87
- continue;
88
- const isPg = raw.startsWith('postgres://') || raw.startsWith('postgresql://');
89
- if (isPg) {
90
- let name = 'postgres';
91
- try {
92
- const u = new URL(raw);
93
- name = u.pathname.replace(/^\//, '') || 'postgres';
94
- }
95
- catch {
96
- name = 'postgres';
97
- }
98
- this.addNamedTarget(name, raw);
99
- continue;
100
- }
101
- const abs = node_path_1.default.resolve(raw);
102
- if (!(0, node_fs_1.existsSync)(abs)) {
103
- this.logger.warn(`Skipping missing database file: ${f}`);
104
- continue;
105
- }
106
- this.addFile(abs);
107
- }
108
- }
109
- addNamedTarget(name, target) {
110
- let id = name;
111
- let n = 2;
112
- while (this.pathById.has(id)) {
113
- id = `${name}__${n}`;
114
- n += 1;
115
- }
116
- this.files.push(target);
117
- this.idByPath.set(target, id);
118
- this.pathById.set(id, target);
119
- this.nameById.set(id, name);
120
- }
121
- addFile(abs) {
122
- if (this.idByPath.has(abs))
123
- return;
124
- const base = node_path_1.default.basename(abs);
125
- let id = base;
126
- let n = 2;
127
- while (this.pathById.has(id)) {
128
- const ext = node_path_1.default.extname(base);
129
- const stem = node_path_1.default.basename(base, ext);
130
- id = `${stem}__${n}${ext}`;
131
- n += 1;
132
- }
133
- this.files.push(abs);
134
- this.idByPath.set(abs, id);
135
- this.pathById.set(id, abs);
136
- this.nameById.set(id, base);
137
- }
138
- /** List all managed databases (metadata only — does not open them). */
139
- list() {
140
- const entries = [];
141
- const seen = new Set();
142
- for (const [id, target] of this.pathById.entries()) {
143
- if (seen.has(id))
144
- continue;
145
- seen.add(id);
146
- const isPg = target.startsWith('postgres://') || target.startsWith('postgresql://');
147
- if (isPg) {
148
- let sanitized = target;
149
- try {
150
- const u = new URL(target);
151
- if (u.password)
152
- u.password = '****';
153
- sanitized = u.toString();
154
- }
155
- catch {
156
- sanitized = target.replace(/:([^:@]+)@/, ':****@');
157
- }
158
- entries.push({
159
- id,
160
- name: this.nameById.get(id) ?? id,
161
- path: sanitized,
162
- dialect: 'postgres',
163
- size: 0,
164
- modified: 'Connected',
165
- readonly: this.isDbReadOnly(id),
166
- });
167
- }
168
- else {
169
- let size = 0;
170
- let modified = '';
171
- try {
172
- const st = (0, node_fs_1.statSync)(target);
173
- size = st.size;
174
- modified = st.mtime.toISOString();
175
- }
176
- catch {
177
- /* ignore */
178
- }
179
- entries.push({
180
- id,
181
- name: this.nameById.get(id) ?? node_path_1.default.basename(target),
182
- path: target,
183
- dialect: 'sqlite',
184
- size,
185
- modified,
186
- readonly: this.isDbReadOnly(id),
187
- });
188
- }
189
- }
190
- return entries;
191
- }
192
- has(id) {
193
- return this.pathById.has(id);
194
- }
195
- /** True if global manager is in readonly mode or this database is explicitly marked read-only. */
196
- isDbReadOnly(id) {
197
- return this.readonlyMode || (this.readonlyById.get(id) ?? false);
198
- }
199
- /** Set or toggle read-only mode for a specific database id. */
200
- setReadonly(id, readonly) {
201
- if (this.readonlyMode && !readonly) {
202
- throw new Error('Manager is in global read-only mode — databases cannot be made writable.');
203
- }
204
- const current = this.readonlyById.get(id);
205
- if (current === readonly)
206
- return;
207
- this.readonlyById.set(id, readonly);
208
- // Close existing connection instance so it is re-opened with new readonly mode on next use
209
- const db = this.openDbs.get(id);
210
- if (db) {
211
- try {
212
- db.close();
213
- }
214
- catch {
215
- /* ignore */
216
- }
217
- this.openDbs.delete(id);
218
- }
219
- }
220
- /** Open (and cache) a database by id; creates the file if it is new SQLite database. */
221
- open(id, readonlyOverride) {
222
- const target = this.pathById.get(id);
223
- if (!target)
224
- throw new Error(`Database "${id}" is not registered.`);
225
- const isRo = this.readonlyMode || (readonlyOverride !== undefined ? readonlyOverride : (this.readonlyById.get(id) ?? false));
226
- let db = this.openDbs.get(id);
227
- if (db && db.isReadOnly !== isRo) {
228
- try {
229
- db.close();
230
- }
231
- catch {
232
- /* ignore */
233
- }
234
- this.openDbs.delete(id);
235
- db = undefined;
236
- }
237
- if (!db) {
238
- const isPg = target.startsWith('postgres://') || target.startsWith('postgresql://');
239
- if (isPg) {
240
- db = new postgres_1.PostgresDatabase(target, this.logger.child(`db:${id}`), { readonly: isRo });
241
- }
242
- else {
243
- db = new database_1.SqliteDatabase(target, this.logger.child(`db:${id}`), { readonly: isRo });
244
- }
245
- this.openDbs.set(id, db);
246
- }
247
- return db;
248
- }
249
- /**
250
- * Register and open an existing database file by path, returning its id.
251
- * Used by the "Open an existing database" file browser. Validates that the
252
- * file is a readable SQLite database before keeping it registered.
253
- */
254
- openFile(absPath, readonly) {
255
- const abs = node_path_1.default.resolve(String(absPath ?? '').trim());
256
- if (!abs)
257
- throw new Error('Database path is required.');
258
- if (!(0, node_fs_1.existsSync)(abs) || !(0, node_fs_1.statSync)(abs).isFile()) {
259
- throw new Error(`Not a file: ${abs}`);
260
- }
261
- const existing = this.idByPath.get(abs);
262
- if (existing) {
263
- if (readonly !== undefined)
264
- this.setReadonly(existing, readonly);
265
- return existing;
266
- }
267
- this.addFile(abs);
268
- const id = this.idByPath.get(abs);
269
- if (!id)
270
- throw new Error('Failed to register database file.');
271
- if (readonly !== undefined)
272
- this.readonlyById.set(id, readonly);
273
- try {
274
- this.open(id); // throws if the file is not a readable SQLite database
275
- }
276
- catch (err) {
277
- // Roll the registration back so a bad file doesn't linger in the list.
278
- this.pathById.delete(id);
279
- this.idByPath.delete(abs);
280
- this.nameById.delete(id);
281
- this.readonlyById.delete(id);
282
- this.files = this.files.filter((p) => p !== abs);
283
- throw err;
284
- }
285
- return id;
286
- }
287
- get(id) {
288
- return this.openDbs.get(id);
289
- }
290
- /** Count the tables in a database (opens it if necessary). */
291
- async countTables(id) {
292
- try {
293
- const db = this.open(id);
294
- const r = await db.listTables();
295
- return r.success ? (r.data?.length ?? 0) : 0;
296
- }
297
- catch {
298
- return 0;
299
- }
300
- }
301
- /** Create a new (empty) SQLite database. Returns its id. */
302
- create(name) {
303
- if (this.readonlyMode)
304
- throw new Error('Read-only mode — creating databases is disabled.');
305
- const fileName = sanitizeFileName(name);
306
- if (!fileName)
307
- throw new Error('Database name is required.');
308
- const abs = node_path_1.default.join(this.createDir, fileName);
309
- this.addFile(abs);
310
- const id = this.idByPath.get(abs);
311
- if (!id)
312
- throw new Error('Failed to register new database.');
313
- this.open(id); // better-sqlite3 creates the file on first open
314
- return id;
315
- }
316
- /** Dynamically register a named PostgreSQL or SQLite connection string. Returns its id. */
317
- addConnection(name, connectionString, readonly) {
318
- if (this.readonlyMode)
319
- throw new Error('Read-only mode — adding connections is disabled.');
320
- const raw = String(connectionString ?? '').trim();
321
- if (!raw)
322
- throw new Error('Connection string is required.');
323
- let cleanName = String(name ?? '').trim();
324
- if (!cleanName) {
325
- try {
326
- const u = new URL(raw);
327
- cleanName = u.pathname.replace(/^\//, '') || 'postgres';
328
- }
329
- catch {
330
- cleanName = 'postgres';
331
- }
332
- }
333
- this.addNamedTarget(cleanName, raw);
334
- const id = this.idByPath.get(raw);
335
- if (!id)
336
- throw new Error('Failed to register connection.');
337
- if (readonly !== undefined)
338
- this.readonlyById.set(id, readonly);
339
- return id;
340
- }
341
- /** Close and delete a database file (including WAL/SHM sidecars). */
342
- remove(id) {
343
- if (this.readonlyMode)
344
- throw new Error('Read-only mode — deleting databases is disabled.');
345
- const target = this.pathById.get(id);
346
- if (!target)
347
- return;
348
- const db = this.openDbs.get(id);
349
- if (db) {
350
- try {
351
- db.close();
352
- }
353
- catch {
354
- /* ignore */
355
- }
356
- this.openDbs.delete(id);
357
- }
358
- this.pathById.delete(id);
359
- this.idByPath.delete(target);
360
- this.nameById.delete(id);
361
- this.readonlyById.delete(id);
362
- this.files = this.files.filter((p) => p !== target);
363
- const isPg = target.startsWith('postgres://') || target.startsWith('postgresql://');
364
- if (!isPg) {
365
- for (const suffix of ['', '-wal', '-shm']) {
366
- try {
367
- (0, node_fs_1.unlinkSync)(target + suffix);
368
- }
369
- catch {
370
- /* ignore */
371
- }
372
- }
373
- }
374
- }
375
- closeAll() {
376
- for (const db of this.openDbs.values()) {
377
- try {
378
- db.close();
379
- }
380
- catch {
381
- /* ignore */
382
- }
383
- }
384
- this.openDbs.clear();
385
- }
386
- }
387
- exports.DbManager = DbManager;
388
- /** Turn a friendly name into a safe database file name (always ends in `.db`). */
389
- function sanitizeFileName(name) {
390
- let n = String(name ?? '').trim().replace(/[\\/]/g, '');
391
- if (!n)
392
- return '';
393
- if (!DB_EXTENSIONS.some((ext) => n.toLowerCase().endsWith(ext)))
394
- n += '.db';
395
- return n;
396
- }
397
- //# sourceMappingURL=manager.js.map
1
+ var __importDefault=this&&this.__importDefault||function(mod){return mod&&mod.__esModule?mod:{default:mod}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.DbManager=void 0;const node_fs_1=require("node:fs"),node_path_1=__importDefault(require("node:path")),database_1=require("./database"),postgres_1=require("./postgres"),logger_1=require("../utils/logger"),common_1=require("../utils/common"),DB_EXTENSIONS=[".db",".sqlite",".sqlite3"];exports.DbManager=class{logger;dir;createDir;readonlyMode;files=[];idByPath=new Map;pathById=new Map;nameById=new Map;readonlyById=new Map;openDbs=new Map;constructor(options,logger){const opts="string"==typeof options?{dir:options}:options??{};this.logger=logger??(0,logger_1.createLogger)("info","admindb"),this.dir=opts.dir?node_path_1.default.resolve(opts.dir):void 0,this.createDir=this.dir??process.cwd(),this.readonlyMode=!!opts.readonly,this.dir&&(0,node_fs_1.mkdirSync)(this.dir,{recursive:!0}),opts.connections&&this.registerConnections(opts.connections),this.registerDirFiles(),this.registerExplicitFiles(opts.files??[])}get directory(){return this.dir??this.createDir}get isReadOnly(){return this.readonlyMode}isDbFile(name){const lower=String(name??"").toLowerCase();return DB_EXTENSIONS.some(ext=>lower.endsWith(ext))}registerConnections(conns){for(const[name,target]of Object.entries(conns??{})){if(!name||!target)continue;const cleanTarget=String(target).trim();cleanTarget&&this.addNamedTarget(name.trim(),cleanTarget)}}registerDirFiles(){if(!this.dir)return;let names=[];try{names=(0,node_fs_1.readdirSync)(this.dir).filter(n=>this.isDbFile(n)).sort((a,b)=>a.localeCompare(b,void 0,{sensitivity:"base"}))}catch(err){this.logger.warn(`Failed to list database directory ${this.dir}: ${(0,common_1.errorMessage)(err)}`)}for(const name of names)this.addFile(node_path_1.default.join(this.dir,name))}registerExplicitFiles(files){for(const f of files??[]){const raw=String(f??"").trim();if(!raw)continue;if(raw.startsWith("postgres://")||raw.startsWith("postgresql://")){let name="postgres";try{name=new URL(raw).pathname.replace(/^\//,"")||"postgres"}catch{name="postgres"}this.addNamedTarget(name,raw);continue}const abs=node_path_1.default.resolve(raw);(0,node_fs_1.existsSync)(abs)?this.addFile(abs):this.logger.warn(`Skipping missing database file: ${f}`)}}addNamedTarget(name,target){let id=name,n=2;for(;this.pathById.has(id);)id=`${name}__${n}`,n+=1;this.files.push(target),this.idByPath.set(target,id),this.pathById.set(id,target),this.nameById.set(id,name)}addFile(abs){if(this.idByPath.has(abs))return;const base=node_path_1.default.basename(abs);let id=base,n=2;for(;this.pathById.has(id);){const ext=node_path_1.default.extname(base);id=`${node_path_1.default.basename(base,ext)}__${n}${ext}`,n+=1}this.files.push(abs),this.idByPath.set(abs,id),this.pathById.set(id,abs),this.nameById.set(id,base)}list(){const entries=[],seen=new Set;for(const[id,target]of this.pathById.entries()){if(seen.has(id))continue;seen.add(id);if(target.startsWith("postgres://")||target.startsWith("postgresql://")){let sanitized=target;try{const u=new URL(target);u.password&&(u.password="****"),sanitized=u.toString()}catch{sanitized=target.replace(/:([^:@]+)@/,":****@")}entries.push({id:id,name:this.nameById.get(id)??id,path:sanitized,dialect:"postgres",size:0,modified:"Connected",readonly:this.isDbReadOnly(id)})}else{let size=0,modified="";try{const st=(0,node_fs_1.statSync)(target);size=st.size,modified=st.mtime.toISOString()}catch{}entries.push({id:id,name:this.nameById.get(id)??node_path_1.default.basename(target),path:target,dialect:"sqlite",size:size,modified:modified,readonly:this.isDbReadOnly(id)})}}return entries}has(id){return this.pathById.has(id)}isDbReadOnly(id){return this.readonlyMode||(this.readonlyById.get(id)??!1)}setReadonly(id,readonly){if(this.readonlyMode&&!readonly)throw new Error("Manager is in global read-only mode — databases cannot be made writable.");if(this.readonlyById.get(id)===readonly)return;this.readonlyById.set(id,readonly);const db=this.openDbs.get(id);if(db){try{db.close()}catch{}this.openDbs.delete(id)}}open(id,readonlyOverride){const target=this.pathById.get(id);if(!target)throw new Error(`Database "${id}" is not registered.`);const isRo=this.readonlyMode||(void 0!==readonlyOverride?readonlyOverride:this.readonlyById.get(id)??!1);let db=this.openDbs.get(id);if(db&&db.isReadOnly!==isRo){try{db.close()}catch{}this.openDbs.delete(id),db=void 0}if(!db){db=target.startsWith("postgres://")||target.startsWith("postgresql://")?new postgres_1.PostgresDatabase(target,this.logger.child(`db:${id}`),{readonly:isRo}):new database_1.SqliteDatabase(target,this.logger.child(`db:${id}`),{readonly:isRo}),this.openDbs.set(id,db)}return db}openFile(absPath,readonly){const abs=node_path_1.default.resolve(String(absPath??"").trim());if(!abs)throw new Error("Database path is required.");if(!(0,node_fs_1.existsSync)(abs)||!(0,node_fs_1.statSync)(abs).isFile())throw new Error(`Not a file: ${abs}`);const existing=this.idByPath.get(abs);if(existing)return void 0!==readonly&&this.setReadonly(existing,readonly),existing;this.addFile(abs);const id=this.idByPath.get(abs);if(!id)throw new Error("Failed to register database file.");void 0!==readonly&&this.readonlyById.set(id,readonly);try{this.open(id)}catch(err){throw this.pathById.delete(id),this.idByPath.delete(abs),this.nameById.delete(id),this.readonlyById.delete(id),this.files=this.files.filter(p=>p!==abs),err}return id}get(id){return this.openDbs.get(id)}async countTables(id){try{const db=this.open(id),r=await db.listTables();return r.success?r.data?.length??0:0}catch{return 0}}create(name){if(this.readonlyMode)throw new Error("Read-only mode — creating databases is disabled.");const fileName=function(name){let n=String(name??"").trim().replace(/[\\/]/g,"");if(!n)return"";DB_EXTENSIONS.some(ext=>n.toLowerCase().endsWith(ext))||(n+=".db");return n}(name);if(!fileName)throw new Error("Database name is required.");const abs=node_path_1.default.join(this.createDir,fileName);this.addFile(abs);const id=this.idByPath.get(abs);if(!id)throw new Error("Failed to register new database.");return this.open(id),id}addConnection(name,connectionString,readonly){if(this.readonlyMode)throw new Error("Read-only mode — adding connections is disabled.");const raw=String(connectionString??"").trim();if(!raw)throw new Error("Connection string is required.");let cleanName=String(name??"").trim();if(!cleanName)try{cleanName=new URL(raw).pathname.replace(/^\//,"")||"postgres"}catch{cleanName="postgres"}this.addNamedTarget(cleanName,raw);const id=this.idByPath.get(raw);if(!id)throw new Error("Failed to register connection.");return void 0!==readonly&&this.readonlyById.set(id,readonly),id}remove(id){if(this.readonlyMode)throw new Error("Read-only mode — deleting databases is disabled.");const target=this.pathById.get(id);if(!target)return;const db=this.openDbs.get(id);if(db){try{db.close()}catch{}this.openDbs.delete(id)}this.pathById.delete(id),this.idByPath.delete(target),this.nameById.delete(id),this.readonlyById.delete(id),this.files=this.files.filter(p=>p!==target);if(!(target.startsWith("postgres://")||target.startsWith("postgresql://")))for(const suffix of["","-wal","-shm"])try{(0,node_fs_1.unlinkSync)(target+suffix)}catch{}}closeAll(){for(const db of this.openDbs.values())try{db.close()}catch{}this.openDbs.clear()}};
@@ -1,5 +1 @@
1
- import type Database from 'better-sqlite3';
2
- import { type ColumnDef } from '../sql/generator';
3
- export declare function modifyTableStructureSync(db: Database.Database, table: string, transformColumns: (columns: ColumnDef[]) => ColumnDef[], renamedOldCol?: string, renamedNewCol?: string): {
4
- changes: number;
5
- };
1
+ import type Database from 'better-sqlite3';import{type ColumnDef} from '../sql/generator';export declare function modifyTableStructureSync(db:Database.Database,table:string,transformColumns:(columns:ColumnDef[])=>ColumnDef[],renamedOldCol?:string,renamedNewCol?:string):{changes:number;};
@@ -1,110 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.modifyTableStructureSync = modifyTableStructureSync;
4
- const generator_1 = require("../sql/generator");
5
- function modifyTableStructureSync(db, table, transformColumns, renamedOldCol, renamedNewCol) {
6
- const rawCols = db.prepare(`PRAGMA table_info(${(0, generator_1.quoteIdentifier)(table)})`).all();
7
- if (!rawCols.length)
8
- throw new Error(`Table "${table}" does not exist.`);
9
- const fks = db.prepare(`PRAGMA foreign_key_list(${(0, generator_1.quoteIdentifier)(table)})`).all();
10
- const indexRows = db.prepare(`PRAGMA index_list(${(0, generator_1.quoteIdentifier)(table)})`).all();
11
- // Discover which single columns are UNIQUE across the whole table (so existing uniqueness is preserved)
12
- const uniqueCols = new Set();
13
- for (const ix of indexRows) {
14
- if (ix.unique) {
15
- const ixCols = db.prepare(`PRAGMA index_info(${(0, generator_1.quoteIdentifier)(ix.name)})`).all().map((c) => c.name);
16
- if (ixCols.length === 1) {
17
- uniqueCols.add(ixCols[0]);
18
- }
19
- }
20
- }
21
- const userIndexes = [];
22
- for (const ix of indexRows) {
23
- if (ix.origin === 'c') {
24
- const ixCols = db.prepare(`PRAGMA index_info(${(0, generator_1.quoteIdentifier)(ix.name)})`).all().map((c) => c.name);
25
- let ixName = ix.name;
26
- if (renamedOldCol && renamedNewCol) {
27
- if (ixName === `idx_${table}_${renamedOldCol}`) {
28
- ixName = `idx_${table}_${renamedNewCol}`;
29
- }
30
- else if (ixName === `idx_${table}_${renamedOldCol}_unique`) {
31
- ixName = `idx_${table}_${renamedNewCol}_unique`;
32
- }
33
- }
34
- userIndexes.push({
35
- name: ixName,
36
- unique: !!ix.unique,
37
- columns: ixCols.map((c) => (renamedOldCol && renamedNewCol && c === renamedOldCol ? renamedNewCol : c)),
38
- });
39
- }
40
- }
41
- const currentCols = rawCols.map((c) => {
42
- const existingFk = fks.find((f) => f.from === c.name);
43
- return {
44
- name: c.name,
45
- type: c.type,
46
- primaryKey: c.pk > 0,
47
- notNull: !!c.notnull,
48
- unique: uniqueCols.has(c.name),
49
- defaultValue: c.dflt_value,
50
- foreignKey: existingFk ? { table: existingFk.table, column: existingFk.to ?? '' } : null,
51
- };
52
- });
53
- const newCols = transformColumns(currentCols);
54
- const tempTable = `_admindb_tmp_${table}_${Date.now()}`;
55
- const createSql = (0, generator_1.generateCreateTable)(tempTable, newCols);
56
- const oldColMap = new Set(rawCols.map((c) => c.name));
57
- const matchingOldCols = [];
58
- const matchingNewCols = [];
59
- for (const nc of newCols) {
60
- let sourceColName = nc.name;
61
- if (renamedOldCol && renamedNewCol && nc.name === renamedNewCol) {
62
- sourceColName = renamedOldCol;
63
- }
64
- if (oldColMap.has(sourceColName)) {
65
- matchingOldCols.push((0, generator_1.quoteIdentifier)(sourceColName));
66
- matchingNewCols.push((0, generator_1.quoteIdentifier)(nc.name));
67
- }
68
- }
69
- db.exec('PRAGMA foreign_keys = OFF;');
70
- db.exec('BEGIN TRANSACTION;');
71
- try {
72
- db.exec(createSql);
73
- if (matchingOldCols.length > 0) {
74
- db.exec(`INSERT INTO ${(0, generator_1.quoteIdentifier)(tempTable)} (${matchingNewCols.join(', ')}) SELECT ${matchingOldCols.join(', ')} FROM ${(0, generator_1.quoteIdentifier)(table)};`);
75
- }
76
- db.exec(`DROP TABLE ${(0, generator_1.quoteIdentifier)(table)};`);
77
- db.exec(`ALTER TABLE ${(0, generator_1.quoteIdentifier)(tempTable)} RENAME TO ${(0, generator_1.quoteIdentifier)(table)};`);
78
- for (const ix of userIndexes) {
79
- const uq = ix.unique ? 'UNIQUE ' : '';
80
- const ixColsStr = ix.columns.map(generator_1.quoteIdentifier).join(', ');
81
- try {
82
- db.exec(`CREATE ${uq}INDEX IF NOT EXISTS ${(0, generator_1.quoteIdentifier)(ix.name)} ON ${(0, generator_1.quoteIdentifier)(table)} (${ixColsStr});`);
83
- }
84
- catch {
85
- /* ignore index recreation error */
86
- }
87
- }
88
- const fkCheck = db.prepare('PRAGMA foreign_key_check;').all();
89
- if (fkCheck.length > 0) {
90
- throw new Error('Foreign key constraint check failed after schema modification.');
91
- }
92
- db.exec('COMMIT;');
93
- return { changes: 1 };
94
- }
95
- catch (err) {
96
- try {
97
- db.exec('ROLLBACK;');
98
- }
99
- catch { /* ignore */ }
100
- try {
101
- db.exec(`DROP TABLE IF EXISTS ${(0, generator_1.quoteIdentifier)(tempTable)};`);
102
- }
103
- catch { /* ignore */ }
104
- throw err;
105
- }
106
- finally {
107
- db.exec('PRAGMA foreign_keys = ON;');
108
- }
109
- }
110
- //# sourceMappingURL=migrations.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.modifyTableStructureSync=function(db,table,transformColumns,renamedOldCol,renamedNewCol){const rawCols=db.prepare(`PRAGMA table_info(${(0,generator_1.quoteIdentifier)(table)})`).all();if(!rawCols.length)throw new Error(`Table "${table}" does not exist.`);const fks=db.prepare(`PRAGMA foreign_key_list(${(0,generator_1.quoteIdentifier)(table)})`).all(),indexRows=db.prepare(`PRAGMA index_list(${(0,generator_1.quoteIdentifier)(table)})`).all(),uniqueCols=new Set;for(const ix of indexRows)if(ix.unique){const ixCols=db.prepare(`PRAGMA index_info(${(0,generator_1.quoteIdentifier)(ix.name)})`).all().map(c=>c.name);1===ixCols.length&&uniqueCols.add(ixCols[0])}const userIndexes=[];for(const ix of indexRows)if("c"===ix.origin){const ixCols=db.prepare(`PRAGMA index_info(${(0,generator_1.quoteIdentifier)(ix.name)})`).all().map(c=>c.name);let ixName=ix.name;renamedOldCol&&renamedNewCol&&(ixName===`idx_${table}_${renamedOldCol}`?ixName=`idx_${table}_${renamedNewCol}`:ixName===`idx_${table}_${renamedOldCol}_unique`&&(ixName=`idx_${table}_${renamedNewCol}_unique`)),userIndexes.push({name:ixName,unique:!!ix.unique,columns:ixCols.map(c=>renamedOldCol&&renamedNewCol&&c===renamedOldCol?renamedNewCol:c)})}const currentCols=rawCols.map(c=>{const existingFk=fks.find(f=>f.from===c.name);return{name:c.name,type:c.type,primaryKey:c.pk>0,notNull:!!c.notnull,unique:uniqueCols.has(c.name),defaultValue:c.dflt_value,foreignKey:existingFk?{table:existingFk.table,column:existingFk.to??""}:null}}),newCols=transformColumns(currentCols),tempTable=`_admindb_tmp_${table}_${Date.now()}`,createSql=(0,generator_1.generateCreateTable)(tempTable,newCols),oldColMap=new Set(rawCols.map(c=>c.name)),matchingOldCols=[],matchingNewCols=[];for(const nc of newCols){let sourceColName=nc.name;renamedOldCol&&renamedNewCol&&nc.name===renamedNewCol&&(sourceColName=renamedOldCol),oldColMap.has(sourceColName)&&(matchingOldCols.push((0,generator_1.quoteIdentifier)(sourceColName)),matchingNewCols.push((0,generator_1.quoteIdentifier)(nc.name)))}db.exec("PRAGMA foreign_keys = OFF;"),db.exec("BEGIN TRANSACTION;");try{db.exec(createSql),matchingOldCols.length>0&&db.exec(`INSERT INTO ${(0,generator_1.quoteIdentifier)(tempTable)} (${matchingNewCols.join(", ")}) SELECT ${matchingOldCols.join(", ")} FROM ${(0,generator_1.quoteIdentifier)(table)};`),db.exec(`DROP TABLE ${(0,generator_1.quoteIdentifier)(table)};`),db.exec(`ALTER TABLE ${(0,generator_1.quoteIdentifier)(tempTable)} RENAME TO ${(0,generator_1.quoteIdentifier)(table)};`);for(const ix of userIndexes){const uq=ix.unique?"UNIQUE ":"",ixColsStr=ix.columns.map(generator_1.quoteIdentifier).join(", ");try{db.exec(`CREATE ${uq}INDEX IF NOT EXISTS ${(0,generator_1.quoteIdentifier)(ix.name)} ON ${(0,generator_1.quoteIdentifier)(table)} (${ixColsStr});`)}catch{}}if(db.prepare("PRAGMA foreign_key_check;").all().length>0)throw new Error("Foreign key constraint check failed after schema modification.");return db.exec("COMMIT;"),{changes:1}}catch(err){try{db.exec("ROLLBACK;")}catch{}try{db.exec(`DROP TABLE IF EXISTS ${(0,generator_1.quoteIdentifier)(tempTable)};`)}catch{}throw err}finally{db.exec("PRAGMA foreign_keys = ON;")}};const generator_1=require("../sql/generator");
@@ -1,85 +1 @@
1
- import type { Logger } from '../utils/logger';
2
- import { type ColumnDef, type IndexDef } from '../sql/generator';
3
- import type { DatabaseDialect, IDatabase, MutationResult, PostgresOptions, QueryOptions, ReferencingTableInfo, Result, RowFilters, SavedQuery, SchemaInfo, SQLInputValue, TableInfoData, TableListItem, WhereClause } from './types';
4
- export declare class PostgresDatabase implements IDatabase {
5
- private pool;
6
- private logger;
7
- readonly path: string;
8
- readonly isReadOnly: boolean;
9
- readonly dialect: DatabaseDialect;
10
- readonly schema: string;
11
- constructor(connection: string | PostgresOptions, logger: Logger, options?: PostgresOptions);
12
- private sanitizeConnectionString;
13
- private readonlyBlocked;
14
- close(): Promise<void>;
15
- private tryRun;
16
- /** Run a callback inside an atomic transaction on a dedicated client. */
17
- private transaction;
18
- private initSchema;
19
- hasMultipleStatements(sql: string): boolean;
20
- all(sql: string, params?: SQLInputValue[]): Promise<Result<unknown[]>>;
21
- run(sql: string, params?: SQLInputValue[]): Promise<Result<MutationResult>>;
22
- execResult(sql: string): Promise<Result<{
23
- changes?: number;
24
- }>>;
25
- runWrite(sql: string): Promise<Result<{
26
- changes?: number;
27
- }>>;
28
- listTables(): Promise<Result<TableListItem[]>>;
29
- getTableInfo(table: string): Promise<Result<TableInfoData>>;
30
- getRowCount(table: string, filters?: RowFilters): Promise<Result<number>>;
31
- getRows(table: string, opts?: QueryOptions): Promise<Result<Record<string, unknown>[]>>;
32
- getAllRows(table: string): Promise<Result<Record<string, unknown>[]>>;
33
- getRow(table: string, where: WhereClause[]): Promise<Result<Record<string, unknown> | null>>;
34
- insertRow(table: string, fields: WhereClause[]): Promise<Result<MutationResult>>;
35
- insertRows(table: string, rows: WhereClause[][]): Promise<Result<{
36
- inserted: number;
37
- skipped: number;
38
- }>>;
39
- updateRow(table: string, fields: WhereClause[], where: WhereClause[]): Promise<Result<MutationResult>>;
40
- updateRows(table: string, rows: {
41
- fields: WhereClause[];
42
- where: WhereClause[];
43
- }[]): Promise<Result<{
44
- updated: number;
45
- }>>;
46
- deleteRow(table: string, where: WhereClause[]): Promise<Result<MutationResult>>;
47
- deleteRows(table: string, rows: WhereClause[][]): Promise<Result<{
48
- deleted: number;
49
- }>>;
50
- getRowsByPks(table: string, pks: WhereClause[][]): Promise<Result<Record<string, unknown>[]>>;
51
- getRowsByFk(table: string, column: string, value: unknown, limit?: number): Promise<Result<{
52
- rows: Record<string, unknown>[];
53
- total: number;
54
- }>>;
55
- getCreateStatement(table: string): Promise<Result<string | null>>;
56
- listSavedQueries(): Promise<Result<SavedQuery[]>>;
57
- saveQuery(name: string, sql: string): Promise<Result<MutationResult>>;
58
- deleteSavedQuery(id: string | number): Promise<Result<MutationResult>>;
59
- getSchema(table: string): Promise<Result<SchemaInfo>>;
60
- getReferencingTables(table: string): Promise<Result<ReferencingTableInfo[]>>;
61
- renameTable(oldName: string, newName: string): Promise<Result<{
62
- changes?: number;
63
- }>>;
64
- addColumn(table: string, col: ColumnDef): Promise<Result<{
65
- changes?: number;
66
- }>>;
67
- modifyColumn(table: string, oldColName: string, newColDef: ColumnDef): Promise<Result<{
68
- changes?: number;
69
- }>>;
70
- renameColumn(table: string, oldName: string, newName: string): Promise<Result<{
71
- changes?: number;
72
- }>>;
73
- dropColumn(table: string, column: string): Promise<Result<{
74
- changes?: number;
75
- }>>;
76
- dropTable(table: string): Promise<Result<{
77
- changes?: number;
78
- }>>;
79
- createIndex(table: string, index: IndexDef): Promise<Result<{
80
- changes?: number;
81
- }>>;
82
- dropIndex(indexName: string): Promise<Result<{
83
- changes?: number;
84
- }>>;
85
- }
1
+ import type {Logger} from '../utils/logger';import{type ColumnDef,type IndexDef} from '../sql/generator';import type {DatabaseDialect,IDatabase,MutationResult,PostgresOptions,QueryOptions,ReferencingTableInfo,Result,RowFilters,SavedQuery,SchemaInfo,SQLInputValue,TableInfoData,TableListItem,WhereClause} from './types';export declare class PostgresDatabase implements IDatabase{private pool;private logger;readonly path:string;readonly isReadOnly:boolean;readonly dialect:DatabaseDialect;readonly schema:string;constructor(connection:string|PostgresOptions,logger:Logger,options?:PostgresOptions);private sanitizeConnectionString;private readonlyBlocked;close():Promise<void>;private tryRun;private transaction;private initSchema;hasMultipleStatements(sql:string):boolean;all(sql:string,params?:SQLInputValue[]):Promise<Result<unknown[]>>;run(sql:string,params?:SQLInputValue[]):Promise<Result<MutationResult>>;execResult(sql:string):Promise<Result<{changes?:number;}>>;runWrite(sql:string):Promise<Result<{changes?:number;}>>;listTables():Promise<Result<TableListItem[]>>;getTableInfo(table:string):Promise<Result<TableInfoData>>;getRowCount(table:string,filters?:RowFilters):Promise<Result<number>>;getRows(table:string,opts?:QueryOptions):Promise<Result<Record<string,unknown>[]>>;getAllRows(table:string):Promise<Result<Record<string,unknown>[]>>;getRow(table:string,where:WhereClause[]):Promise<Result<Record<string,unknown>|null>>;insertRow(table:string,fields:WhereClause[]):Promise<Result<MutationResult>>;insertRows(table:string,rows:WhereClause[][]):Promise<Result<{inserted:number;skipped:number;}>>;updateRow(table:string,fields:WhereClause[],where:WhereClause[]):Promise<Result<MutationResult>>;updateRows(table:string,rows:{fields:WhereClause[];where:WhereClause[];}[]):Promise<Result<{updated:number;}>>;deleteRow(table:string,where:WhereClause[]):Promise<Result<MutationResult>>;deleteRows(table:string,rows:WhereClause[][]):Promise<Result<{deleted:number;}>>;getRowsByPks(table:string,pks:WhereClause[][]):Promise<Result<Record<string,unknown>[]>>;getRowsByFk(table:string,column:string,value:unknown,limit?:number):Promise<Result<{rows:Record<string,unknown>[];total:number;}>>;getCreateStatement(table:string):Promise<Result<string|null>>;listSavedQueries():Promise<Result<SavedQuery[]>>;saveQuery(name:string,sql:string):Promise<Result<MutationResult>>;deleteSavedQuery(id:string|number):Promise<Result<MutationResult>>;getSchema(table:string):Promise<Result<SchemaInfo>>;getReferencingTables(table:string):Promise<Result<ReferencingTableInfo[]>>;renameTable(oldName:string,newName:string):Promise<Result<{changes?:number;}>>;addColumn(table:string,col:ColumnDef):Promise<Result<{changes?:number;}>>;modifyColumn(table:string,oldColName:string,newColDef:ColumnDef):Promise<Result<{changes?:number;}>>;renameColumn(table:string,oldName:string,newName:string):Promise<Result<{changes?:number;}>>;dropColumn(table:string,column:string):Promise<Result<{changes?:number;}>>;dropTable(table:string):Promise<Result<{changes?:number;}>>;createIndex(table:string,index:IndexDef):Promise<Result<{changes?:number;}>>;dropIndex(indexName:string):Promise<Result<{changes?:number;}>>;}