Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
2d8bf02
feat: adds indexes and constraints page
Rudra-Sankha-Sinhamahapatra Dec 27, 2025
30e13ba
fix: handling rendering
Rudra-Sankha-Sinhamahapatra Dec 27, 2025
c85bcf6
fix: handling rendering
Rudra-Sankha-Sinhamahapatra Dec 27, 2025
6078a7a
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
ada5552
refactor: using snake_case instead of CamelCase on sql query names
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
f950a34
refactor: placing interfaces on appropriate files
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
58519d1
refactor: using types on dialects
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
906ffe5
refactor: using ...data
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
9627f92
feat: added filters & refresh button on pages
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
92c9c01
refactor: codes with required changes
Rudra-Sankha-Sinhamahapatra Dec 28, 2025
f4e73e1
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 3, 2026
b8a7755
fix: conflicts
Rudra-Sankha-Sinhamahapatra Jan 4, 2026
930eaad
fix: merge with main
Rudra-Sankha-Sinhamahapatra Jan 5, 2026
b33d546
refactor: placing constraints & inside inside a single page with a le…
Rudra-Sankha-Sinhamahapatra Jan 5, 2026
5711563
fix: merge conflicts
Rudra-Sankha-Sinhamahapatra Jan 6, 2026
fe92a2c
chore: merge with main
Rudra-Sankha-Sinhamahapatra Jan 8, 2026
ce2e142
refactor: remove exports
Rudra-Sankha-Sinhamahapatra Jan 8, 2026
eb79119
refactor: required changes
Rudra-Sankha-Sinhamahapatra Jan 8, 2026
ee7cb6e
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 8, 2026
510e459
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 9, 2026
5ecd6dd
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 16, 2026
ab620c0
feat(database): add lastOpenedDefinition to database store type
letstri Jan 16, 2026
b524696
refactor: moved enums inside definitions
Rudra-Sankha-Sinhamahapatra Jan 17, 2026
b7f31e5
fix: keeping definitions sidebar and main component inside a single b…
Rudra-Sankha-Sinhamahapatra Jan 17, 2026
29fd2eb
fix: primary key showcase on index page
Rudra-Sankha-Sinhamahapatra Jan 17, 2026
dbafca3
fix: spacing between item1 on item2 inside constraints page
Rudra-Sankha-Sinhamahapatra Jan 17, 2026
51ee045
refactor: putting filters below the headers
Rudra-Sankha-Sinhamahapatra Jan 17, 2026
bde1d2c
fix: gap inside select
Rudra-Sankha-Sinhamahapatra Jan 17, 2026
4a6aee5
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 18, 2026
9a4b598
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 18, 2026
f0a995e
fix: lint errors
Rudra-Sankha-Sinhamahapatra Jan 19, 2026
c3fb3bd
fix: lint errors
Rudra-Sankha-Sinhamahapatra Jan 19, 2026
692216b
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 19, 2026
fa6b84b
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 19, 2026
6414d9f
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 19, 2026
837b37e
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 20, 2026
c656748
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 21, 2026
12a8bb6
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 21, 2026
179626d
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 23, 2026
6ec397f
fix: made definitions sidebar as same as tables page
Rudra-Sankha-Sinhamahapatra Jan 23, 2026
96e8c27
feat: adds tabs for recentlyOpenedDefinitions inside definitions page
Rudra-Sankha-Sinhamahapatra Jan 23, 2026
2c71786
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 23, 2026
faa994c
refactor(definitions): streamline definitions page layout
letstri Jan 24, 2026
b38d009
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 24, 2026
3e6699b
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 24, 2026
7e1d4ca
refactor: simplify
letstri Jan 24, 2026
767bf48
feat: adds skeleton
Rudra-Sankha-Sinhamahapatra Jan 24, 2026
9b34996
Merge branch 'feat/index-page' of https://github.com/wannabespace/con…
Rudra-Sankha-Sinhamahapatra Jan 24, 2026
040e0e7
fix: added skeleton on refetching also
Rudra-Sankha-Sinhamahapatra Jan 24, 2026
ef4c49f
refactor: simplify label showing
Rudra-Sankha-Sinhamahapatra Jan 24, 2026
b7df028
refactor: add MOTION_BLOCK_PROPS for consistent animation settings
letstri Jan 24, 2026
7ec925a
Merge branch 'feat/index-page' of https://github.com/wannabespace/con…
letstri Jan 24, 2026
586b58b
refactor: definitions
letstri Jan 25, 2026
c580251
feat: enhance DefinitionsHeader with refresh functionality and add Se…
letstri Jan 25, 2026
c86d9dd
feat: update routing and sidebar for enums, adjust layout spacing in …
letstri Jan 25, 2026
7cb4257
feat: update icons and improve layout for database constraints, enums…
letstri Jan 25, 2026
954ff05
feat: enhance database constraints and indexes pages with highlighted…
letstri Jan 25, 2026
3e0302d
refactor: update connection store type and clean up definitions layout
letstri Jan 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface System {
* @name columns
* @type table
*/
interface Columns {
export interface Columns {
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
database: string
table: string
name: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* @name indexes
* @type table
*/
export interface SysIndexes {
object_id: number
index_id: number
name: string
is_unique: boolean
is_primary_key: boolean
}

/**
* @name tables
* @type table
*/
export interface SysTables {
object_id: number
schema_id: number
name: string
}

/**
* @name schemas
* @type table
*/
export interface SysSchemas {
schema_id: number
name: string
}

/**
* @name index_columns
* @type table
*/
export interface SysIndexColumns {
object_id: number
index_id: number
column_id: number
}

/**
* @name columns
* @type table
*/
export interface SysColumns {
object_id: number
column_id: number
name: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @name statistics
* @type table
*/

export interface MysqlStatistics {
TABLE_SCHEMA: string
TABLE_NAME: string
INDEX_NAME: string
COLUMN_NAME: string
NON_UNIQUE: number
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import type { PgNamespace } from './indexes'

/**
* @name pg_catalog
* @type schema
*/
export interface PgCatalog {
pg_namespace: PgNamespace
}

/**
* @name pg_namespace
* @type table
*/
interface PgNamespace {
oid: number
nspname: string
nspowner: number
nspacl: string | null
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @name pg_namespace
* @type table
*/
export interface PgNamespace {
oid: number
nspname: string
nspowner: number
nspacl: string | null
}

/**
* @name pg_class
* @type table
*/
export interface PgClass {
oid: number
relname: string
relnamespace: number
relkind: string
}

/**
* @name pg_index
* @type table
*/
export interface PgIndex {
indrelid: number
indexrelid: number
indkey: unknown
indisunique: boolean
indisprimary: boolean
}

/**
* @name pg_attribute
* @type table
*/
export interface PgAttribute {
attrelid: number
attnum: number
attname: string
}
2 changes: 2 additions & 0 deletions apps/desktop/src/entities/database/index.ts
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './lib/last-opened-databases'
export * from './queries/columns'
export * from './queries/constraints'
export * from './queries/enums'
export * from './queries/indexes'
export * from './queries/rows'
export * from './queries/tables-and-schemas'
export * from './queries/total'
Expand All @@ -15,6 +16,7 @@ export * from './sql/constraints'
export * from './sql/delete-rows'
export * from './sql/drop-table'
export * from './sql/enums'
export * from './sql/indexes'
export * from './sql/rename-table'
export * from './sql/rows'
export * from './sql/select'
Expand Down
14 changes: 14 additions & 0 deletions apps/desktop/src/entities/database/queries/indexes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { databases } from '~/drizzle'
import { queryOptions, useQuery } from '@tanstack/react-query'
import { indexesQuery } from '../sql/indexes'

export function databaseIndexesQuery({ database }: { database: typeof databases.$inferSelect }) {
return queryOptions({
queryKey: ['database', database.id, 'indexes'],
queryFn: () => indexesQuery.run(database),
})
}

export function useDatabaseIndexes(...params: Parameters<typeof databaseIndexesQuery>) {
return useQuery(databaseIndexesQuery(...params))
}
132 changes: 132 additions & 0 deletions apps/desktop/src/entities/database/sql/indexes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import type { Kysely } from 'kysely'
import type { Columns as ClickHouseColumns } from '../dialects/clickhouse/schema/system'
import type { SysColumns, SysIndexColumns, SysIndexes, SysSchemas, SysTables } from '../dialects/mssql/schema/indexes'
import type { MysqlStatistics } from '../dialects/mysql/schema/indexes'
import type { PgAttribute, PgClass, PgIndex, PgNamespace } from '../dialects/postgres/schema/indexes'
import { type } from 'arktype'
import { sql } from 'kysely'
import { createQuery } from '../query'

export const indexesType = type({
schema: 'string',
table: 'string',
name: 'string',
column: 'string',
isUnique: 'boolean | 1 | 0',
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
isPrimary: 'boolean | 1 | 0',
}).pipe(data => ({
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
...data,
isUnique: !!data.isUnique,
isPrimary: !!data.isPrimary,
}))

export const indexesQuery = createQuery({
type: indexesType.array(),
query: () => ({
postgres: (db) => {
const sysDb = db as unknown as Kysely<{
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
pg_class: PgClass
pg_index: PgIndex
pg_attribute: PgAttribute
pg_namespace: PgNamespace
}>

return sysDb
.selectFrom('pg_class as t')
.innerJoin('pg_index as ix', 't.oid', 'ix.indrelid')
.innerJoin('pg_class as i', 'i.oid', 'ix.indexrelid')
.innerJoin('pg_attribute as a', join => join
.onRef('a.attrelid', '=', 't.oid')
.on(sql<boolean>`a.attnum = ANY(ix.indkey)`))
.innerJoin('pg_namespace as n', 'n.oid', 't.relnamespace')
.select([
'n.nspname as schema',
't.relname as table',
'i.relname as name',
'a.attname as column',
'ix.indisunique as isUnique',
'ix.indisprimary as isPrimary',
])
.where('n.nspname', 'not in', ['pg_catalog', 'information_schema'])
.where('t.relkind', '=', 'r')
.execute()
},

mysql: (db) => {
const sysDb = db as unknown as Kysely<{
'information_schema.STATISTICS': MysqlStatistics
}>

return sysDb
.selectFrom('information_schema.STATISTICS')
.select([
'TABLE_SCHEMA as schema',
'TABLE_NAME as table',
'INDEX_NAME as name',
'COLUMN_NAME as column',
eb => eb('NON_UNIQUE', '=', 0).as('isUnique'),
eb => eb('INDEX_NAME', '=', 'PRIMARY').as('isPrimary'),
])
.where('TABLE_SCHEMA', 'not in', ['mysql', 'information_schema', 'performance_schema', 'sys'])
.execute()
},

mssql: (db) => {
const sysDb = db as unknown as Kysely<{
'sys.indexes': SysIndexes
'sys.tables': SysTables
'sys.schemas': SysSchemas
'sys.index_columns': SysIndexColumns
'sys.columns': SysColumns
}>

return sysDb
.selectFrom('sys.indexes as i')
.innerJoin('sys.tables as t', 't.object_id', 'i.object_id')
.innerJoin('sys.schemas as s', 's.schema_id', 't.schema_id')
.innerJoin('sys.index_columns as ic', join => join
.onRef('ic.object_id', '=', 'i.object_id')
.onRef('ic.index_id', '=', 'i.index_id'))
.innerJoin('sys.columns as c', join => join
.onRef('c.object_id', '=', 'ic.object_id')
.onRef('c.column_id', '=', 'ic.column_id'))
.select([
's.name as schema',
't.name as table',
'i.name as name',
'c.name as column',
'i.is_unique as isUnique',
'i.is_primary_key as isPrimary',
])
.execute()
},

clickhouse: async (db) => {
/* ClickHouse uses ORDER BY as its primary key/sorting key (similar to clustered index).
It doesn't enforce constraints like traditional RDBMS (no foreign keys, unique constraints, etc.).
We show ORDER BY columns as primary key indexes since that's how ClickHouse optimizes queries. */

const sysDb = db as unknown as Kysely<{
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
'system.columns': ClickHouseColumns
}>

const query = await sysDb
.selectFrom('system.columns')
.select([
'database as schema',
'table',
'name as column',
])
.where('is_in_primary_key', '=', 1)
.where('database', 'not in', ['system', 'information_schema'])
.execute()

return query.map(row => ({
...row,
name: 'primary_key',
isUnique: true,
isPrimary: true,
}))
},
}),
})
Loading