admindb 2.1.0 → 2.2.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 (191) hide show
  1. package/README.md +41 -12
  2. package/dist/app.d.ts +1 -69
  3. package/dist/app.js +3 -30
  4. package/dist/auth/config.d.ts +1 -19
  5. package/dist/auth/config.js +0 -26
  6. package/dist/auth/crypto.d.ts +1 -27
  7. package/dist/auth/crypto.js +1 -26
  8. package/dist/auth/index.d.ts +1 -5
  9. package/dist/auth/index.js +0 -1
  10. package/dist/auth/middleware.d.ts +1 -14
  11. package/dist/auth/middleware.js +0 -15
  12. package/dist/auth/routes.d.ts +1 -7
  13. package/dist/auth/routes.js +0 -8
  14. package/dist/auth/types.d.ts +1 -35
  15. package/dist/auth/types.js +1 -5
  16. package/dist/cli/args.d.ts +1 -45
  17. package/dist/cli/args.js +3 -11
  18. package/dist/cli/config.d.ts +1 -56
  19. package/dist/cli/config.js +0 -5
  20. package/dist/cli/index.d.ts +1 -4
  21. package/dist/cli/index.js +0 -1
  22. package/dist/cli/runner.d.ts +1 -1
  23. package/dist/cli/runner.js +6 -17
  24. package/dist/cli.d.ts +1 -2
  25. package/dist/cli.js +0 -1
  26. package/dist/data/chain.d.ts +1 -0
  27. package/dist/data/chain.js +707 -0
  28. package/dist/data/datasets.d.ts +1 -17
  29. package/dist/data/datasets.js +0 -4
  30. package/dist/data/detector.d.ts +1 -30
  31. package/dist/data/detector.js +53 -14
  32. package/dist/data/engine.d.ts +1 -10
  33. package/dist/data/engine.js +82 -48
  34. package/dist/data/index.d.ts +1 -5
  35. package/dist/data/index.js +1 -1
  36. package/dist/data/strategies.d.ts +1 -30
  37. package/dist/data/strategies.js +4 -8
  38. package/dist/data/types.d.ts +1 -73
  39. package/dist/data/types.js +0 -3
  40. package/dist/db/database.d.ts +1 -119
  41. package/dist/db/database.js +20 -14
  42. package/dist/db/export.d.ts +1 -12
  43. package/dist/db/export.js +54 -6
  44. package/dist/db/filters.d.ts +1 -22
  45. package/dist/db/filters.js +0 -16
  46. package/dist/db/index.d.ts +1 -8
  47. package/dist/db/index.js +0 -1
  48. package/dist/db/introspection.d.ts +1 -6
  49. package/dist/db/introspection.js +0 -5
  50. package/dist/db/manager.d.ts +1 -81
  51. package/dist/db/manager.js +13 -59
  52. package/dist/db/migrations.d.ts +1 -5
  53. package/dist/db/migrations.js +2 -5
  54. package/dist/db/postgres.d.ts +1 -85
  55. package/dist/db/postgres.js +21 -31
  56. package/dist/db/types.d.ts +1 -206
  57. package/dist/db/types.js +0 -1
  58. package/dist/index.d.ts +1 -23
  59. package/dist/index.js +0 -14
  60. package/dist/public/css/app.css +1 -1
  61. package/dist/public/js/api.js +1 -47
  62. package/dist/public/js/app.js +1 -262
  63. package/dist/public/js/browse.js +1 -1371
  64. package/dist/public/js/common.js +1 -0
  65. package/dist/public/js/databases.js +1 -235
  66. package/dist/public/js/designer.js +1 -258
  67. package/dist/public/js/forms.js +1 -826
  68. package/dist/public/js/home.js +1 -0
  69. package/dist/public/js/inspector.js +1 -638
  70. package/dist/public/js/query.js +1 -322
  71. package/dist/public/js/schema.js +1 -447
  72. package/dist/public/js/seed.js +1 -1090
  73. package/dist/routes/api/erd.d.ts +1 -0
  74. package/dist/routes/api/erd.js +50 -0
  75. package/dist/routes/api/helpers.d.ts +1 -42
  76. package/dist/routes/api/helpers.js +33 -3
  77. package/dist/routes/api/import-export.d.ts +1 -3
  78. package/dist/routes/api/import-export.js +0 -2
  79. package/dist/routes/api/index.d.ts +1 -4
  80. package/dist/routes/api/index.js +15 -4
  81. package/dist/routes/api/query.d.ts +1 -3
  82. package/dist/routes/api/query.js +13 -11
  83. package/dist/routes/api/rows.d.ts +1 -3
  84. package/dist/routes/api/rows.js +0 -11
  85. package/dist/routes/api/seed.d.ts +1 -3
  86. package/dist/routes/api/seed.js +79 -8
  87. package/dist/routes/api/tables.d.ts +1 -3
  88. package/dist/routes/api/tables.js +77 -6
  89. package/dist/routes/databases.d.ts +1 -26
  90. package/dist/routes/databases.js +1 -3
  91. package/dist/routes/index.d.ts +1 -3
  92. package/dist/routes/index.js +0 -1
  93. package/dist/routes/pages.d.ts +1 -9
  94. package/dist/routes/pages.js +18 -11
  95. package/dist/serverless.d.ts +1 -40
  96. package/dist/serverless.js +3 -39
  97. package/dist/sql/classifier.d.ts +1 -19
  98. package/dist/sql/classifier.js +0 -13
  99. package/dist/sql/error-analyzer.d.ts +1 -0
  100. package/dist/sql/error-analyzer.js +550 -0
  101. package/dist/sql/generator.d.ts +1 -81
  102. package/dist/sql/generator.js +0 -29
  103. package/dist/sql/index.d.ts +1 -2
  104. package/dist/sql/index.js +0 -1
  105. package/dist/types/api.d.ts +1 -412
  106. package/dist/types/api.js +0 -7
  107. package/dist/utils/colors.d.ts +1 -40
  108. package/dist/utils/colors.js +0 -10
  109. package/dist/utils/common.d.ts +1 -50
  110. package/dist/utils/common.js +19 -23
  111. package/dist/utils/csv.d.ts +1 -15
  112. package/dist/utils/csv.js +0 -13
  113. package/dist/utils/datatype.d.ts +1 -49
  114. package/dist/utils/datatype.js +0 -41
  115. package/dist/utils/icons.d.ts +1 -11
  116. package/dist/utils/icons.js +25 -16
  117. package/dist/utils/index.d.ts +1 -4
  118. package/dist/utils/index.js +0 -1
  119. package/dist/utils/logger.d.ts +1 -10
  120. package/dist/utils/logger.js +0 -4
  121. package/dist/views/layouts/main.hbs +14 -5
  122. package/dist/views/pages/databases.hbs +0 -18
  123. package/dist/views/pages/designer.hbs +0 -10
  124. package/dist/views/pages/erd.hbs +1241 -0
  125. package/dist/views/pages/error.hbs +0 -2
  126. package/dist/views/pages/form.hbs +0 -5
  127. package/dist/views/pages/home.hbs +98 -10
  128. package/dist/views/pages/info.hbs +107 -0
  129. package/dist/views/pages/login.hbs +0 -13
  130. package/dist/views/pages/query.hbs +54 -21
  131. package/dist/views/pages/schema.hbs +0 -20
  132. package/dist/views/pages/seed.hbs +435 -202
  133. package/dist/views/pages/table.hbs +0 -14
  134. package/dist/views/partials/icon.hbs +0 -1
  135. package/dist/views/partials/navbar.hbs +0 -6
  136. package/dist/views/partials/sidebar.hbs +12 -8
  137. package/docs/API.md +6 -1
  138. package/docs/EXAMPLES.md +3 -0
  139. package/package.json +7 -5
  140. package/dist/app.js.map +0 -1
  141. package/dist/auth/config.js.map +0 -1
  142. package/dist/auth/crypto.js.map +0 -1
  143. package/dist/auth/index.js.map +0 -1
  144. package/dist/auth/middleware.js.map +0 -1
  145. package/dist/auth/routes.js.map +0 -1
  146. package/dist/auth/types.js.map +0 -1
  147. package/dist/cli/args.js.map +0 -1
  148. package/dist/cli/config.js.map +0 -1
  149. package/dist/cli/index.js.map +0 -1
  150. package/dist/cli/runner.js.map +0 -1
  151. package/dist/cli.js.map +0 -1
  152. package/dist/data/datasets.js.map +0 -1
  153. package/dist/data/detector.js.map +0 -1
  154. package/dist/data/engine.js.map +0 -1
  155. package/dist/data/index.js.map +0 -1
  156. package/dist/data/strategies.js.map +0 -1
  157. package/dist/data/types.js.map +0 -1
  158. package/dist/db/database.js.map +0 -1
  159. package/dist/db/export.js.map +0 -1
  160. package/dist/db/filters.js.map +0 -1
  161. package/dist/db/index.js.map +0 -1
  162. package/dist/db/introspection.js.map +0 -1
  163. package/dist/db/manager.js.map +0 -1
  164. package/dist/db/migrations.js.map +0 -1
  165. package/dist/db/postgres.js.map +0 -1
  166. package/dist/db/types.js.map +0 -1
  167. package/dist/index.js.map +0 -1
  168. package/dist/public/css/input.css +0 -302
  169. package/dist/public/js/icons.js +0 -51
  170. package/dist/routes/api/helpers.js.map +0 -1
  171. package/dist/routes/api/import-export.js.map +0 -1
  172. package/dist/routes/api/index.js.map +0 -1
  173. package/dist/routes/api/query.js.map +0 -1
  174. package/dist/routes/api/rows.js.map +0 -1
  175. package/dist/routes/api/seed.js.map +0 -1
  176. package/dist/routes/api/tables.js.map +0 -1
  177. package/dist/routes/databases.js.map +0 -1
  178. package/dist/routes/index.js.map +0 -1
  179. package/dist/routes/pages.js.map +0 -1
  180. package/dist/serverless.js.map +0 -1
  181. package/dist/sql/classifier.js.map +0 -1
  182. package/dist/sql/generator.js.map +0 -1
  183. package/dist/sql/index.js.map +0 -1
  184. package/dist/types/api.js.map +0 -1
  185. package/dist/utils/colors.js.map +0 -1
  186. package/dist/utils/common.js.map +0 -1
  187. package/dist/utils/csv.js.map +0 -1
  188. package/dist/utils/datatype.js.map +0 -1
  189. package/dist/utils/icons.js.map +0 -1
  190. package/dist/utils/index.js.map +0 -1
  191. package/dist/utils/logger.js.map +0 -1
@@ -1,119 +1 @@
1
- import type { Logger } from '../utils/logger';
2
- import { type ColumnDef, type IndexDef } from '../sql/generator';
3
- import type { DatabaseDialect, DbOpenOptions, IDatabase, ReferencingTableInfo, Result, RowFilters, SavedQuery, SchemaInfo, SQLInputValue, TableInfoData, TableListItem, WhereClause } from './types';
4
- export * from './types';
5
- export * from './filters';
6
- /**
7
- * Promise-style wrapper around the better-sqlite3 driver.
8
- * Every call returns a consistent `{ success, data?, error? }` shape and
9
- * performs one-time, idempotent schema initialization.
10
- */
11
- export declare class SqliteDatabase implements IDatabase {
12
- private db;
13
- private logger;
14
- readonly path: string;
15
- readonly isReadOnly: boolean;
16
- readonly dialect: DatabaseDialect;
17
- constructor(dbPath: string, logger: Logger, options?: DbOpenOptions);
18
- private readonlyBlocked;
19
- close(): void;
20
- private initSchema;
21
- private tryRun;
22
- /** Run an atomic transaction. Reverts on any error and enforces read-only mode. */
23
- private transaction;
24
- private toBind;
25
- all(sql: string, params?: SQLInputValue[]): Promise<Result<unknown[]>>;
26
- run(sql: string, params?: SQLInputValue[]): Promise<Result<{
27
- changes: number;
28
- lastInsertRowid: number | null;
29
- }>>;
30
- execResult(sql: string): Promise<Result<{
31
- changes?: number;
32
- }>>;
33
- hasMultipleStatements(sql: string): boolean;
34
- runWrite(sql: string): Promise<Result<{
35
- changes?: number;
36
- }>>;
37
- listTables(): Promise<Result<TableListItem[]>>;
38
- getTableInfo(table: string): Promise<Result<TableInfoData>>;
39
- getRowCount(table: string, filters?: RowFilters): Promise<Result<number>>;
40
- getRows(table: string, opts?: {
41
- page?: number;
42
- limit?: number;
43
- orderBy?: string;
44
- orderDir?: 'asc' | 'desc';
45
- filters?: RowFilters;
46
- }): Promise<Result<Record<string, unknown>[]>>;
47
- getAllRows(table: string): Promise<Result<Record<string, unknown>[]>>;
48
- getRow(table: string, where: WhereClause[]): Promise<Result<Record<string, unknown> | null>>;
49
- insertRow(table: string, fields: WhereClause[]): Promise<Result<{
50
- changes: number;
51
- lastInsertRowid: number | null;
52
- }>>;
53
- /** Insert many rows inside a single atomic transaction. */
54
- insertRows(table: string, rows: WhereClause[][]): Promise<Result<{
55
- inserted: number;
56
- skipped: number;
57
- }>>;
58
- updateRow(table: string, fields: WhereClause[], where: WhereClause[]): Promise<Result<{
59
- changes: number;
60
- lastInsertRowid: number | null;
61
- }>>;
62
- /** Apply many row updates inside a single atomic transaction. */
63
- updateRows(table: string, rows: {
64
- fields: WhereClause[];
65
- where: WhereClause[];
66
- }[]): Promise<Result<{
67
- updated: number;
68
- }>>;
69
- deleteRow(table: string, where: WhereClause[]): Promise<Result<{
70
- changes: number;
71
- lastInsertRowid: number | null;
72
- }>>;
73
- /** Delete many rows inside a single atomic transaction. */
74
- deleteRows(table: string, rows: WhereClause[][]): Promise<Result<{
75
- deleted: number;
76
- }>>;
77
- getRowsByPks(table: string, pks: WhereClause[][]): Promise<Result<Record<string, unknown>[]>>;
78
- getCreateStatement(table: string): Promise<Result<string | null>>;
79
- listSavedQueries(): Promise<Result<SavedQuery[]>>;
80
- saveQuery(name: string, sql: string): Promise<Result<{
81
- changes: number;
82
- lastInsertRowid: number | null;
83
- }>>;
84
- deleteSavedQuery(id: string | number): Promise<Result<{
85
- changes: number;
86
- lastInsertRowid: number | null;
87
- }>>;
88
- getSchema(table: string): Promise<Result<SchemaInfo>>;
89
- getReferencingTables(table: string): Promise<Result<ReferencingTableInfo[]>>;
90
- getRowsByFk(table: string, column: string, value: unknown, limit?: number): Promise<Result<{
91
- rows: Record<string, unknown>[];
92
- total: number;
93
- }>>;
94
- renameTable(oldName: string, newName: string): Promise<Result<{
95
- changes?: number;
96
- }>>;
97
- addColumn(table: string, col: ColumnDef): Promise<Result<{
98
- changes?: number;
99
- }>>;
100
- modifyColumn(table: string, oldColName: string, newColDef: ColumnDef): Promise<Result<{
101
- changes?: number;
102
- }>>;
103
- renameColumn(table: string, oldName: string, newName: string): Promise<Result<{
104
- changes?: number;
105
- }>>;
106
- dropColumn(table: string, column: string): Promise<Result<{
107
- changes?: number;
108
- }>>;
109
- dropTable(table: string): Promise<Result<{
110
- changes?: number;
111
- }>>;
112
- createIndex(table: string, index: IndexDef): Promise<Result<{
113
- changes?: number;
114
- }>>;
115
- dropIndex(indexName: string): Promise<Result<{
116
- changes?: number;
117
- }>>;
118
- private getTableInfoSync;
119
- }
1
+ import type {Logger} from '../utils/logger';import{type ColumnDef,type IndexDef} from '../sql/generator';import type {DatabaseDialect,DbOpenOptions,IDatabase,ReferencingTableInfo,Result,RowFilters,SavedQuery,SchemaInfo,SQLInputValue,TableInfoData,TableListItem,WhereClause} from './types';export * from './types';export * from './filters';export declare class SqliteDatabase implements IDatabase{private db;private logger;readonly path:string;readonly isReadOnly:boolean;readonly dialect:DatabaseDialect;constructor(dbPath:string,logger:Logger,options?:DbOpenOptions);private readonlyBlocked;close():void;private initSchema;private tryRun;private transaction;private toBind;all(sql:string,params?:SQLInputValue[]):Promise<Result<unknown[]>>;run(sql:string,params?:SQLInputValue[]):Promise<Result<{changes:number;lastInsertRowid:number|null;}>>;execResult(sql:string):Promise<Result<{changes?:number;}>>;hasMultipleStatements(sql:string):boolean;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?:{page?:number;limit?:number;orderBy?:string;orderDir?:'asc'|'desc';filters?:RowFilters;}):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<{changes:number;lastInsertRowid:number|null;}>>;insertRows(table:string,rows:WhereClause[][]):Promise<Result<{inserted:number;skipped:number;}>>;updateRow(table:string,fields:WhereClause[],where:WhereClause[]):Promise<Result<{changes:number;lastInsertRowid:number|null;}>>;updateRows(table:string,rows:{fields:WhereClause[];where:WhereClause[];}[]):Promise<Result<{updated:number;}>>;deleteRow(table:string,where:WhereClause[]):Promise<Result<{changes:number;lastInsertRowid:number|null;}>>;deleteRows(table:string,rows:WhereClause[][]):Promise<Result<{deleted:number;}>>;getRowsByPks(table:string,pks:WhereClause[][]):Promise<Result<Record<string,unknown>[]>>;getCreateStatement(table:string):Promise<Result<string|null>>;listSavedQueries():Promise<Result<SavedQuery[]>>;saveQuery(name:string,sql:string):Promise<Result<{changes:number;lastInsertRowid:number|null;}>>;deleteSavedQuery(id:string|number):Promise<Result<{changes:number;lastInsertRowid:number|null;}>>;getSettings():Promise<Result<Record<string,string>>>;getSchema(table:string):Promise<Result<SchemaInfo>>;getReferencingTables(table:string):Promise<Result<ReferencingTableInfo[]>>;getRowsByFk(table:string,column:string,value:unknown,limit?:number):Promise<Result<{rows:Record<string,unknown>[];total:number;}>>;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;}>>;private getTableInfoSync;}
@@ -27,11 +27,6 @@ const introspection_1 = require("./introspection");
27
27
  const migrations_1 = require("./migrations");
28
28
  __exportStar(require("./types"), exports);
29
29
  __exportStar(require("./filters"), exports);
30
- /**
31
- * Promise-style wrapper around the better-sqlite3 driver.
32
- * Every call returns a consistent `{ success, data?, error? }` shape and
33
- * performs one-time, idempotent schema initialization.
34
- */
35
30
  class SqliteDatabase {
36
31
  db;
37
32
  logger;
@@ -85,7 +80,6 @@ class SqliteDatabase {
85
80
  return { success: false, error: msg };
86
81
  }
87
82
  }
88
- /** Run an atomic transaction. Reverts on any error and enforces read-only mode. */
89
83
  transaction(fn) {
90
84
  if (this.isReadOnly)
91
85
  return Promise.resolve(this.readonlyBlocked());
@@ -100,7 +94,7 @@ class SqliteDatabase {
100
94
  try {
101
95
  this.db.exec('ROLLBACK');
102
96
  }
103
- catch { /* ignore */ }
97
+ catch { }
104
98
  throw err;
105
99
  }
106
100
  });
@@ -218,7 +212,6 @@ class SqliteDatabase {
218
212
  const sql = `INSERT INTO ${(0, generator_1.quoteIdentifier)(table)} (${cols.join(', ')}) VALUES (${fields.map(() => '?').join(', ')})`;
219
213
  return this.run(sql, fields.map((f) => this.toBind(f.value)));
220
214
  }
221
- /** Insert many rows inside a single atomic transaction. */
222
215
  async insertRows(table, rows) {
223
216
  return this.transaction(() => {
224
217
  let inserted = 0;
@@ -239,7 +232,6 @@ class SqliteDatabase {
239
232
  const sql = `UPDATE ${(0, generator_1.quoteIdentifier)(table)} SET ${sets.join(', ')} WHERE ${conds.join(' AND ')}`;
240
233
  return this.run(sql, [...fields.map((f) => this.toBind(f.value)), ...where.map((w) => this.toBind(w.value))]);
241
234
  }
242
- /** Apply many row updates inside a single atomic transaction. */
243
235
  async updateRows(table, rows) {
244
236
  return this.transaction(() => {
245
237
  let updated = 0;
@@ -260,7 +252,6 @@ class SqliteDatabase {
260
252
  const sql = `DELETE FROM ${(0, generator_1.quoteIdentifier)(table)} WHERE ${conds.join(' AND ')}`;
261
253
  return this.run(sql, where.map((w) => this.toBind(w.value)));
262
254
  }
263
- /** Delete many rows inside a single atomic transaction. */
264
255
  async deleteRows(table, rows) {
265
256
  return this.transaction(() => {
266
257
  let deleted = 0;
@@ -308,6 +299,23 @@ class SqliteDatabase {
308
299
  async deleteSavedQuery(id) {
309
300
  return this.run(`DELETE FROM ${(0, generator_1.quoteIdentifier)(types_1.INTERNAL_TABLES.savedQueries)} WHERE id = ?`, [Number(id)]);
310
301
  }
302
+ async getSettings() {
303
+ return this.tryRun(() => {
304
+ const pragmas = ['journal_mode', 'synchronous', 'foreign_keys', 'page_size', 'encoding', 'auto_vacuum', 'mmap_size', 'temp_store'];
305
+ const settings = {};
306
+ for (const p of pragmas) {
307
+ try {
308
+ const row = this.db.prepare(`PRAGMA ${p}`).get();
309
+ if (row && p in row) {
310
+ settings[p] = String(row[p]);
311
+ }
312
+ }
313
+ catch {
314
+ }
315
+ }
316
+ return settings;
317
+ });
318
+ }
311
319
  async getSchema(table) {
312
320
  return this.tryRun(() => (0, introspection_1.getSchemaSync)(this.db, table));
313
321
  }
@@ -380,7 +388,6 @@ class SqliteDatabase {
380
388
  const defaultMatches = newColDef.defaultValue === undefined || String(newColDef.defaultValue ?? '').trim() === String(existing.dflt_value ?? '').trim();
381
389
  const fkMatches = newColDef.foreignKey === undefined || ((!newColDef.foreignKey && !existingFk) ||
382
390
  (newColDef.foreignKey && existingFk && newColDef.foreignKey.table === existingFk.table && newColDef.foreignKey.column === existingFk.to));
383
- // Fast path: if ONLY the column name changed, use native RENAME COLUMN.
384
391
  if (oldColName !== newName && typeMatches && pkMatches && notNullMatches && uniqueMatches && defaultMatches && fkMatches) {
385
392
  this.db.exec((0, generator_1.generateRenameColumn)(table, oldColName, newName));
386
393
  const existingIdxNames = new Set(indexRows.map((i) => i.name));
@@ -393,7 +400,7 @@ class SqliteDatabase {
393
400
  this.db.exec(`DROP INDEX ${(0, generator_1.quoteIdentifier)(defaultOldIdx)};`);
394
401
  this.db.exec(`CREATE ${uniqueKeyword}INDEX IF NOT EXISTS ${(0, generator_1.quoteIdentifier)(newIdxName)} ON ${(0, generator_1.quoteIdentifier)(table)} (${(0, generator_1.quoteIdentifier)(newName)});`);
395
402
  }
396
- catch { /* ignore */ }
403
+ catch { }
397
404
  }
398
405
  }
399
406
  return { changes: 1 };
@@ -436,7 +443,7 @@ class SqliteDatabase {
436
443
  this.db.exec(`DROP INDEX ${(0, generator_1.quoteIdentifier)(defaultOldIdx)};`);
437
444
  this.db.exec(`CREATE ${uniqueKeyword}INDEX IF NOT EXISTS ${(0, generator_1.quoteIdentifier)(newIdxName)} ON ${(0, generator_1.quoteIdentifier)(table)} (${(0, generator_1.quoteIdentifier)(newName)});`);
438
445
  }
439
- catch { /* ignore */ }
446
+ catch { }
440
447
  }
441
448
  }
442
449
  return { changes: 1 };
@@ -468,4 +475,3 @@ class SqliteDatabase {
468
475
  }
469
476
  }
470
477
  exports.SqliteDatabase = SqliteDatabase;
471
- //# sourceMappingURL=database.js.map
@@ -1,12 +1 @@
1
- import type { IDatabase } from './types';
2
- export interface DumpResult {
3
- success: boolean;
4
- data?: string;
5
- error?: string;
6
- }
7
- /**
8
- * Produce a downloadable SQL dump: for every table emit its CREATE statement
9
- * followed by one INSERT statement per row. BLOB values are exported as
10
- * X'…' literals so they round-trip as real blobs.
11
- */
12
- export declare function generateSqlDump(db: IDatabase): Promise<DumpResult>;
1
+ import type {IDatabase} from './types';export interface DumpResult{success:boolean;data?:string;error?:string;}export declare function generateSqlDump(db:IDatabase):Promise<DumpResult>;export declare function generateSchemaDump(db:IDatabase):Promise<DumpResult>;
package/dist/db/export.js CHANGED
@@ -1,12 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateSqlDump = generateSqlDump;
4
+ exports.generateSchemaDump = generateSchemaDump;
4
5
  const generator_1 = require("../sql/generator");
5
- /**
6
- * Produce a downloadable SQL dump: for every table emit its CREATE statement
7
- * followed by one INSERT statement per row. BLOB values are exported as
8
- * X'…' literals so they round-trip as real blobs.
9
- */
10
6
  async function generateSqlDump(db) {
11
7
  const out = [];
12
8
  if (db.dialect === 'sqlite') {
@@ -39,4 +35,56 @@ async function generateSqlDump(db) {
39
35
  out.push('COMMIT;');
40
36
  return { success: true, data: out.join('\n') };
41
37
  }
42
- //# sourceMappingURL=export.js.map
38
+ async function generateSchemaDump(db) {
39
+ const out = [];
40
+ if (db.dialect === 'sqlite') {
41
+ const allSchemas = await db.all(`SELECT sql FROM sqlite_master WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_saved_queries'`);
42
+ if (allSchemas.success && allSchemas.data) {
43
+ for (const row of allSchemas.data) {
44
+ let stmt = String(row.sql).trim();
45
+ if (!stmt.endsWith(';'))
46
+ stmt += ';';
47
+ out.push(stmt);
48
+ out.push('');
49
+ }
50
+ }
51
+ else {
52
+ return { success: false, error: allSchemas.error ?? 'Failed to read sqlite_master.' };
53
+ }
54
+ }
55
+ else {
56
+ const tables = await db.listTables();
57
+ if (!tables.success)
58
+ return { success: false, error: tables.error ?? 'Failed to list tables.' };
59
+ for (const t of tables.data ?? []) {
60
+ const name = t.name;
61
+ const info = await db.getTableInfo(name);
62
+ if (info.success && info.data) {
63
+ if (info.data.sql) {
64
+ out.push(info.data.sql.trim());
65
+ }
66
+ if (info.data.foreignKeys && info.data.foreignKeys.length > 0) {
67
+ for (const fk of info.data.foreignKeys) {
68
+ if (fk.from && fk.to && fk.table) {
69
+ let action = '';
70
+ if (fk.on_delete && fk.on_delete !== 'NO ACTION')
71
+ action += ` ON DELETE ${fk.on_delete}`;
72
+ if (fk.on_update && fk.on_update !== 'NO ACTION')
73
+ action += ` ON UPDATE ${fk.on_update}`;
74
+ out.push(`ALTER TABLE "${name}" ADD FOREIGN KEY ("${fk.from}") REFERENCES "${fk.table}" ("${fk.to}")${action};`);
75
+ }
76
+ }
77
+ }
78
+ if (info.data.indexes && info.data.indexes.length > 0) {
79
+ for (const idx of info.data.indexes) {
80
+ if (idx.sql) {
81
+ out.push(idx.sql.trim() + ';');
82
+ }
83
+ }
84
+ }
85
+ out.push('');
86
+ }
87
+ }
88
+ }
89
+ return { success: true, data: out.join('\n').trim() };
90
+ }
@@ -1,22 +1 @@
1
- import type { FilterCondition, RowFilters, SQLInputValue } from './types';
2
- /** Escape LIKE wildcards so user filter text is matched literally. */
3
- export declare function escapeLike(s: string): string;
4
- /**
5
- * Build a parameterized WHERE clause from per-column filters.
6
- *
7
- * A filter value is either:
8
- * - the legacy string syntax: `=value` exact, `!=value`, `>value`, `>=value`,
9
- * `<value`, `<=value`, `value*` prefix, anything else → substring match; or
10
- * - a structured `FilterCondition` (or array of them) produced by the
11
- * type-aware filter form (FK dropdowns, boolean toggles, date/number ranges).
12
- */
13
- export declare function pushFilterCondition(conds: string[], params: SQLInputValue[], quotedCol: string, c: FilterCondition): void;
14
- export declare function buildFilterClause(filters: RowFilters | undefined, availableCols: string[]): {
15
- where: string;
16
- params: SQLInputValue[];
17
- };
18
- /**
19
- * Replace SQLite-style `?` placeholders with PostgreSQL-style `$1, $2, ...`
20
- * placeholders while safely preserving single-quoted string literals.
21
- */
22
- export declare function convertPlaceholdersToPostgres(sql: string, startIdx?: number): string;
1
+ import type {FilterCondition,RowFilters,SQLInputValue} from './types';export declare function escapeLike(s:string):string;export declare function pushFilterCondition(conds:string[],params:SQLInputValue[],quotedCol:string,c:FilterCondition):void;export declare function buildFilterClause(filters:RowFilters|undefined,availableCols:string[]):{where:string;params:SQLInputValue[];};export declare function convertPlaceholdersToPostgres(sql:string,startIdx?:number):string;
@@ -5,19 +5,9 @@ exports.pushFilterCondition = pushFilterCondition;
5
5
  exports.buildFilterClause = buildFilterClause;
6
6
  exports.convertPlaceholdersToPostgres = convertPlaceholdersToPostgres;
7
7
  const generator_1 = require("../sql/generator");
8
- /** Escape LIKE wildcards so user filter text is matched literally. */
9
8
  function escapeLike(s) {
10
9
  return String(s).replace(/[\\%_]/g, (m) => '\\' + m);
11
10
  }
12
- /**
13
- * Build a parameterized WHERE clause from per-column filters.
14
- *
15
- * A filter value is either:
16
- * - the legacy string syntax: `=value` exact, `!=value`, `>value`, `>=value`,
17
- * `<value`, `<=value`, `value*` prefix, anything else → substring match; or
18
- * - a structured `FilterCondition` (or array of them) produced by the
19
- * type-aware filter form (FK dropdowns, boolean toggles, date/number ranges).
20
- */
21
11
  function pushFilterCondition(conds, params, quotedCol, c) {
22
12
  const value = String(c.value ?? '');
23
13
  switch (c.op) {
@@ -88,7 +78,6 @@ function buildFilterClause(filters, availableCols) {
88
78
  pushFilterCondition(conds, params, q, raw);
89
79
  continue;
90
80
  }
91
- // Legacy string syntax.
92
81
  const value = String(raw ?? '').trim();
93
82
  if (value === '')
94
83
  continue;
@@ -127,10 +116,6 @@ function buildFilterClause(filters, availableCols) {
127
116
  }
128
117
  return { where: conds.length ? ` WHERE ${conds.join(' AND ')}` : '', params };
129
118
  }
130
- /**
131
- * Replace SQLite-style `?` placeholders with PostgreSQL-style `$1, $2, ...`
132
- * placeholders while safely preserving single-quoted string literals.
133
- */
134
119
  function convertPlaceholdersToPostgres(sql, startIdx = 1) {
135
120
  let idx = startIdx;
136
121
  let inString = false;
@@ -155,4 +140,3 @@ function convertPlaceholdersToPostgres(sql, startIdx = 1) {
155
140
  }
156
141
  return result;
157
142
  }
158
- //# sourceMappingURL=filters.js.map
@@ -1,8 +1 @@
1
- export * from './types';
2
- export * from './filters';
3
- export * from './introspection';
4
- export * from './migrations';
5
- export * from './database';
6
- export * from './postgres';
7
- export * from './manager';
8
- export * from './export';
1
+ export * from './types';export * from './filters';export * from './introspection';export * from './migrations';export * from './database';export * from './postgres';export * from './manager';export * from './export';
package/dist/db/index.js CHANGED
@@ -22,4 +22,3 @@ __exportStar(require("./database"), exports);
22
22
  __exportStar(require("./postgres"), exports);
23
23
  __exportStar(require("./manager"), exports);
24
24
  __exportStar(require("./export"), exports);
25
- //# sourceMappingURL=index.js.map
@@ -1,6 +1 @@
1
- import type Database from 'better-sqlite3';
2
- import type { ReferencingTableInfo, SchemaInfo, TableInfoData, TableListItem } from './types';
3
- export declare function listTablesSync(db: Database.Database): TableListItem[];
4
- export declare function getTableInfoSync(db: Database.Database, table: string): TableInfoData;
5
- export declare function getSchemaSync(db: Database.Database, table: string): SchemaInfo;
6
- export declare function getReferencingTablesSync(db: Database.Database, table: string): ReferencingTableInfo[];
1
+ import type Database from 'better-sqlite3';import type {ReferencingTableInfo,SchemaInfo,TableInfoData,TableListItem} from './types';export declare function listTablesSync(db:Database.Database):TableListItem[];export declare function getTableInfoSync(db:Database.Database,table:string):TableInfoData;export declare function getSchemaSync(db:Database.Database,table:string):SchemaInfo;export declare function getReferencingTablesSync(db:Database.Database,table:string):ReferencingTableInfo[];
@@ -11,13 +11,11 @@ function listTablesSync(db) {
11
11
  .all();
12
12
  return rows.map((r) => ({ name: r.name }));
13
13
  }
14
- /** Get all tables non-internal in the SQLite database. */
15
14
  function getTableNames(db) {
16
15
  return db
17
16
  .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'")
18
17
  .all().map((r) => r.name);
19
18
  }
20
- /** Discover all foreign keys declared across all other tables pointing to `targetTable`. */
21
19
  function getIncomingFks(db, targetTable) {
22
20
  const refs = [];
23
21
  for (const t of getTableNames(db)) {
@@ -31,7 +29,6 @@ function getIncomingFks(db, targetTable) {
31
29
  }
32
30
  }
33
31
  catch {
34
- /* ignore unreadable tables */
35
32
  }
36
33
  }
37
34
  return refs;
@@ -162,11 +159,9 @@ function getReferencingTablesSync(db, table) {
162
159
  refCount = Number(row.c);
163
160
  }
164
161
  catch {
165
- /* count is best-effort */
166
162
  }
167
163
  result.push({ table: t, refs: tRefs, refCount });
168
164
  }
169
165
  result.sort((a, b) => a.table.localeCompare(b.table));
170
166
  return result;
171
167
  }
172
- //# sourceMappingURL=introspection.js.map
@@ -1,81 +1 @@
1
- import type { IDatabase } from './types';
2
- import { type Logger } from '../utils/logger';
3
- export interface DbManagerOptions {
4
- /** Directory of database files. Scanned for known extensions; new DBs are created here. */
5
- dir?: string;
6
- /** Explicit database file paths or connection strings. */
7
- files?: string[];
8
- /** Named database connections map (e.g. { "mydb": "postgresql://...", "name1": "postgresql://..." }). */
9
- connections?: Record<string, string>;
10
- /** Open every managed database read-only (no writes, no create/delete of files). */
11
- readonly?: boolean;
12
- }
13
- export interface DatabaseEntry {
14
- /** Stable, URL-safe id (usually the file name or connection name, deduped on collision). */
15
- id: string;
16
- /** Name for display. */
17
- name: string;
18
- /** Path on disk or sanitized connection URI. */
19
- path: string;
20
- /** Database dialect (sqlite or postgres). */
21
- dialect: 'sqlite' | 'postgres';
22
- size: number;
23
- modified: string;
24
- /** Whether this specific database is opened in read-only mode. */
25
- readonly: boolean;
26
- }
27
- /**
28
- * Manages multiple SQLite database files and PostgreSQL database connections.
29
- *
30
- * Databases come from three sources:
31
- * - a `connections` map — named PostgreSQL or SQLite connection strings (e.g. from JSON config),
32
- * - a `dir` — every SQLite file with a known extension is scanned in,
33
- * - an explicit `files[]` array — specific file locations or connection strings.
34
- */
35
- export declare class DbManager {
36
- private logger;
37
- private dir?;
38
- private createDir;
39
- private readonly readonlyMode;
40
- private files;
41
- private idByPath;
42
- private pathById;
43
- private nameById;
44
- private readonlyById;
45
- private openDbs;
46
- constructor(options: DbManagerOptions | string, logger?: Logger);
47
- get directory(): string;
48
- /** True when this manager opens every database read-only. */
49
- get isReadOnly(): boolean;
50
- isDbFile(name: string): boolean;
51
- private registerConnections;
52
- private registerDirFiles;
53
- private registerExplicitFiles;
54
- private addNamedTarget;
55
- private addFile;
56
- /** List all managed databases (metadata only — does not open them). */
57
- list(): DatabaseEntry[];
58
- has(id: string): boolean;
59
- /** True if global manager is in readonly mode or this database is explicitly marked read-only. */
60
- isDbReadOnly(id: string): boolean;
61
- /** Set or toggle read-only mode for a specific database id. */
62
- setReadonly(id: string, readonly: boolean): void;
63
- /** Open (and cache) a database by id; creates the file if it is new SQLite database. */
64
- open(id: string, readonlyOverride?: boolean): IDatabase;
65
- /**
66
- * Register and open an existing database file by path, returning its id.
67
- * Used by the "Open an existing database" file browser. Validates that the
68
- * file is a readable SQLite database before keeping it registered.
69
- */
70
- openFile(absPath: string, readonly?: boolean): string;
71
- get(id: string): IDatabase | undefined;
72
- /** Count the tables in a database (opens it if necessary). */
73
- countTables(id: string): Promise<number>;
74
- /** Create a new (empty) SQLite database. Returns its id. */
75
- create(name: string): string;
76
- /** Dynamically register a named PostgreSQL or SQLite connection string. Returns its id. */
77
- addConnection(name: string, connectionString: string, readonly?: boolean): string;
78
- /** Close and delete a database file (including WAL/SHM sidecars). */
79
- remove(id: string): void;
80
- closeAll(): void;
81
- }
1
+ import type {IDatabase} from './types';import{type Logger} from '../utils/logger';export interface DbManagerOptions{dir?:string;files?:string[];connections?:Record<string,string>;readonly ?:boolean;}export interface DatabaseEntry{id:string;name:string;path:string;dialect:'sqlite'|'postgres';size:number;modified:string;readonly :boolean;}export declare class DbManager{private logger;private dir?;private createDir;private readonly readonlyMode;private files;private idByPath;private pathById;private nameById;private readonlyById;private openDbs;constructor(options:DbManagerOptions|string,logger?:Logger);get directory():string;get isReadOnly():boolean;isDbFile(name:string):boolean;private registerConnections;private registerDirFiles;private registerExplicitFiles;private addNamedTarget;private addFile;list():DatabaseEntry[];has(id:string):boolean;isDbReadOnly(id:string):boolean;setReadonly(id:string,readonly :boolean):void;open(id:string,readonlyOverride?:boolean):IDatabase;openFile(absPath:string,readonly ?:boolean):string;get(id:string):IDatabase|undefined;countTables(id:string):Promise<number>;create(name:string):string;addConnection(name:string,connectionString:string,readonly ?:boolean):string;remove(id:string):void;closeAll():void;}