@devmoods/postgres-admin 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,6 +32,8 @@ var getDisplayType = (dbType) => {
32
32
  case "timestamp without time zone":
33
33
  case "timestamp with time zone":
34
34
  return "datetime";
35
+ case "interval":
36
+ return "duration";
35
37
  case "integer":
36
38
  case "numeric":
37
39
  case "smallint":
@@ -128,7 +130,7 @@ function toJsonSchema(table) {
128
130
  }
129
131
  async function getTable(tableId) {
130
132
  if (!tableCache.has(tableId)) {
131
- const tables = await readTables();
133
+ const { tables } = await readTables();
132
134
  for (const table of tables) {
133
135
  tableCache.set(table.tableName, table);
134
136
  }
@@ -140,8 +142,9 @@ async function getTable(tableId) {
140
142
  return value;
141
143
  }
142
144
  async function readTables() {
145
+ const connectionString = readEnv("POSTGRES_URL");
143
146
  const structure = await pgStructure({
144
- connectionString: readEnv("POSTGRES_URL")
147
+ connectionString
145
148
  });
146
149
  const toMetadata = (column) => ({
147
150
  type: getPrimitiveType(column.type.name),
@@ -165,11 +168,11 @@ async function readTables() {
165
168
  };
166
169
  });
167
170
  };
168
- const result = [];
171
+ const tables = [];
169
172
  for (const table of structure.tables) {
170
173
  const belongsTo = toBelongsTo(table);
171
174
  const columnsArray = table.columns.mapToArray((column) => column);
172
- result.push({
175
+ tables.push({
173
176
  tableName: table.name,
174
177
  primaryKey: table.primaryKey?.columns.at(0)?.name ?? null,
175
178
  belongsTo,
@@ -181,7 +184,10 @@ async function readTables() {
181
184
  schema: toJsonSchema(table)
182
185
  });
183
186
  }
184
- return result;
187
+ return {
188
+ databaseName: new URL(connectionString).pathname,
189
+ tables
190
+ };
185
191
  }
186
192
 
187
193
  // src/api/utils.ts
@@ -205,6 +211,18 @@ function queryParamToArray(queryParam) {
205
211
  }
206
212
  return [];
207
213
  }
214
+ function counter() {
215
+ const values = {};
216
+ return {
217
+ get: (key) => {
218
+ if (!(key in values)) {
219
+ values[key] = 0;
220
+ }
221
+ values[key]++;
222
+ return values[key];
223
+ }
224
+ };
225
+ }
208
226
 
209
227
  // src/api/app.ts
210
228
  function createRouter({
@@ -220,7 +238,7 @@ function createRouter({
220
238
  app.get(
221
239
  "/api/tables",
222
240
  route(async () => {
223
- const tables = await readTables();
241
+ const { databaseName, tables } = await readTables();
224
242
  const rowCounts = Object.fromEntries(
225
243
  await Promise.all(
226
244
  tables.map(async (table) => {
@@ -232,6 +250,7 @@ function createRouter({
232
250
  )
233
251
  );
234
252
  return {
253
+ databaseName,
235
254
  tables,
236
255
  rowCounts
237
256
  };
@@ -298,18 +317,7 @@ function createRouter({
298
317
  }).map(async (t) => [t, await getTable(t)])
299
318
  )
300
319
  );
301
- const aliasCounter = /* @__PURE__ */ (() => {
302
- const values = {};
303
- return {
304
- get: (key) => {
305
- if (!(key in values)) {
306
- values[key] = 0;
307
- }
308
- values[key]++;
309
- return values[key];
310
- }
311
- };
312
- })();
320
+ const aliasCounter = counter();
313
321
  const joins = [];
314
322
  for (const column of definition.columnNames) {
315
323
  const metadata = definition.columnMetadata[column];
@@ -326,11 +334,16 @@ function createRouter({
326
334
  );
327
335
  }
328
336
  joins.push(
329
- sql`LEFT JOIN ${sql.identifier(fkTable)} ${sql.identifier(alias)} ON ${sql.identifier(alias)}.${sql.identifier(fkColumn)} = ${sql.identifier(table)}.${sql.identifier(column)}`
337
+ sql`
338
+ LEFT JOIN ${sql.identifier(fkTable)} ${sql.identifier(alias)}
339
+ ON ${sql.identifier(alias)}.${sql.identifier(fkColumn)} = ${sql.identifier(table)}.${sql.identifier(column)}`
330
340
  );
331
341
  }
332
342
  }
333
- const statement = sql`SELECT ${joinStatements(fieldsToSelect, ", ")} FROM ${sql.identifier(table)} ${joinStatements(joins, " ")}`;
343
+ const statement = sql`
344
+ SELECT ${joinStatements(fieldsToSelect, ", ")}
345
+ FROM ${sql.identifier(table)} ${joinStatements(joins, " ")}
346
+ `;
334
347
  if (search && search.length > 2) {
335
348
  statement.append(" WHERE ");
336
349
  statement.append(
@@ -371,10 +384,10 @@ function createRouter({
371
384
  throw BadRequest(`Table ${table} has no primary key`);
372
385
  }
373
386
  const statement = sql`
374
- SELECT *
375
- FROM ${sql.identifier(table)}
376
- WHERE ${sql.identifier(primaryKey)} = ${req.params.pk}
377
- `;
387
+ SELECT *
388
+ FROM ${sql.identifier(table)}
389
+ WHERE ${sql.identifier(primaryKey)} = ${req.params.pk}
390
+ `;
378
391
  return postgres.first(statement);
379
392
  })
380
393
  );
@@ -389,9 +402,9 @@ function createRouter({
389
402
  }
390
403
  const { [primaryKey]: pk, ...data } = req.body;
391
404
  const statement = sql`
392
- INSERT INTO ${sql.identifier(table)}
393
- ${sql.spreadInsert(data)}
394
- `;
405
+ INSERT INTO ${sql.identifier(table)}
406
+ ${sql.spreadInsert(data)}
407
+ `;
395
408
  return postgres.first(statement);
396
409
  })
397
410
  );
@@ -405,18 +418,27 @@ function createRouter({
405
418
  if (!primaryKey) {
406
419
  throw BadRequest(`Table ${table} has no primary key`);
407
420
  }
421
+ const updatedAtColumns = definition.columnNames.filter(
422
+ (c) => ["updated_at", "modified_time"].includes(c)
423
+ );
424
+ const data = {
425
+ ...req.body
426
+ };
427
+ for (const updateAtColumn of updatedAtColumns) {
428
+ data[updateAtColumn] = sql.raw("NOW()");
429
+ }
408
430
  return await postgres.transaction(async (tx) => {
409
431
  await postgres.get(sql`
410
- SELECT * FROM ${sql.identifier(table)}
411
- WHERE ${sql.identifier(primaryKey)} = ${req.params.pk}
412
- FOR UPDATE
413
- `);
432
+ SELECT * FROM ${sql.identifier(table)}
433
+ WHERE ${sql.identifier(primaryKey)} = ${req.params.pk}
434
+ FOR UPDATE
435
+ `);
414
436
  return tx.get(sql`
415
- UPDATE ${sql.identifier(table)}
416
- SET ${sql.spreadUpdate(req.body)}
417
- WHERE ${sql.identifier(primaryKey)} = ${pk}
418
- RETURNING *
419
- `);
437
+ UPDATE ${sql.identifier(table)}
438
+ SET ${sql.spreadUpdate(data)}
439
+ WHERE ${sql.identifier(primaryKey)} = ${pk}
440
+ RETURNING *
441
+ `);
420
442
  });
421
443
  })
422
444
  );
@@ -431,9 +453,9 @@ function createRouter({
431
453
  throw BadRequest(`Table ${table} has no primary key`);
432
454
  }
433
455
  const statement = sql`
434
- DELETE FROM ${sql.identifier(table)}
435
- WHERE ${sql.identifier(primaryKey)} = ${pk}
436
- `;
456
+ DELETE FROM ${sql.identifier(table)}
457
+ WHERE ${sql.identifier(primaryKey)} = ${pk}
458
+ `;
437
459
  await postgres.query(statement);
438
460
  return 204;
439
461
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devmoods/postgres-admin",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -11,7 +11,7 @@
11
11
  "clean": "rm -rf dist",
12
12
  "build:server": "tsup-node src/index.ts --format esm --dts",
13
13
  "build:client": "tsc --noEmit && vite build",
14
- "build": "pnpm run build:server && pnpm run build:client",
14
+ "build": "pnpm run build:client && pnpm run build:server",
15
15
  "test": "vitest"
16
16
  },
17
17
  "dependencies": {
@@ -24,25 +24,27 @@
24
24
  "devDependencies": {
25
25
  "@bitiforms/adapter-devmoods-ui": "^0.12.0",
26
26
  "@bitiforms/react": "^0.12.0",
27
+ "@devmoods/express-extras": "^0.49.3",
27
28
  "@devmoods/fetch": "^4.0.1",
28
- "@devmoods/ui": "^2.5.0",
29
- "@tanstack/react-query": "^5.62.8",
30
- "@types/react": "^19.0.2",
31
- "@types/react-dom": "^19.0.2",
29
+ "@devmoods/ui": "^2.7.2",
30
+ "@tanstack/react-query": "^5.64.1",
31
+ "@types/react": "^19.0.7",
32
+ "@types/react-dom": "^19.0.3",
32
33
  "@vitejs/plugin-react": "^4.3.4",
33
- "@vitest/coverage-v8": "2.1.8",
34
+ "@vitest/coverage-v8": "3.0.1",
35
+ "babel-plugin-react-compiler": "19.0.0-beta-e552027-20250112",
34
36
  "dotenv": "^16.4.7",
35
37
  "express": "^4.21.2",
36
38
  "react": "^19.0.0",
37
39
  "react-dom": "^19.0.0",
38
40
  "react-fast-compare": "^3.2.2",
39
41
  "react-icons": "^5.4.0",
40
- "react-router": "^7.0.2",
41
- "sass": "^1.83.0",
42
+ "react-router": "^7.1.2",
43
+ "sass": "^1.83.4",
42
44
  "tsup": "^8.3.5",
43
- "vite": "^6.0.5",
44
- "vitest": "^2.1.8",
45
- "zustand": "^5.0.2"
45
+ "vite": "^6.0.7",
46
+ "vitest": "^3.0.1",
47
+ "zustand": "^5.0.3"
46
48
  },
47
- "gitHead": "2d07a60de638850bc0bcf124f711f9ea9e75f23c"
49
+ "gitHead": "af37872764b25c4a71e9f09cc822b85e3ff99310"
48
50
  }