Skip to content

Commit

Permalink
Show table size for postgresql and mysql (#213)
Browse files Browse the repository at this point in the history
* todo: schema/database

* prevent postgres

* database schema

* change: schema database

* change: create schema database from tab to use dialog

* update: schema database

* show table size at sidebar

* add table size for postgresql

---------

Co-authored-by: sokphaladam <[email protected]>
  • Loading branch information
invisal and sokphaladam authored Dec 20, 2024
1 parent 2290c72 commit 3030106
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 26 deletions.
15 changes: 14 additions & 1 deletion src/app/storybook/listview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ function Demo1() {
name: "movies",
key: "movies.movies",
icon: LucideTable,
progressBarLabel: "1.3GB",
progressBarValue: 9050,
progressBarMax: 10000,
},
{
name: "users",
badgeContent: "fts5",
badgeClassName: "bg-red-500 text-white",
key: "movies.users",
progressBarLabel: "1.5KB",
progressBarValue: 1500,
progressBarMax: 10000,
icon: LucideTable,
children: [
{
Expand All @@ -54,7 +60,14 @@ function Demo1() {
},
],
},
{ name: "reviews", key: "movies.reviews", icon: LucideTable },
{
name: "reviews",
key: "movies.reviews",
icon: LucideTable,
progressBarLabel: "256KB",
progressBarValue: 5550,
progressBarMax: 10000,
},
],
},
{
Expand Down
61 changes: 46 additions & 15 deletions src/components/gui/schema-sidebar-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,25 @@ interface SchemaListProps {
search: string;
}

function formatTableSize(byteCount?: number) {
const byteInKb = 1024;
const byteInMb = byteInKb * 1024;
const byteInGb = byteInMb * 1024;

if (!byteCount) return undefined;
if (byteInMb * 999 < byteCount)
return (byteCount / byteInGb).toFixed(1) + " GB";
if (byteInMb * 100 < byteCount)
return (byteCount / byteInMb).toFixed(0) + " MB";
if (byteInKb * 100 < byteCount)
return (byteCount / byteInMb).toFixed(1) + " MB";
if (byteInKb < byteCount) return Math.floor(byteCount / byteInKb) + " KB";
return "1 KB";
}

function prepareListViewItem(
schema: DatabaseSchemaItem[]
schema: DatabaseSchemaItem[],
maxTableSize: number
): ListViewItem<DatabaseSchemaItem>[] {
return schema.map((s) => {
let icon = Table;
Expand All @@ -34,6 +51,9 @@ function prepareListViewItem(
iconColor: iconClassName,
key: s.schemaName + "." + s.name,
name: s.name,
progressBarMax: maxTableSize,
progressBarValue: s.tableSchema?.stats?.sizeInByte,
progressBarLabel: formatTableSize(s.tableSchema?.stats?.sizeInByte),
};
});
}
Expand Down Expand Up @@ -121,11 +141,11 @@ export default function SchemaList({ search }: Readonly<SchemaListProps>) {
const isTable = item?.type === "table";

return [
item?.type === 'schema' && {
title: 'Edit',
item?.type === "schema" && {
title: "Edit",
onClick: () => {
setEditSchema(item.schemaName);
}
},
},
{
title: "Copy Name",
Expand All @@ -146,15 +166,15 @@ export default function SchemaList({ search }: Readonly<SchemaListProps>) {
},
isTable && databaseDriver.getFlags().supportCreateUpdateTable
? {
title: "Edit Table",
onClick: () => {
openTab({
tableName: item?.name,
type: "schema",
schemaName: item?.schemaName ?? "",
});
},
}
title: "Edit Table",
onClick: () => {
openTab({
tableName: item?.name,
type: "schema",
schemaName: item?.schemaName ?? "",
});
},
}
: undefined,
databaseDriver.getFlags().supportCreateUpdateTable
? { separator: true }
Expand All @@ -168,14 +188,20 @@ export default function SchemaList({ search }: Readonly<SchemaListProps>) {
const listViewItems = useMemo(() => {
const r = sortTable(
Object.entries(schema).map(([s, tables]) => {
const maxTableSize = Math.max(
...tables.map((t) => t.tableSchema?.stats?.sizeInByte ?? 0)
);

return {
data: { type: "schema", schemaName: s },
icon: LucideDatabase,
name: s,
iconBadgeColor: s === currentSchemaName ? "bg-green-600" : undefined,
key: s.toString(),
children: sortTable(
groupByFtsTable(groupTriggerByTable(prepareListViewItem(tables)))
groupByFtsTable(
groupTriggerByTable(prepareListViewItem(tables, maxTableSize))
)
),
} as ListViewItem<DatabaseSchemaItem>;
})
Expand All @@ -199,7 +225,12 @@ export default function SchemaList({ search }: Readonly<SchemaListProps>) {

return (
<>
{editSchema && <SchemaCreateDialog schemaName={editSchema} onClose={() => setEditSchema(null)} />}
{editSchema && (
<SchemaCreateDialog
schemaName={editSchema}
onClose={() => setEditSchema(null)}
/>
)}
<ListView
full
filter={filterCallback}
Expand Down
26 changes: 25 additions & 1 deletion src/components/listview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export interface ListViewItem<T = unknown> {
badgeContent?: string;
badgeClassName?: string;
children?: ListViewItem<T>[];
progressBarValue?: number;
progressBarMax?: number;
progressBarLabel?: string;
}

interface ListViewProps<T> {
Expand Down Expand Up @@ -224,7 +227,7 @@ function renderList<T>(props: ListViewRendererProps<T>): React.ReactElement {
</div>
)}

<div className="text-xs line-clamp-1">
<div className="text-xs line-clamp-1 flex-1">
<Highlight text={item.name} highlight={highlight} />
{item.badgeContent && (
<span
Expand All @@ -237,6 +240,27 @@ function renderList<T>(props: ListViewRendererProps<T>): React.ReactElement {
</span>
)}
</div>

{item.progressBarValue && item.progressBarMax && (
<div className="w-[50px] h-full flex items-center relative text-muted-foreground">
<div
className="dark:bg-gray-800 dark:border-gray-700 bg-gray-100 rounded-sm h-[20px] border border-gray-200"
style={{
width:
Math.max(
Math.ceil(
(item.progressBarValue / item.progressBarMax) *
100
),
5
) + "%",
}}
></div>
<span className="absolute right-0">
{item.progressBarLabel}
</span>
</div>
)}
</div>
</div>
{isCollapsed &&
Expand Down
5 changes: 5 additions & 0 deletions src/drivers/base-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ export interface DatabaseTableFts5 {
contentRowId?: string;
}

export interface DatabaseTableSchemaStats {
sizeInByte?: number;
estimateRowCount?: number;
}
export interface DatabaseTableSchema {
columns: DatabaseTableColumn[];
pk: string[];
Expand All @@ -156,6 +160,7 @@ export interface DatabaseTableSchema {
type?: "table" | "view";
withoutRowId?: boolean;
strict?: boolean;
stats?: DatabaseTableSchemaStats
}

export type TriggerWhen = "BEFORE" | "AFTER" | "INSTEAD_OF";
Expand Down
21 changes: 13 additions & 8 deletions src/drivers/mysql/mysql-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ interface MySqlTable {
TABLE_SCHEMA: string;
TABLE_NAME: string;
TABLE_TYPE: string;
INDEX_LENGTH: number;
DATA_LENGTH: number;
}

interface MySQLConstraintResult {
Expand Down Expand Up @@ -157,7 +159,7 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {
.rows as unknown as MySqlDatabase[];

const tableSql =
"SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM information_schema.tables WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";
"SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, DATA_LENGTH, INDEX_LENGTH FROM information_schema.tables WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";
const tableResult = (await this.query(tableSql))
.rows as unknown as MySqlTable[];

Expand Down Expand Up @@ -191,6 +193,9 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {
tableName: t.TABLE_NAME,
schemaName: t.TABLE_SCHEMA,
tableSchema: {
stats: {
sizeInByte: t.DATA_LENGTH + t.INDEX_LENGTH
},
autoIncrement: false,
pk: [],
columns: [],
Expand Down Expand Up @@ -345,13 +350,13 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {
foreignKey:
constraint.CONSTRAINT_TYPE === "FOREIGN KEY"
? {
columns: columnList.map((c) => c.COLUMN_NAME),
foreignColumns: columnList.map(
(c) => c.REFERENCED_COLUMN_NAME
),
foreignSchemaName: columnList[0].REFERENCED_TABLE_SCHEMA,
foreignTableName: columnList[0].REFERENCED_TABLE_NAME,
}
columns: columnList.map((c) => c.COLUMN_NAME),
foreignColumns: columnList.map(
(c) => c.REFERENCED_COLUMN_NAME
),
foreignSchemaName: columnList[0].REFERENCED_TABLE_SCHEMA,
foreignTableName: columnList[0].REFERENCED_TABLE_NAME,
}
: undefined,
};
}
Expand Down
6 changes: 5 additions & 1 deletion src/drivers/postgres/postgres-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface PostgresTableRow {
table_schema: string;
table_name: string;
table_type: string;
table_size: number;
}

interface PostgresColumnRow {
Expand Down Expand Up @@ -92,7 +93,7 @@ export default abstract class PostgresLikeDriver extends CommonSQLImplement {

const tableResult = (
await this.query(
"SELECT * FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog', 'pg_toast') AND table_type = 'BASE TABLE';"
"SELECT *, pg_total_relation_size(quote_ident(table_schema) || '.' || quote_ident(table_name)) AS table_size FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog', 'pg_toast') AND table_type = 'BASE TABLE';"
)
).rows as unknown as PostgresTableRow[];

Expand Down Expand Up @@ -145,6 +146,9 @@ WHERE
type: table.table_type === "BASE TABLE" ? "table" : "view",
tableName: table.table_name,
tableSchema: {
stats: {
sizeInByte: table.table_size,
},
columns: [],
constraints: [],
pk: [],
Expand Down

0 comments on commit 3030106

Please sign in to comment.