@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/client/.vite/manifest.json +11 -0
- package/dist/client/_index.html +2 -2
- package/dist/client/assets/index-Bt3yyG-e.css +1 -0
- package/dist/client/assets/index-d5ZRUuNE.js +87 -0
- package/dist/client/assets/index-d5ZRUuNE.js.map +1 -0
- package/dist/index.js +61 -39
- package/package.json +15 -13
- package/dist/client/assets/index-BLwsC3n4.js +0 -78
- package/dist/client/assets/index-BPI_MtFs.css +0 -1
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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`
|
|
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`
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
393
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
|
|
435
|
-
|
|
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.
|
|
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:
|
|
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.
|
|
29
|
-
"@tanstack/react-query": "^5.
|
|
30
|
-
"@types/react": "^19.0.
|
|
31
|
-
"@types/react-dom": "^19.0.
|
|
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": "
|
|
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.
|
|
41
|
-
"sass": "^1.83.
|
|
42
|
+
"react-router": "^7.1.2",
|
|
43
|
+
"sass": "^1.83.4",
|
|
42
44
|
"tsup": "^8.3.5",
|
|
43
|
-
"vite": "^6.0.
|
|
44
|
-
"vitest": "^
|
|
45
|
-
"zustand": "^5.0.
|
|
45
|
+
"vite": "^6.0.7",
|
|
46
|
+
"vitest": "^3.0.1",
|
|
47
|
+
"zustand": "^5.0.3"
|
|
46
48
|
},
|
|
47
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "af37872764b25c4a71e9f09cc822b85e3ff99310"
|
|
48
50
|
}
|