From 5d1658c52201c28b84bb9de29d4f6267499cfe54 Mon Sep 17 00:00:00 2001 From: andres Date: Sun, 7 Jul 2024 01:40:04 +0200 Subject: [PATCH] refactor table details queries (indexes, foreign_keys, columns) --- api/src/index.ts | 87 ++++++++++--------- .../components/db-table-view/data-table.tsx | 2 +- .../db/$dbName/tables/$tableName/index.tsx | 13 +-- frontend/src/services/db/db.hooks.ts | 37 +++++--- frontend/src/services/db/db.service.ts | 27 +++--- frontend/src/services/db/db.types.ts | 17 ++++ 6 files changed, 117 insertions(+), 66 deletions(-) diff --git a/api/src/index.ts b/api/src/index.ts index ae8be75..76bef49 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -5,7 +5,7 @@ import postgres from "postgres"; const DB_URL = Bun.env.DB_URL; if (!DB_URL) { - console.error("DB_URL not found in environment variables"); + console.error("❗DB_URL not found in environment variables"); process.exit(1); } @@ -28,34 +28,46 @@ const app = new Elysia({ prefix: "/api" }) return new Response(JSON.stringify(tables, null, 2)).json(); }) - .get("databases/:dbName/tables/:name/data", async ({ params, query }) => { - const { name, dbName } = params; - const { perPage = "50", page = "0" } = query; - return getTableData({ - tableName: name, - dbName, - perPage: Number.parseInt(perPage, 10), - page: Number.parseInt(page, 10), - }); - }) - .get("db/tables/:name/columns", async ({ params, query }) => { - const { name } = params; + .get( + "databases/:dbName/tables/:tableName/data", + async ({ params, query }) => { + const { tableName, dbName } = params; + const { perPage = "50", page = "0" } = query; + return getTableData({ + tableName, + dbName, + perPage: Number.parseInt(perPage, 10), + page: Number.parseInt(page, 10), + }); + }, + ) + .get( + "databases/:dbName/tables/:tableName/columns", + async ({ params, query }) => { + const { tableName, dbName } = params; - const columns = await getColumns(name); - return new Response(JSON.stringify(columns, null, 2)).json(); - }) - .get("db/tables/:name/indexes", async ({ params, query }) => { - const { name } = params; + const columns = await getColumns(dbName, tableName); + return new Response(JSON.stringify(columns, null, 2)).json(); + }, + ) + .get( + "databases/:dbName/tables/:tableName/indexes", + async ({ params, query }) => { + const { tableName, dbName } = params; - const indexes = await getIndexes(name); - return new Response(JSON.stringify(indexes, null, 2)).json(); - }) - .get("db/tables/:name/foreign-keys", async ({ params, query }) => { - const { name } = params; + const indexes = await getIndexes(dbName, tableName); + return new Response(JSON.stringify(indexes, null, 2)).json(); + }, + ) + .get( + "databases/:dbName/tables/:tableName/foreign-keys", + async ({ params, query }) => { + const { tableName, dbName } = params; - const foreignKeys = await getForeignKeys(name); - return new Response(JSON.stringify(foreignKeys, null, 2)).json(); - }) + const foreignKeys = await getForeignKeys(dbName, tableName); + return new Response(JSON.stringify(foreignKeys, null, 2)).json(); + }, + ) .use(cors()) .listen(3000); @@ -63,13 +75,12 @@ console.log( `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`, ); -async function getIndexes(table: string) { - const returnObj = {}; - +async function getIndexes(dbName: string, tableName: string) { const [tableOidResult] = await sql` SELECT oid - FROM pg_class - WHERE relname = ${table} + FROM pg_class + WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = ${dbName}) + AND relname = ${tableName} `; const tableOid = tableOidResult.oid; @@ -114,7 +125,7 @@ async function getIndexes(table: string) { }); } -async function getColumns(tableName: string) { +async function getColumns(dbName: string, tableName: string) { return await sql` SELECT cols.column_name, @@ -129,12 +140,14 @@ async function getColumns(tableName: string) { pg_catalog.pg_description AS pgd ON pgd.objoid = st.relid AND pgd.objsubid = cols.ordinal_position WHERE cols.table_name = ${tableName} + AND cols.table_schema = ${dbName} + ORDER BY cols.ordinal_position; `; } -async function getForeignKeys(table: string) { +async function getForeignKeys(dbName: string, tableName: string) { const result = await sql` SELECT conname, @@ -147,7 +160,8 @@ async function getForeignKeys(table: string) { SELECT pc.oid FROM pg_class AS pc INNER JOIN pg_namespace AS pn ON (pn.oid = pc.relnamespace) - WHERE pc.relname = ${table} + WHERE pc.relname = ${tableName} + AND pn.nspname = ${dbName} ) AND contype = 'f'::char ORDER BY conkey, conname @@ -157,10 +171,6 @@ async function getForeignKeys(table: string) { const match = row.definition.match( /FOREIGN KEY\s*\((.+)\)\s*REFERENCES (.+)\((.+)\)(.*)$/iy, ); - console.log(match); - console.log("match[0]", match[0]); - console.log("match[1]", match[1]); - console.log("match[2]", match[2]); if (match) { const sourceColumns = match[1] .split(",") @@ -168,7 +178,6 @@ async function getForeignKeys(table: string) { const targetTableMatch = match[2].match( /^(("([^"]|"")+"|[^"]+)\.)?"?("([^"]|"")+"|[^"]+)$/, ); - console.log("targetTableMatch", targetTableMatch); const targetTable = targetTableMatch ? targetTableMatch[0].trim() : null; const targetColumns = match[3] .split(",") diff --git a/frontend/src/components/db-table-view/data-table.tsx b/frontend/src/components/db-table-view/data-table.tsx index fee3541..9ebd621 100644 --- a/frontend/src/components/db-table-view/data-table.tsx +++ b/frontend/src/components/db-table-view/data-table.tsx @@ -48,7 +48,7 @@ export const DataTable = ({ onPageIndexChange: (pageIndex: number) => void; onPageSizeChange: (pageSize: number) => void; }) => { - const { data: details } = useTableColumnsQuery({ name: tableName }); + const { data: details } = useTableColumnsQuery({ dbName, tableName }); const { data } = useTableDataQuery({ tableName, dbName, diff --git a/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx b/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx index 853ea1c..cd96424 100644 --- a/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx +++ b/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx @@ -79,17 +79,20 @@ const tableForeignKeysColumns = [ ]; function TableDetailsTable() { - const { tableName: name } = Route.useParams(); - const { data: tableColumns } = useTableColumnsQuery({ name }); - const { data: tableIndexes } = useTableIndexesQuery({ name }); - const { data: tableForeignKeys } = useTableForeignKeysQuery({ name }); + const { tableName, dbName } = Route.useParams(); + const { data: tableColumns } = useTableColumnsQuery({ tableName, dbName }); + const { data: tableIndexes } = useTableIndexesQuery({ tableName, dbName }); + const { data: tableForeignKeys } = useTableForeignKeysQuery({ + tableName, + dbName, + }); return (

- {name} + {tableName}

{ return useQuery({ @@ -38,27 +44,36 @@ export const useTableDataQuery = (args: GetTableDataArgs) => { }); }; -export const useTableColumnsQuery = (args: { name?: string }) => { +export const useTableColumnsQuery = (args: GetTableColumnsArgs) => { return useQuery({ queryKey: [DB_QUERY_KEYS.TABLES.COLUMNS, args], - queryFn: () => dbService.getTableColumns(args.name ?? ""), - placeholderData: keepPreviousData, - enabled: !!args.name, + queryFn: () => dbService.getTableColumns(args), + placeholderData: (previousData, previousQuery) => { + if ( + typeof previousQuery?.queryKey[1] !== "string" && + (previousQuery?.queryKey[1].dbName !== args.dbName || + previousQuery?.queryKey[1].tableName !== args.tableName) + ) { + return undefined; + } + return previousData; + }, + enabled: !!args.tableName && !!args.dbName, }); }; -export const useTableIndexesQuery = (args: { name?: string }) => { +export const useTableIndexesQuery = (args: GetTableIndexesArgs) => { return useQuery({ queryKey: [DB_QUERY_KEYS.TABLES.INDEXES, args], - queryFn: () => dbService.getTableIndexes(args.name ?? ""), - enabled: !!args.name, + queryFn: () => dbService.getTableIndexes(args), + enabled: !!args.tableName && !!args.dbName, }); }; -export const useTableForeignKeysQuery = (args: { name?: string }) => { +export const useTableForeignKeysQuery = (args: GetTableForeignKeysArgs) => { return useQuery({ queryKey: [DB_QUERY_KEYS.TABLES.FOREIGN_KEYS, args], - queryFn: () => dbService.getTableForeignKeys(args.name ?? ""), - enabled: !!args.name, + queryFn: () => dbService.getTableForeignKeys(args), + enabled: !!args.tableName && !!args.dbName, }); }; diff --git a/frontend/src/services/db/db.service.ts b/frontend/src/services/db/db.service.ts index 439e31d..bb45104 100644 --- a/frontend/src/services/db/db.service.ts +++ b/frontend/src/services/db/db.service.ts @@ -2,8 +2,11 @@ import { getValuable } from "@/lib/utils"; import { dbInstance } from "@/services/db/db.instance"; import type { DatabasesResponse, + GetTableColumnsArgs, GetTableDataArgs, GetTableDataResponse, + GetTableForeignKeysArgs, + GetTableIndexesArgs, GetTablesListArgs, GetTablesListResponse, TableColumns, @@ -32,17 +35,21 @@ class DbService { .json(); } - getTableColumns(name: string) { - return dbInstance.get(`api/db/tables/${name}/columns`).json(); - } - - getTableIndexes(name: string) { - return dbInstance.get(`api/db/tables/${name}/indexes`).json(); - } - - getTableForeignKeys(name: string) { + getTableColumns({ dbName, tableName }: GetTableColumnsArgs) { return dbInstance - .get(`api/db/tables/${name}/foreign-keys`) + .get(`api/databases/${dbName}/tables/${tableName}/columns`) + .json(); + } + + getTableIndexes({ dbName, tableName }: GetTableIndexesArgs) { + return dbInstance + .get(`api/databases/${dbName}/tables/${tableName}/indexes`) + .json(); + } + + getTableForeignKeys({ dbName, tableName }: GetTableForeignKeysArgs) { + return dbInstance + .get(`api/databases/${dbName}/tables/${tableName}/foreign-keys`) .json(); } } diff --git a/frontend/src/services/db/db.types.ts b/frontend/src/services/db/db.types.ts index e714f4e..79f9a1c 100644 --- a/frontend/src/services/db/db.types.ts +++ b/frontend/src/services/db/db.types.ts @@ -33,6 +33,12 @@ export type GetTableDataResponse = { data: Array>; }; +// Table Columns +export type GetTableColumnsArgs = { + tableName: string; + dbName: string; +}; + export type TableColumn = { column_name: string; data_type: string; @@ -41,6 +47,12 @@ export type TableColumn = { }; export type TableColumns = TableColumn[]; +// Table Indexes +export type GetTableIndexesArgs = { + tableName: string; + dbName: string; +}; + export type TableIndexEntry = { key: string; type: string; @@ -50,6 +62,11 @@ export type TableIndexEntry = { }; export type TableIndexes = TableIndexEntry[]; +// Table Foreign Keys +export type GetTableForeignKeysArgs = { + tableName: string; + dbName: string; +}; export type TableForeignKey = { conname: string; deferrable: boolean;