Skip to content

Commit 8c11f14

Browse files
committed
refactor(database): update Database type definition and enhance System interface with parts property
1 parent ade1c55 commit 8c11f14

5 files changed

Lines changed: 72 additions & 82 deletions

File tree

apps/desktop/src/entities/connection/dialects/clickhouse/schema/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ import type { WithSchema } from '../../../utils/types'
22
import type { InformationSchema } from './information'
33
import type { System } from './system'
44

5-
export type Database = WithSchema<InformationSchema, 'information_schema'> & WithSchema<System, 'system'>
5+
export type Database = WithSchema<InformationSchema, 'information_schema'>
6+
& WithSchema<System, 'system'>

apps/desktop/src/entities/connection/dialects/clickhouse/schema/system.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
export interface System {
66
columns: Columns
7+
parts: Parts
78
}
89

910
/**
@@ -16,3 +17,14 @@ interface Columns {
1617
name: string
1718
is_in_primary_key: number
1819
}
20+
21+
/**
22+
* @name parts
23+
* @type table
24+
*/
25+
interface Parts {
26+
database: string
27+
table: string
28+
rows: number
29+
active: number
30+
}

apps/desktop/src/entities/connection/dialects/postgres/schema/catalog.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ interface PgClass {
2929
relname: string
3030
relnamespace: number
3131
relkind: string
32+
reltuples: number
3233
}
3334

3435
/**

apps/desktop/src/entities/connection/sql/total.ts

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { buildWhere } from './rows'
66

77
export const totalQuery = createQuery({
88
type: type({
9-
count: 'string',
9+
count: 'number',
1010
isEstimated: 'boolean',
1111
}),
1212
query: ({
@@ -24,50 +24,43 @@ export const totalQuery = createQuery({
2424
if (!exact && !filters?.length) {
2525
const estimate = await db
2626
.withSchema('pg_catalog')
27-
.withTables<{
28-
pg_class: { reltuples: number, relname: string, relnamespace: number }
29-
pg_namespace: { oid: number, nspname: string }
30-
}>()
31-
.selectFrom('pg_class')
32-
.innerJoin('pg_namespace', 'pg_namespace.oid', 'pg_class.relnamespace')
33-
.select('pg_class.reltuples as count')
34-
.where('pg_namespace.nspname', '=', schema)
35-
.where('pg_class.relname', '=', table)
27+
.selectFrom('pg_catalog.pg_class')
28+
.innerJoin('pg_catalog.pg_namespace', 'pg_catalog.pg_namespace.oid', 'pg_catalog.pg_class.relnamespace')
29+
.select('pg_catalog.pg_class.reltuples as count')
30+
.where('pg_catalog.pg_namespace.nspname', '=', schema)
31+
.where('pg_catalog.pg_class.relname', '=', table)
3632
.executeTakeFirst()
3733

38-
if (estimate && Number(estimate.count) >= 0) {
34+
if (estimate && estimate.count >= 0) {
3935
return {
40-
count: String(Math.round(Number(estimate.count))),
36+
count: Math.round(estimate.count),
4137
isEstimated: true,
4238
}
4339
}
4440
}
41+
4542
const query = await db
4643
.withSchema(schema)
4744
.withTables<{ [table]: Record<string, unknown> }>()
4845
.selectFrom(table)
4946
.select(db.fn.countAll().as('total'))
5047
.$if(filters !== undefined, qb => qb.where(eb => buildWhere(eb, filters!)))
51-
.execute()
48+
.executeTakeFirst()
5249

53-
return { count: String(query[0]?.total ?? 0), isEstimated: false }
50+
return { count: Number(query?.total ?? 0), isEstimated: false }
5451
},
55-
5652
mysql: async (db) => {
5753
if (!exact && !filters?.length) {
5854
const estimate = await db
5955
.withSchema('information_schema')
60-
.withTables<{
61-
TABLES: { TABLE_SCHEMA: string, TABLE_NAME: string, TABLE_ROWS: number }
62-
}>()
63-
.selectFrom('TABLES')
56+
.selectFrom('information_schema.TABLES')
6457
.select('TABLE_ROWS as count')
6558
.where('TABLE_SCHEMA', '=', schema)
6659
.where('TABLE_NAME', '=', table)
6760
.executeTakeFirst()
6861

69-
if (estimate && Number(estimate.count) >= 0) {
70-
return { count: String(estimate.count), isEstimated: true }
62+
if (estimate && estimate.count >= 0) {
63+
return { count: estimate.count, isEstimated: true }
7164
}
7265
}
7366

@@ -77,9 +70,9 @@ export const totalQuery = createQuery({
7770
.selectFrom(table)
7871
.select(db.fn.countAll().as('total'))
7972
.$if(filters !== undefined, qb => qb.where(eb => buildWhere(eb, filters!)))
80-
.execute()
73+
.executeTakeFirst()
8174

82-
return { count: String(query[0]?.total ?? 0), isEstimated: false }
75+
return { count: Number(query?.total ?? 0), isEstimated: false }
8376
},
8477

8578
mssql: async (db) => {
@@ -89,10 +82,10 @@ export const totalQuery = createQuery({
8982
.selectFrom(table)
9083
.select(db.fn.countAll().as('total'))
9184
.$if(filters !== undefined, qb => qb.where(eb => buildWhere(eb, filters!)))
92-
.execute()
85+
.executeTakeFirst()
9386

9487
return {
95-
count: String(query[0]?.total ?? 0),
88+
count: Number(query?.total ?? 0),
9689
isEstimated: false,
9790
}
9891
},
@@ -101,18 +94,15 @@ export const totalQuery = createQuery({
10194
if (!exact && !filters?.length) {
10295
const estimate = await db
10396
.withSchema('system')
104-
.withTables<{
105-
parts: { database: string, table: string, rows: number, active: number }
106-
}>()
107-
.selectFrom('parts')
97+
.selectFrom('system.parts')
10898
.select(db.fn.sum(sql.ref('rows')).as('count'))
10999
.where('database', '=', schema)
110100
.where('table', '=', table)
111101
.where('active', '=', 1)
112102
.executeTakeFirst()
113103

114104
if (estimate && Number(estimate.count) >= 0) {
115-
return { count: String(estimate.count), isEstimated: true }
105+
return { count: Number(estimate.count), isEstimated: true }
116106
}
117107
}
118108

@@ -122,9 +112,9 @@ export const totalQuery = createQuery({
122112
.selectFrom(table)
123113
.select(db.fn.countAll().as('total'))
124114
.$if(filters !== undefined, qb => qb.where(eb => buildWhere(eb, filters!)))
125-
.execute()
115+
.executeTakeFirst()
126116

127-
return { count: String(query[0]?.total ?? 0), isEstimated: false }
117+
return { count: Number(query?.total ?? 0), isEstimated: false }
128118
},
129119
}),
130120
})

apps/desktop/src/routes/_protected/database/$id/table/-components/header/header.tsx

Lines changed: 35 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Separator } from '@conar/ui/components/separator'
2+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@conar/ui/components/tooltip'
23
import { cn } from '@conar/ui/lib/utils'
34
import NumberFlow from '@number-flow/react'
45
import { useStore } from '@tanstack/react-store'
@@ -20,45 +21,6 @@ export function Header({ table, schema }: { table: string, schema: string }) {
2021

2122
const columnsCount = columns?.length ?? 0
2223
const count = Number(total?.count)
23-
let countDisplay
24-
if (isLoading || !total) {
25-
countDisplay = <span className="animate-pulse text-[11px] opacity-50">...</span>
26-
}
27-
else if (!Number.isFinite(count)) {
28-
countDisplay = <span className="text-[11px] text-muted-foreground"></span>
29-
}
30-
else {
31-
countDisplay = (
32-
<span className="inline-flex items-center gap-1 font-medium">
33-
<NumberFlow
34-
value={count}
35-
format={{ notation: 'compact', compactDisplay: 'short', maximumFractionDigits: 1 }}
36-
className="font-semibold text-muted-foreground tabular-nums"
37-
/>
38-
<span className="text-muted-foreground">
39-
{count === 1 ? 'row' : 'rows'}
40-
</span>
41-
42-
{total.isEstimated && (
43-
<span className="font-normal text-muted-foreground opacity-60">
44-
(estimated)
45-
</span>
46-
)}
47-
<button
48-
type="button"
49-
className={cn(`
50-
ml-2 rounded-sm border px-1.5 py-0.5 text-[10px] font-normal
51-
text-muted-foreground transition-colors
52-
hover:bg-muted/30
53-
`)}
54-
onClick={() => setExact(v => !v)}
55-
title={exact ? 'Show estimated count' : 'Show exact count'}
56-
>
57-
{exact ? 'Show estimate' : 'Exact count'}
58-
</button>
59-
</span>
60-
)
61-
}
6224

6325
return (
6426
<div className="flex w-full items-center justify-between gap-6">
@@ -73,16 +35,40 @@ export function Header({ table, schema }: { table: string, schema: string }) {
7335
{' '}
7436
<span data-mask>{table}</span>
7537
</h2>
76-
<p className="text-xs text-muted-foreground">
77-
<span className="tabular-nums">{columnsCount}</span>
78-
{' '}
79-
column
80-
{columnsCount === 1 ? '' : 's'}
81-
{' '}
82-
83-
{' '}
84-
{countDisplay}
85-
</p>
38+
<div className="flex items-center gap-2 text-xs text-muted-foreground">
39+
<span>
40+
<span className="tabular-nums">{columnsCount}</span>
41+
{' '}
42+
column
43+
{columnsCount === 1 ? '' : 's'}
44+
</span>
45+
<Separator orientation="vertical" className="h-3!" />
46+
<TooltipProvider>
47+
<Tooltip>
48+
<TooltipTrigger
49+
className={cn('inline-flex items-center gap-1', !exact && total?.isEstimated && `
50+
cursor-pointer
51+
`)}
52+
onClick={() => setExact(true)}
53+
>
54+
<NumberFlow
55+
value={count}
56+
format={{ notation: 'compact', compactDisplay: 'short', maximumFractionDigits: 1 }}
57+
className={cn('text-muted-foreground tabular-nums', isLoading && `
58+
animate-pulse
59+
`)}
60+
prefix={total?.isEstimated ? '~' : ''}
61+
suffix={count === 1 ? ' row' : ' rows'}
62+
/>
63+
</TooltipTrigger>
64+
{!exact && total?.isEstimated && (
65+
<TooltipContent side="bottom">
66+
Click to get the exact count.
67+
</TooltipContent>
68+
)}
69+
</Tooltip>
70+
</TooltipProvider>
71+
</div>
8672
</div>
8773
<Separator orientation="vertical" className="h-6!" />
8874
<HeaderSearch table={table} schema={schema} />

0 commit comments

Comments
 (0)