Skip to content

feat(schema): adds table schema & query copy - #275

Merged
letstri merged 59 commits into
mainfrom
feat/copy-table-queryAndSchema
Jan 31, 2026
Merged

feat(schema): adds table schema & query copy#275
letstri merged 59 commits into
mainfrom
feat/copy-table-queryAndSchema

Conversation

@Rudra-Sankha-Sinhamahapatra

@Rudra-Sankha-Sinhamahapatra Rudra-Sankha-Sinhamahapatra commented Dec 31, 2025

Copy link
Copy Markdown
Contributor

Description of Changes

  • What was changed?

-> Added ability to copy schema and queries via filters or without filters

-> Now users can view sql query and other schema and queries based on the current database and its support. If it supports it will show , otherwise it will show database databaseName doesnt supports schema schemaType

-> Added Enum support

-> Foreign Key support

-> unique key support

-> Indexes support

-> Different datatype related schemas and queries check through out different databases as different database can have different syntaxes on schemas and queries ( All though checked everything , but not sure if any syntax is not covered with data type )

  • Why was it changed?
    Now users can easily copy schema or queries
  • Any related issues or discussions?

Closes #26 (If applicable, delete this line if not)

Checklist

  • My changes are scoped and focused
  • I have tested the code locally

Notes to reviewer

Screen Recording

Screen.Recording.2025-12-31.at.10.mp4

@railway-app

railway-app Bot commented Dec 31, 2025

Copy link
Copy Markdown

This PR was not deployed automatically as @Rudra-Sankha-Sinhamahapatra does not have access to the Railway project.

In order to get automatic PR deploys, please add @Rudra-Sankha-Sinhamahapatra to your workspace on Railway.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds functionality to copy table schemas and queries in multiple formats (SQL, TypeScript, Zod, Prisma, Drizzle, Kysely) with or without applied filters.

Key Changes:

  • Added a new HeaderActionsCopy component with a dropdown menu and dialog interface for copying schemas/queries
  • Implemented generator functions for converting table schemas to various formats (SQL, TypeScript, Zod, Prisma, Drizzle, Kysely)
  • Implemented query generators that respect active filters for different ORMs/query builders
  • Created template functions to structure the generated code output

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 19 comments.

File Description
header-actions.tsx Integrated the new HeaderActionsCopy component into the table header actions
header-actions-copy.tsx New component providing UI for selecting and copying schemas/queries in various formats with a dialog preview
generators.ts New utility file containing logic to generate schema and query code in multiple formats based on column metadata and filters
templates.ts New utility file providing string templates for different schema and query output formats

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/desktop/src/entities/database/utils/generators.ts Outdated
Comment thread apps/desktop/src/entities/connection/utils/generators.ts Outdated
Comment thread apps/desktop/src/entities/database/utils/generators.ts Outdated
Comment thread apps/desktop/src/entities/connection/generators/templates.ts
Comment thread apps/desktop/src/entities/database/utils/generators.ts Outdated
Comment thread apps/desktop/src/entities/connection/generators/templates.ts
Comment thread apps/desktop/src/entities/database/utils/generators.ts Outdated
Comment thread apps/desktop/src/entities/database/utils/generators.ts Outdated
@geekyharsh05

Copy link
Copy Markdown
Contributor

@Rudra-Sankha-Sinhamahapatra Great work!

@letstri

letstri commented Jan 2, 2026

Copy link
Copy Markdown
Member

amazing job, man! 🤝

@letstri

letstri commented Jan 6, 2026

Copy link
Copy Markdown
Member

issues:

  1. prisma query has only 1 filter
image image
  1. strange formatting
image image image image
  1. drizzle shouldn't have the first letter capital
image
  1. sql should have or all capital or all lower
image
  1. not sure, but better to avoid mappings in prisma
image
  1. usually zod have the first letter as lower
image

Comment thread apps/desktop/src/entities/database/utils/helpers.ts Outdated
Comment thread apps/desktop/src/entities/database/utils/types.ts Outdated
Comment thread apps/desktop/src/entities/connection/utils/generators.ts Fixed
@letstri
letstri requested a review from Copilot January 28, 2026 15:47
Comment thread apps/desktop/src/entities/connection/generators/formats/prisma.ts Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 18 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +9 to +12
export function generateQuerySQL(table: string, filters: ActiveFilter[]) {
// TODO: use kysely to generate the query
const whereClauses = filters.map((f) => {
const col = `"${f.column}"`

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The column name is quoted using hardcoded double quotes ("${f.column}"), but this is not correct for all database dialects. MySQL and ClickHouse use backticks, MSSQL uses square brackets, and only PostgreSQL uses double quotes. This should use the quoteIdentifier function with the appropriate dialect to ensure the generated SQL is correct for the target database. The dialect parameter is not available in this function, which is a design issue.

Suggested change
export function generateQuerySQL(table: string, filters: ActiveFilter[]) {
// TODO: use kysely to generate the query
const whereClauses = filters.map((f) => {
const col = `"${f.column}"`
export function generateQuerySQL(table: string, filters: ActiveFilter[], dialect: ConnectionType = ConnectionType.Postgres) {
// TODO: use kysely to generate the query
const whereClauses = filters.map((f) => {
const col = quoteIdentifier(f.column, dialect)

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +64
export function sqlQueryTemplate(table: string, where: string) {
return where
? `SELECT * FROM "${table}"\nWHERE ${where};`
: `SELECT * FROM "${table}";`

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table name is quoted using hardcoded double quotes ("${table}"), but this is not correct for all database dialects. MySQL and ClickHouse use backticks, MSSQL uses square brackets, and only PostgreSQL uses double quotes. This should accept a dialect parameter and use the quoteIdentifier function to ensure the generated SQL is correct for the target database.

Copilot uses AI. Check for mistakes.

const match = findEnum(c, table, enums)
if (match?.values.length) {
const valuesArr = match.values.map(v => `'${v}'`).join(', ')

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum values are not properly escaped when generating the Zod schema. If an enum value contains a single quote, it will break the generated code. The values should be escaped using .replace(/'/g, "\\'") or similar before being wrapped in single quotes.

Suggested change
const valuesArr = match.values.map(v => `'${v}'`).join(', ')
const valuesArr = match.values.map(v => `'${v.replace(/'/g, "\\'")}'`).join(', ')

Copilot uses AI. Check for mistakes.
Comment on lines +66 to +69
const valuesList = match.values.map(v => `'${v}'`).join(', ')

imports.add(enumFunc)
extras.push(`export const ${enumVarName} = ${enumFunc}('${eName}', [${valuesList}]);`)

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum values and enum names are not properly escaped when generating the Drizzle schema. If an enum value or name contains a single quote, it will break the generated code. The values and names should be escaped using .replace(/'/g, "\\'") or similar before being wrapped in single quotes.

Suggested change
const valuesList = match.values.map(v => `'${v}'`).join(', ')
imports.add(enumFunc)
extras.push(`export const ${enumVarName} = ${enumFunc}('${eName}', [${valuesList}]);`)
const escapedEName = eName.replace(/'/g, "\\'")
const valuesList = match.values.map(v => `'${v.replace(/'/g, "\\'")}'`).join(', ')
imports.add(enumFunc)
extras.push(`export const ${enumVarName} = ${enumFunc}('${escapedEName}', [${valuesList}]);`)

Copilot uses AI. Check for mistakes.
}

if (needsMap) {
attributes.push(`@map("${c.id}")`)

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Column IDs in Prisma's @Map attribute are not properly escaped. If a column ID contains a double quote, it will break the generated Prisma schema. The ID should be escaped using .replace(/"/g, '\\"') before being wrapped in double quotes in the @Map attribute.

Copilot uses AI. Check for mistakes.
return value ? 'TRUE' : 'FALSE'
if (value instanceof Date)
return `'${value.toISOString()}'`
return `'${String(value)}'`

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default case in formatValue converts the value to a string and wraps it in single quotes, but it doesn't escape any single quotes that might be in the stringified value. This could lead to SQL injection or broken queries if the value contains single quotes. The return statement should be '${String(value).replace(/'/g, '\'\'')}' to properly escape quotes.

Suggested change
return `'${String(value)}'`
return `'${String(value).replace(/'/g, '\'\'')}'`

Copilot uses AI. Check for mistakes.

const match = findEnum(c, table, enums)
if (match?.values.length) {
typeScriptType = match.values.map(v => `'${v}'`).join(' | ')

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum values are not properly escaped when generating the TypeScript type. If an enum value contains a single quote, it will break the generated code. The values should be escaped using .replace(/'/g, "\\'") or similar before being wrapped in single quotes.

Suggested change
typeScriptType = match.values.map(v => `'${v}'`).join(' | ')
typeScriptType = match.values.map(v => `'${String(v).replace(/'/g, "\\'")}'`).join(' | ')

Copilot uses AI. Check for mistakes.
Comment on lines +295 to +301
mysql: (name: string) => `\`${name}\``,
clickhouse: (name: string) => `\`${name}\``,
mssql: (name: string) => `[${name}]`,
postgres: (name: string) => `"${name}"`,
}

export function quoteIdentifier(name: string, dialect: ConnectionType) {

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quoteIdentifier function wraps identifiers in quotes but doesn't escape the identifier content itself. If an identifier contains the quote character used by the dialect (e.g., a double quote in PostgreSQL, a backtick in MySQL, or a square bracket in MSSQL), it will break the generated SQL. Each quote character should be escaped according to the dialect's rules before wrapping.

Suggested change
mysql: (name: string) => `\`${name}\``,
clickhouse: (name: string) => `\`${name}\``,
mssql: (name: string) => `[${name}]`,
postgres: (name: string) => `"${name}"`,
}
export function quoteIdentifier(name: string, dialect: ConnectionType) {
mysql: (name: string) => `\`${name.replace(/`/g, '``')}\``,
clickhouse: (name: string) => `\`${name.replace(/`/g, '``')}\``,
mssql: (name: string) => `[${name.replace(/]/g, ']]')}]`,
postgres: (name: string) => `"${name.replace(/"/g, '""')}"`,
}
export function quoteIdentifier(name: string, dialect: ConnectionType): string {

Copilot uses AI. Check for mistakes.
const enumValues = match.values.map((v) => {
if (/^[a-z]\w*$/i.test(v))
return ` ${v}`
return ` ${sanitize(v)} @map("${v}")`

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum values in Prisma's @Map attribute are not properly escaped. If an enum value contains a double quote, it will break the generated Prisma schema. The value should be escaped using .replace(/"/g, '\\"') before being wrapped in double quotes in the @Map attribute.

Suggested change
return ` ${sanitize(v)} @map("${v}")`
const mappedValue = v.replace(/"/g, '\\"')
return ` ${sanitize(v)} @map("${mappedValue}")`

Copilot uses AI. Check for mistakes.
const colName = camelCase(f.column)

const existing = acc[colName]
return { ...acc, [colName]: existing && typeof existing === 'object' && typeof finalValue === 'object' && finalValue !== null && existing !== null ? { ...existing, ...finalValue } : finalValue }

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable 'existing' is of type date, object or regular expression, but it is compared to an expression of type null.

Suggested change
return { ...acc, [colName]: existing && typeof existing === 'object' && typeof finalValue === 'object' && finalValue !== null && existing !== null ? { ...existing, ...finalValue } : finalValue }
return { ...acc, [colName]: existing && typeof existing === 'object' && typeof finalValue === 'object' && finalValue !== null ? { ...existing, ...finalValue } : finalValue }

Copilot uses AI. Check for mistakes.
Comment thread apps/desktop/src/entities/connection/generators/formats/prisma.ts Fixed
Comment thread apps/desktop/src/entities/connection/generators/formats/prisma.ts Fixed
Comment thread apps/desktop/src/entities/connection/generators/formats/prisma.ts Fixed
@Rudra-Sankha-Sinhamahapatra Rudra-Sankha-Sinhamahapatra changed the title feat: added ability to copy table schema & query (filters or without … feat(schema): adds table schema & query copy Jan 30, 2026
existing: PrismaFilterValue | undefined,
next: PrismaFilterValue,
): PrismaFilterValue {
if (existing == null || typeof existing !== 'object' || typeof next !== 'object' || next === null) {
@letstri
letstri merged commit 75751f2 into main Jan 31, 2026
2 checks passed
@letstri
letstri deleted the feat/copy-table-queryAndSchema branch January 31, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ability to copy table query and schema with ORM

4 participants