admindb 2.2.1 → 2.3.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 (89) hide show
  1. package/README.md +368 -364
  2. package/dist/app.js +25 -16
  3. package/dist/auth/config.d.ts +1 -1
  4. package/dist/auth/config.js +18 -30
  5. package/dist/auth/crypto.js +11 -21
  6. package/dist/auth/middleware.js +9 -16
  7. package/dist/auth/routes.js +9 -15
  8. package/dist/cli/args.d.ts +1 -1
  9. package/dist/cli/args.js +20 -29
  10. package/dist/cli/config.d.ts +1 -1
  11. package/dist/cli/config.js +15 -18
  12. package/dist/cli/runner.js +13 -13
  13. package/dist/data/chain.d.ts +1 -1
  14. package/dist/data/chain.js +40 -617
  15. package/dist/data/datasets.d.ts +1 -1
  16. package/dist/data/datasets.js +43 -1
  17. package/dist/data/detector.js +45 -21
  18. package/dist/data/engine.d.ts +1 -1
  19. package/dist/data/engine.js +483 -142
  20. package/dist/data/index.d.ts +1 -1
  21. package/dist/data/index.js +8 -0
  22. package/dist/data/prng.d.ts +1 -0
  23. package/dist/data/prng.js +73 -0
  24. package/dist/data/registry.d.ts +1 -0
  25. package/dist/data/registry.js +805 -0
  26. package/dist/data/schema-graph.d.ts +1 -0
  27. package/dist/data/schema-graph.js +210 -0
  28. package/dist/data/strategies.d.ts +1 -1
  29. package/dist/data/strategies.js +44 -283
  30. package/dist/data/templates.d.ts +1 -0
  31. package/dist/data/templates.js +134 -0
  32. package/dist/data/types.d.ts +1 -1
  33. package/dist/data/validator.d.ts +1 -0
  34. package/dist/data/validator.js +160 -0
  35. package/dist/db/database.js +9 -14
  36. package/dist/db/export.js +32 -55
  37. package/dist/db/filters.d.ts +1 -1
  38. package/dist/db/filters.js +15 -38
  39. package/dist/db/introspection.js +4 -7
  40. package/dist/db/manager.d.ts +1 -1
  41. package/dist/db/manager.js +48 -53
  42. package/dist/db/migrations.js +7 -14
  43. package/dist/db/postgres.js +30 -78
  44. package/dist/index.d.ts +1 -1
  45. package/dist/public/css/app.css +1 -1
  46. package/dist/public/js/browse.js +1 -1
  47. package/dist/public/js/inspector.js +1 -1
  48. package/dist/public/js/query.js +1 -1
  49. package/dist/public/js/seed.js +1 -1
  50. package/dist/routes/api/erd.js +3 -8
  51. package/dist/routes/api/helpers.d.ts +1 -1
  52. package/dist/routes/api/helpers.js +75 -25
  53. package/dist/routes/api/import-export.js +1 -2
  54. package/dist/routes/api/query.js +2 -6
  55. package/dist/routes/api/rows.js +4 -8
  56. package/dist/routes/api/seed.js +35 -21
  57. package/dist/routes/api/tables.js +15 -30
  58. package/dist/routes/databases.js +8 -26
  59. package/dist/routes/pages.js +67 -18
  60. package/dist/serverless.js +31 -44
  61. package/dist/sql/generator.d.ts +1 -1
  62. package/dist/sql/generator.js +35 -109
  63. package/dist/types/api.d.ts +1 -1
  64. package/dist/utils/common.d.ts +1 -1
  65. package/dist/utils/common.js +45 -85
  66. package/dist/utils/csv.d.ts +1 -1
  67. package/dist/utils/csv.js +11 -17
  68. package/dist/utils/datatype.js +46 -60
  69. package/dist/utils/icons.js +8 -8
  70. package/dist/views/layouts/main.hbs +1 -87
  71. package/dist/views/pages/databases.hbs +1 -233
  72. package/dist/views/pages/designer.hbs +1 -89
  73. package/dist/views/pages/erd.hbs +1 -1241
  74. package/dist/views/pages/error.hbs +1 -10
  75. package/dist/views/pages/form.hbs +1 -59
  76. package/dist/views/pages/home.hbs +1 -220
  77. package/dist/views/pages/info.hbs +1 -107
  78. package/dist/views/pages/login.hbs +1 -98
  79. package/dist/views/pages/query.hbs +1 -129
  80. package/dist/views/pages/schema.hbs +1 -298
  81. package/dist/views/pages/seed-select.hbs +251 -0
  82. package/dist/views/pages/seed.hbs +256 -414
  83. package/dist/views/pages/table.hbs +1 -327
  84. package/dist/views/partials/navbar.hbs +1 -83
  85. package/dist/views/partials/sidebar.hbs +1 -129
  86. package/docs/API.md +149 -149
  87. package/docs/EXAMPLES.md +579 -579
  88. package/docs/SECURITY.md +265 -265
  89. package/package.json +80 -79
@@ -10,12 +10,14 @@ const database_1 = require("./database");
10
10
  const postgres_1 = require("./postgres");
11
11
  const logger_1 = require("../utils/logger");
12
12
  const common_1 = require("../utils/common");
13
+ const serverless_1 = require("../serverless");
13
14
  const DB_EXTENSIONS = ['.db', '.sqlite', '.sqlite3'];
14
15
  class DbManager {
15
16
  logger;
16
17
  dir;
17
18
  createDir;
18
19
  readonlyMode;
20
+ isServerless;
19
21
  files = [];
20
22
  idByPath = new Map();
21
23
  pathById = new Map();
@@ -27,12 +29,12 @@ class DbManager {
27
29
  this.logger = logger ?? (0, logger_1.createLogger)('info', 'admindb');
28
30
  this.dir = opts.dir ? node_path_1.default.resolve(opts.dir) : undefined;
29
31
  this.createDir = this.dir ?? process.cwd();
30
- this.readonlyMode = !!opts.readonly;
32
+ this.readonlyMode = Boolean(opts.readonly);
33
+ this.isServerless = opts.serverless !== undefined ? opts.serverless : (0, serverless_1.isServerlessEnvironment)();
31
34
  if (this.dir)
32
35
  (0, node_fs_1.mkdirSync)(this.dir, { recursive: true });
33
- if (opts.connections) {
36
+ if (opts.connections)
34
37
  this.registerConnections(opts.connections);
35
- }
36
38
  this.registerDirFiles();
37
39
  this.registerExplicitFiles(opts.files ?? []);
38
40
  }
@@ -48,28 +50,24 @@ class DbManager {
48
50
  }
49
51
  registerConnections(conns) {
50
52
  for (const [name, target] of Object.entries(conns ?? {})) {
51
- if (!name || !target)
52
- continue;
53
- const cleanTarget = String(target).trim();
54
- if (!cleanTarget)
55
- continue;
56
- this.addNamedTarget(name.trim(), cleanTarget);
53
+ const cleanTarget = String(target ?? '').trim();
54
+ if (name && cleanTarget)
55
+ this.addNamedTarget(name.trim(), cleanTarget);
57
56
  }
58
57
  }
59
58
  registerDirFiles() {
60
59
  if (!this.dir)
61
60
  return;
62
- let names = [];
63
61
  try {
64
- names = (0, node_fs_1.readdirSync)(this.dir)
62
+ const names = (0, node_fs_1.readdirSync)(this.dir)
65
63
  .filter((n) => this.isDbFile(n))
66
64
  .sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
65
+ for (const name of names)
66
+ this.addFile(node_path_1.default.join(this.dir, name));
67
67
  }
68
68
  catch (err) {
69
69
  this.logger.warn(`Failed to list database directory ${this.dir}: ${(0, common_1.errorMessage)(err)}`);
70
70
  }
71
- for (const name of names)
72
- this.addFile(node_path_1.default.join(this.dir, name));
73
71
  }
74
72
  registerExplicitFiles(files) {
75
73
  for (const f of files ?? []) {
@@ -79,12 +77,9 @@ class DbManager {
79
77
  if ((0, common_1.isPostgresConnectionString)(raw)) {
80
78
  let name = 'postgres';
81
79
  try {
82
- const u = new URL(raw);
83
- name = u.pathname.replace(/^\//, '') || 'postgres';
84
- }
85
- catch {
86
- name = 'postgres';
80
+ name = new URL(raw).pathname.replace(/^\//, '') || 'postgres';
87
81
  }
82
+ catch { }
88
83
  this.addNamedTarget(name, raw);
89
84
  continue;
90
85
  }
@@ -99,10 +94,8 @@ class DbManager {
99
94
  addNamedTarget(name, target) {
100
95
  let id = name;
101
96
  let n = 2;
102
- while (this.pathById.has(id)) {
103
- id = `${name}__${n}`;
104
- n += 1;
105
- }
97
+ while (this.pathById.has(id))
98
+ id = `${name}__${n++}`;
106
99
  this.files.push(target);
107
100
  this.idByPath.set(target, id);
108
101
  this.pathById.set(id, target);
@@ -116,9 +109,7 @@ class DbManager {
116
109
  let n = 2;
117
110
  while (this.pathById.has(id)) {
118
111
  const ext = node_path_1.default.extname(base);
119
- const stem = node_path_1.default.basename(base, ext);
120
- id = `${stem}__${n}${ext}`;
121
- n += 1;
112
+ id = `${node_path_1.default.basename(base, ext)}__${n++}${ext}`;
122
113
  }
123
114
  this.files.push(abs);
124
115
  this.idByPath.set(abs, id);
@@ -151,8 +142,7 @@ class DbManager {
151
142
  size = st.size;
152
143
  modified = st.mtime.toISOString();
153
144
  }
154
- catch {
155
- }
145
+ catch { }
156
146
  entries.push({
157
147
  id,
158
148
  name: this.nameById.get(id) ?? node_path_1.default.basename(target),
@@ -170,14 +160,29 @@ class DbManager {
170
160
  return this.pathById.has(id);
171
161
  }
172
162
  isDbReadOnly(id) {
173
- return this.readonlyMode || (this.readonlyById.get(id) ?? false);
163
+ if (this.readonlyMode)
164
+ return true;
165
+ if (this.readonlyById.has(id))
166
+ return Boolean(this.readonlyById.get(id));
167
+ if (this.isServerless) {
168
+ const target = this.pathById.get(id);
169
+ const isPg = target ? (0, common_1.isPostgresConnectionString)(target) : false;
170
+ return !isPg;
171
+ }
172
+ return false;
174
173
  }
175
174
  setReadonly(id, readonly) {
176
175
  if (this.readonlyMode && !readonly) {
177
176
  throw new Error('Manager is in global read-only mode — databases cannot be made writable.');
178
177
  }
179
- const current = this.readonlyById.get(id);
180
- if (current === readonly)
178
+ if (this.isServerless && !readonly) {
179
+ const target = this.pathById.get(id);
180
+ const isPg = target ? (0, common_1.isPostgresConnectionString)(target) : false;
181
+ if (!isPg) {
182
+ throw new Error('SQLite database cannot be made writable in a serverless environment.');
183
+ }
184
+ }
185
+ if (this.readonlyById.get(id) === readonly)
181
186
  return;
182
187
  this.readonlyById.set(id, readonly);
183
188
  const db = this.openDbs.get(id);
@@ -185,8 +190,7 @@ class DbManager {
185
190
  try {
186
191
  db.close();
187
192
  }
188
- catch {
189
- }
193
+ catch { }
190
194
  this.openDbs.delete(id);
191
195
  }
192
196
  }
@@ -194,24 +198,21 @@ class DbManager {
194
198
  const target = this.pathById.get(id);
195
199
  if (!target)
196
200
  throw new Error(`Database "${id}" is not registered.`);
197
- const isRo = this.readonlyMode || (readonlyOverride !== undefined ? readonlyOverride : (this.readonlyById.get(id) ?? false));
201
+ const isRo = readonlyOverride !== undefined ? readonlyOverride : this.isDbReadOnly(id);
198
202
  let db = this.openDbs.get(id);
199
203
  if (db && db.isReadOnly !== isRo) {
200
204
  try {
201
205
  db.close();
202
206
  }
203
- catch {
204
- }
207
+ catch { }
205
208
  this.openDbs.delete(id);
206
209
  db = undefined;
207
210
  }
208
211
  if (!db) {
209
- if ((0, common_1.isPostgresConnectionString)(target)) {
210
- db = new postgres_1.PostgresDatabase(target, this.logger.child(`db:${id}`), { readonly: isRo });
211
- }
212
- else {
213
- db = new database_1.SqliteDatabase(target, this.logger.child(`db:${id}`), { readonly: isRo });
214
- }
212
+ const childLogger = this.logger.child(`db:${id}`);
213
+ db = (0, common_1.isPostgresConnectionString)(target)
214
+ ? new postgres_1.PostgresDatabase(target, childLogger, { readonly: isRo })
215
+ : new database_1.SqliteDatabase(target, childLogger, { readonly: isRo });
215
216
  this.openDbs.set(id, db);
216
217
  }
217
218
  return db;
@@ -220,9 +221,8 @@ class DbManager {
220
221
  const abs = node_path_1.default.resolve(String(absPath ?? '').trim());
221
222
  if (!abs)
222
223
  throw new Error('Database path is required.');
223
- if (!(0, node_fs_1.existsSync)(abs) || !(0, node_fs_1.statSync)(abs).isFile()) {
224
+ if (!(0, node_fs_1.existsSync)(abs) || !(0, node_fs_1.statSync)(abs).isFile())
224
225
  throw new Error(`Not a file: ${abs}`);
225
- }
226
226
  const existing = this.idByPath.get(abs);
227
227
  if (existing) {
228
228
  if (readonly !== undefined)
@@ -253,8 +253,7 @@ class DbManager {
253
253
  }
254
254
  async countTables(id) {
255
255
  try {
256
- const db = this.open(id);
257
- const r = await db.listTables();
256
+ const r = await this.open(id).listTables();
258
257
  return r.success ? (r.data?.length ?? 0) : 0;
259
258
  }
260
259
  catch {
@@ -284,8 +283,7 @@ class DbManager {
284
283
  let cleanName = String(name ?? '').trim();
285
284
  if (!cleanName) {
286
285
  try {
287
- const u = new URL(raw);
288
- cleanName = u.pathname.replace(/^\//, '') || 'postgres';
286
+ cleanName = new URL(raw).pathname.replace(/^\//, '') || 'postgres';
289
287
  }
290
288
  catch {
291
289
  cleanName = 'postgres';
@@ -310,8 +308,7 @@ class DbManager {
310
308
  try {
311
309
  db.close();
312
310
  }
313
- catch {
314
- }
311
+ catch { }
315
312
  this.openDbs.delete(id);
316
313
  }
317
314
  this.pathById.delete(id);
@@ -324,8 +321,7 @@ class DbManager {
324
321
  try {
325
322
  (0, node_fs_1.unlinkSync)(target + suffix);
326
323
  }
327
- catch {
328
- }
324
+ catch { }
329
325
  }
330
326
  }
331
327
  }
@@ -334,8 +330,7 @@ class DbManager {
334
330
  try {
335
331
  db.close();
336
332
  }
337
- catch {
338
- }
333
+ catch { }
339
334
  }
340
335
  this.openDbs.clear();
341
336
  }
@@ -12,9 +12,8 @@ function modifyTableStructureSync(db, table, transformColumns, renamedOldCol, re
12
12
  for (const ix of indexRows) {
13
13
  if (ix.unique) {
14
14
  const ixCols = db.prepare(`PRAGMA index_info(${(0, generator_1.quoteIdentifier)(ix.name)})`).all().map((c) => c.name);
15
- if (ixCols.length === 1) {
15
+ if (ixCols.length === 1)
16
16
  uniqueCols.add(ixCols[0]);
17
- }
18
17
  }
19
18
  }
20
19
  const userIndexes = [];
@@ -32,7 +31,7 @@ function modifyTableStructureSync(db, table, transformColumns, renamedOldCol, re
32
31
  }
33
32
  userIndexes.push({
34
33
  name: ixName,
35
- unique: !!ix.unique,
34
+ unique: Boolean(ix.unique),
36
35
  columns: ixCols.map((c) => (renamedOldCol && renamedNewCol && c === renamedOldCol ? renamedNewCol : c)),
37
36
  });
38
37
  }
@@ -43,7 +42,7 @@ function modifyTableStructureSync(db, table, transformColumns, renamedOldCol, re
43
42
  name: c.name,
44
43
  type: c.type,
45
44
  primaryKey: c.pk > 0,
46
- notNull: !!c.notnull,
45
+ notNull: Boolean(c.notnull),
47
46
  unique: uniqueCols.has(c.name),
48
47
  defaultValue: c.dflt_value,
49
48
  foreignKey: existingFk ? { table: existingFk.table, column: existingFk.to ?? '' } : null,
@@ -56,17 +55,13 @@ function modifyTableStructureSync(db, table, transformColumns, renamedOldCol, re
56
55
  const matchingOldCols = [];
57
56
  const matchingNewCols = [];
58
57
  for (const nc of newCols) {
59
- let sourceColName = nc.name;
60
- if (renamedOldCol && renamedNewCol && nc.name === renamedNewCol) {
61
- sourceColName = renamedOldCol;
62
- }
58
+ const sourceColName = renamedOldCol && renamedNewCol && nc.name === renamedNewCol ? renamedOldCol : nc.name;
63
59
  if (oldColMap.has(sourceColName)) {
64
60
  matchingOldCols.push((0, generator_1.quoteIdentifier)(sourceColName));
65
61
  matchingNewCols.push((0, generator_1.quoteIdentifier)(nc.name));
66
62
  }
67
63
  }
68
- db.exec('PRAGMA foreign_keys = OFF;');
69
- db.exec('BEGIN TRANSACTION;');
64
+ db.exec('PRAGMA foreign_keys = OFF;\nBEGIN TRANSACTION;');
70
65
  try {
71
66
  db.exec(createSql);
72
67
  if (matchingOldCols.length > 0) {
@@ -80,11 +75,9 @@ function modifyTableStructureSync(db, table, transformColumns, renamedOldCol, re
80
75
  try {
81
76
  db.exec(`CREATE ${uq}INDEX IF NOT EXISTS ${(0, generator_1.quoteIdentifier)(ix.name)} ON ${(0, generator_1.quoteIdentifier)(table)} (${ixColsStr});`);
82
77
  }
83
- catch {
84
- }
78
+ catch { }
85
79
  }
86
- const fkCheck = db.prepare('PRAGMA foreign_key_check;').all();
87
- if (fkCheck.length > 0) {
80
+ if (db.prepare('PRAGMA foreign_key_check;').all().length > 0) {
88
81
  throw new Error('Foreign key constraint check failed after schema modification.');
89
82
  }
90
83
  db.exec('COMMIT;');
@@ -30,21 +30,17 @@ class PostgresDatabase {
30
30
  if (sslMode === 'disable') {
31
31
  sslConfig = false;
32
32
  }
33
- else if (sslConfig === undefined) {
34
- if (sslMode === 'require' || sslMode === 'prefer' || sslMode === 'no-verify' || !isLocal) {
35
- sslConfig = { rejectUnauthorized: false };
36
- }
33
+ else if (sslConfig === undefined && (sslMode === 'require' || sslMode === 'prefer' || sslMode === 'no-verify' || !isLocal)) {
34
+ sslConfig = { rejectUnauthorized: false };
37
35
  }
38
36
  }
39
- catch {
40
- }
37
+ catch { }
41
38
  }
42
39
  else if (opts.host && sslConfig === undefined) {
43
40
  const host = opts.host.toLowerCase();
44
41
  const isLocal = host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '0.0.0.0';
45
- if (!isLocal) {
42
+ if (!isLocal)
46
43
  sslConfig = { rejectUnauthorized: false };
47
- }
48
44
  }
49
45
  const poolConfig = {
50
46
  connectionString: opts.connectionString,
@@ -86,8 +82,7 @@ class PostgresDatabase {
86
82
  }
87
83
  async tryRun(fn) {
88
84
  try {
89
- const data = await fn();
90
- return { success: true, data };
85
+ return { success: true, data: await fn() };
91
86
  }
92
87
  catch (err) {
93
88
  const msg = (0, common_1.errorMessage)(err);
@@ -109,8 +104,7 @@ class PostgresDatabase {
109
104
  try {
110
105
  await client.query('ROLLBACK');
111
106
  }
112
- catch {
113
- }
107
+ catch { }
114
108
  const msg = (0, common_1.errorMessage)(err);
115
109
  this.logger.error(msg);
116
110
  return { success: false, error: msg };
@@ -120,15 +114,14 @@ class PostgresDatabase {
120
114
  }
121
115
  }
122
116
  async initSchema() {
123
- const sql = `
117
+ await this.pool.query(`
124
118
  CREATE TABLE IF NOT EXISTS ${(0, generator_1.quoteIdentifier)(types_1.INTERNAL_TABLES.savedQueries)} (
125
119
  id SERIAL PRIMARY KEY,
126
120
  name VARCHAR(255) NOT NULL UNIQUE,
127
121
  sql TEXT NOT NULL,
128
122
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
129
123
  );
130
- `;
131
- await this.pool.query(sql);
124
+ `);
132
125
  }
133
126
  hasMultipleStatements(sql) {
134
127
  const s = String(sql ?? '').trim();
@@ -145,18 +138,15 @@ class PostgresDatabase {
145
138
  }
146
139
  inString = !inString;
147
140
  }
148
- else if (ch === ';' && !inString) {
149
- const rest = s.slice(i + 1).trim();
150
- if (rest.length > 0)
151
- count++;
141
+ else if (ch === ';' && !inString && s.slice(i + 1).trim().length > 0) {
142
+ count++;
152
143
  }
153
144
  }
154
145
  return count > 0;
155
146
  }
156
147
  async all(sql, params = []) {
157
148
  return this.tryRun(async () => {
158
- const pgSql = (0, filters_1.convertPlaceholdersToPostgres)(sql);
159
- const res = await this.pool.query(pgSql, params);
149
+ const res = await this.pool.query((0, filters_1.convertPlaceholdersToPostgres)(sql), params);
160
150
  return res.rows;
161
151
  });
162
152
  }
@@ -164,12 +154,8 @@ class PostgresDatabase {
164
154
  if (this.isReadOnly)
165
155
  return this.readonlyBlocked();
166
156
  return this.tryRun(async () => {
167
- const pgSql = (0, filters_1.convertPlaceholdersToPostgres)(sql);
168
- const res = await this.pool.query(pgSql, params);
169
- return {
170
- changes: res.rowCount ?? 0,
171
- lastInsertRowid: null,
172
- };
157
+ const res = await this.pool.query((0, filters_1.convertPlaceholdersToPostgres)(sql), params);
158
+ return { changes: res.rowCount ?? 0, lastInsertRowid: null };
173
159
  });
174
160
  }
175
161
  async execResult(sql) {
@@ -184,15 +170,7 @@ class PostgresDatabase {
184
170
  });
185
171
  }
186
172
  async runWrite(sql) {
187
- if (this.isReadOnly)
188
- return this.readonlyBlocked();
189
- return this.tryRun(async () => {
190
- const res = await this.pool.query(sql);
191
- const changes = Array.isArray(res)
192
- ? res.reduce((acc, r) => acc + (r.rowCount ?? 0), 0)
193
- : res.rowCount ?? undefined;
194
- return { changes };
195
- });
173
+ return this.execResult(sql);
196
174
  }
197
175
  async listTables() {
198
176
  return this.tryRun(async () => {
@@ -293,7 +271,6 @@ class PostgresDatabase {
293
271
  if (primaryKey.length) {
294
272
  colDefs.push(` PRIMARY KEY (${primaryKey.map(generator_1.quoteIdentifier).join(', ')})`);
295
273
  }
296
- const synthesizedSql = `CREATE TABLE ${(0, generator_1.quoteIdentifier)(table)} (\n${colDefs.join(',\n')}\n);`;
297
274
  return {
298
275
  table,
299
276
  columns,
@@ -308,7 +285,7 @@ class PostgresDatabase {
308
285
  })),
309
286
  primaryKey,
310
287
  indexes,
311
- sql: synthesizedSql,
288
+ sql: `CREATE TABLE ${(0, generator_1.quoteIdentifier)(table)} (\n${colDefs.join(',\n')}\n);`,
312
289
  };
313
290
  });
314
291
  }
@@ -321,8 +298,7 @@ class PostgresDatabase {
321
298
  pgWhere = (0, filters_1.convertPlaceholdersToPostgres)(where);
322
299
  params = p;
323
300
  }
324
- const sql = `SELECT COUNT(*) AS c FROM ${(0, generator_1.quoteIdentifier)(table)}${pgWhere}`;
325
- const res = await this.pool.query(sql, params);
301
+ const res = await this.pool.query(`SELECT COUNT(*) AS c FROM ${(0, generator_1.quoteIdentifier)(table)}${pgWhere}`, params);
326
302
  return Number(res.rows[0]?.c ?? 0);
327
303
  });
328
304
  }
@@ -342,12 +318,10 @@ class PostgresDatabase {
342
318
  }
343
319
  const nextParamIdx = filterParams.length + 1;
344
320
  let sql = `SELECT * FROM ${(0, generator_1.quoteIdentifier)(table)}${pgWhere}`;
345
- if (orderCol) {
321
+ if (orderCol)
346
322
  sql += ` ORDER BY ${(0, generator_1.quoteIdentifier)(orderCol)} ${orderDir}`;
347
- }
348
323
  sql += ` LIMIT $${nextParamIdx} OFFSET $${nextParamIdx + 1}`;
349
- const allParams = [...filterParams, limit, offset];
350
- const res = await this.pool.query(sql, allParams);
324
+ const res = await this.pool.query(sql, [...filterParams, limit, offset]);
351
325
  return res.rows;
352
326
  });
353
327
  }
@@ -373,10 +347,7 @@ class PostgresDatabase {
373
347
  const placeholders = fields.map((_, idx) => `$${idx + 1}`);
374
348
  const sql = `INSERT INTO ${(0, generator_1.quoteIdentifier)(table)} (${cols.join(', ')}) VALUES (${placeholders.join(', ')}) RETURNING *`;
375
349
  const res = await this.pool.query(sql, fields.map((f) => f.value));
376
- return {
377
- changes: res.rowCount ?? 1,
378
- lastInsertRowid: null,
379
- };
350
+ return { changes: res.rowCount ?? 1, lastInsertRowid: null };
380
351
  });
381
352
  }
382
353
  async insertRows(table, rows) {
@@ -402,10 +373,7 @@ class PostgresDatabase {
402
373
  const conds = where.map((w, idx) => `${(0, generator_1.quoteIdentifier)(w.column)} = $${fields.length + idx + 1}`);
403
374
  const sql = `UPDATE ${(0, generator_1.quoteIdentifier)(table)} SET ${sets.join(', ')} WHERE ${conds.join(' AND ')}`;
404
375
  const res = await this.pool.query(sql, [...fields.map((f) => f.value), ...where.map((w) => w.value)]);
405
- return {
406
- changes: res.rowCount ?? 0,
407
- lastInsertRowid: null,
408
- };
376
+ return { changes: res.rowCount ?? 0, lastInsertRowid: null };
409
377
  });
410
378
  }
411
379
  async updateRows(table, rows) {
@@ -430,10 +398,7 @@ class PostgresDatabase {
430
398
  const conds = where.map((w, idx) => `${(0, generator_1.quoteIdentifier)(w.column)} = $${idx + 1}`);
431
399
  const sql = `DELETE FROM ${(0, generator_1.quoteIdentifier)(table)} WHERE ${conds.join(' AND ')}`;
432
400
  const res = await this.pool.query(sql, where.map((w) => w.value));
433
- return {
434
- changes: res.rowCount ?? 0,
435
- lastInsertRowid: null,
436
- };
401
+ return { changes: res.rowCount ?? 0, lastInsertRowid: null };
437
402
  });
438
403
  }
439
404
  async deleteRows(table, rows) {
@@ -494,19 +459,13 @@ class PostgresDatabase {
494
459
  async saveQuery(name, sql) {
495
460
  return this.tryRun(async () => {
496
461
  const res = await this.pool.query(`INSERT INTO ${(0, generator_1.quoteIdentifier)(types_1.INTERNAL_TABLES.savedQueries)} (name, sql) VALUES ($1, $2) RETURNING id`, [name, sql]);
497
- return {
498
- changes: res.rowCount ?? 1,
499
- lastInsertRowid: Number(res.rows[0]?.id ?? null),
500
- };
462
+ return { changes: res.rowCount ?? 1, lastInsertRowid: Number(res.rows[0]?.id ?? null) };
501
463
  });
502
464
  }
503
465
  async deleteSavedQuery(id) {
504
466
  return this.tryRun(async () => {
505
467
  const res = await this.pool.query(`DELETE FROM ${(0, generator_1.quoteIdentifier)(types_1.INTERNAL_TABLES.savedQueries)} WHERE id = $1`, [Number(id)]);
506
- return {
507
- changes: res.rowCount ?? 0,
508
- lastInsertRowid: null,
509
- };
468
+ return { changes: res.rowCount ?? 0, lastInsertRowid: null };
510
469
  });
511
470
  }
512
471
  async getSettings() {
@@ -515,11 +474,10 @@ class PostgresDatabase {
515
474
  const settings = {};
516
475
  try {
517
476
  const res = await this.pool.query(`SELECT name, setting FROM pg_settings WHERE name = ANY($1::text[])`, [keys]);
518
- for (const row of res.rows) {
477
+ for (const row of res.rows)
519
478
  settings[row.name] = String(row.setting);
520
- }
521
479
  }
522
- catch (err) {
480
+ catch {
523
481
  try {
524
482
  const ver = await this.pool.query('SHOW server_version');
525
483
  settings['server_version'] = String(ver.rows[0]?.server_version);
@@ -610,11 +568,7 @@ class PostgresDatabase {
610
568
  for (const [tbl, refs] of byTable.entries()) {
611
569
  try {
612
570
  const countRes = await this.pool.query(`SELECT COUNT(*) AS c FROM ${(0, generator_1.quoteIdentifier)(tbl)} WHERE ${refs.map((r) => `${(0, generator_1.quoteIdentifier)(r.from)} IS NOT NULL`).join(' OR ')}`);
613
- results.push({
614
- table: tbl,
615
- refs,
616
- refCount: Number(countRes.rows[0]?.c ?? 0),
617
- });
571
+ results.push({ table: tbl, refs, refCount: Number(countRes.rows[0]?.c ?? 0) });
618
572
  }
619
573
  catch {
620
574
  results.push({ table: tbl, refs, refCount: 0 });
@@ -669,12 +623,10 @@ class PostgresDatabase {
669
623
  await this.pool.query(`ALTER TABLE ${(0, generator_1.quoteIdentifier)(table)} ALTER COLUMN ${(0, generator_1.quoteIdentifier)(colToModify)} ${action};`);
670
624
  }
671
625
  if (newColDef.defaultValue !== undefined) {
672
- if (newColDef.defaultValue === null || newColDef.defaultValue === '') {
673
- await this.pool.query(`ALTER TABLE ${(0, generator_1.quoteIdentifier)(table)} ALTER COLUMN ${(0, generator_1.quoteIdentifier)(colToModify)} DROP DEFAULT;`);
674
- }
675
- else {
676
- await this.pool.query(`ALTER TABLE ${(0, generator_1.quoteIdentifier)(table)} ALTER COLUMN ${(0, generator_1.quoteIdentifier)(colToModify)} SET DEFAULT ${newColDef.defaultValue};`);
677
- }
626
+ const action = newColDef.defaultValue === null || newColDef.defaultValue === ''
627
+ ? 'DROP DEFAULT'
628
+ : `SET DEFAULT ${newColDef.defaultValue}`;
629
+ await this.pool.query(`ALTER TABLE ${(0, generator_1.quoteIdentifier)(table)} ALTER COLUMN ${(0, generator_1.quoteIdentifier)(colToModify)} ${action};`);
678
630
  }
679
631
  if (newColDef.unique !== undefined) {
680
632
  const idxName = `idx_${table}_${colToModify}_unique`;
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export{createRouter,type AppOptions} from './app';export{createLogger,type Logger,type LogLevel} from './utils/logger';export{c,supportsColor} from './utils/colors';export{SqliteDatabase,PostgresDatabase,type IDatabase,type DatabaseDialect,type PostgresOptions,type MutationResult,type QueryOptions,type Result,type TableInfoData,type ColumnInfo,type ForeignKeyInfo,type WhereClause,type IndexInfo,type SchemaInfo,type ColumnDetail,type SavedQuery,type RowFilters,type FilterCondition,type FilterValue,type SQLInputValue,} from './db/index';export{DbManager,type DbManagerOptions,type DatabaseEntry} from './db/manager';export{type ColumnDef,type IndexDef,} from './sql/generator';export{type ColumnPlan,type ColumnGeneratorConfig,type GeneratorStrategyId,type StrategyDescriptor,type GenerateResult,} from './data/index';export{type AuthConfig,type ResolvedAuthConfig,resolveAuthConfig,getOrCreatePersistentSecret,createSessionToken,verifySessionToken,parseCookies,constantTimeCompare,hashPassword,verifyPassword,DEFAULT_USERNAME,DEFAULT_PASSWORD_HASH,SESSION_COOKIE_NAME,} from './auth/index';export{isServerlessEnvironment,createServerlessHandler,createLambdaHandler,type LambdaProxyResult,} from './serverless';export{sniffMimeType,generateHexDump,analyzeBlob,isJsonString,formatJsonSafely,type MimeAnalysis,type HexDumpLine,type HexDumpResult,type BlobMetadata,} from './utils/datatype';export * from './types/api';
1
+ export{createRouter,type AppOptions} from './app';export{createLogger,type Logger,type LogLevel} from './utils/logger';export{c,supportsColor} from './utils/colors';export{SqliteDatabase,PostgresDatabase,type IDatabase,type DatabaseDialect,type PostgresOptions,type MutationResult,type QueryOptions,type Result,type TableInfoData,type ColumnInfo,type ForeignKeyInfo,type WhereClause,type IndexInfo,type SchemaInfo,type ColumnDetail,type SavedQuery,type RowFilters,type FilterCondition,type FilterValue,type SQLInputValue} from './db/index';export{DbManager,type DbManagerOptions,type DatabaseEntry} from './db/manager';export{type ColumnDef,type IndexDef} from './sql/generator';export{type ColumnPlan,type ColumnGeneratorConfig,type GeneratorStrategyId,type StrategyDescriptor,type GenerateResult} from './data/index';export{type AuthConfig,type ResolvedAuthConfig,resolveAuthConfig,getOrCreatePersistentSecret,createSessionToken,verifySessionToken,parseCookies,constantTimeCompare,hashPassword,verifyPassword,DEFAULT_USERNAME,DEFAULT_PASSWORD_HASH,SESSION_COOKIE_NAME} from './auth/index';export{isServerlessEnvironment,createServerlessHandler,createLambdaHandler,type LambdaProxyResult} from './serverless';export{sniffMimeType,generateHexDump,analyzeBlob,isJsonString,formatJsonSafely,type MimeAnalysis,type HexDumpLine,type HexDumpResult,type BlobMetadata} from './utils/datatype';export * from './types/api';