feat(schema): adds table schema & query copy - #275
Conversation
|
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. |
There was a problem hiding this comment.
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
HeaderActionsCopycomponent 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.
|
@Rudra-Sankha-Sinhamahapatra Great work! |
|
amazing job, man! 🤝 |
…e compatibility checks
…t/copy-table-queryAndSchema
…t/copy-table-queryAndSchema chore: merge with main
…t/copy-table-queryAndSchema refactor: merge with main
…t/copy-table-queryAndSchema
…t/copy-table-queryAndSchema
There was a problem hiding this comment.
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.
| export function generateQuerySQL(table: string, filters: ActiveFilter[]) { | ||
| // TODO: use kysely to generate the query | ||
| const whereClauses = filters.map((f) => { | ||
| const col = `"${f.column}"` |
There was a problem hiding this comment.
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.
| 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) |
| export function sqlQueryTemplate(table: string, where: string) { | ||
| return where | ||
| ? `SELECT * FROM "${table}"\nWHERE ${where};` | ||
| : `SELECT * FROM "${table}";` |
There was a problem hiding this comment.
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.
|
|
||
| const match = findEnum(c, table, enums) | ||
| if (match?.values.length) { | ||
| const valuesArr = match.values.map(v => `'${v}'`).join(', ') |
There was a problem hiding this comment.
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.
| const valuesArr = match.values.map(v => `'${v}'`).join(', ') | |
| const valuesArr = match.values.map(v => `'${v.replace(/'/g, "\\'")}'`).join(', ') |
| const valuesList = match.values.map(v => `'${v}'`).join(', ') | ||
|
|
||
| imports.add(enumFunc) | ||
| extras.push(`export const ${enumVarName} = ${enumFunc}('${eName}', [${valuesList}]);`) |
There was a problem hiding this comment.
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.
| 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}]);`) |
| } | ||
|
|
||
| if (needsMap) { | ||
| attributes.push(`@map("${c.id}")`) |
There was a problem hiding this comment.
| return value ? 'TRUE' : 'FALSE' | ||
| if (value instanceof Date) | ||
| return `'${value.toISOString()}'` | ||
| return `'${String(value)}'` |
There was a problem hiding this comment.
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.
| return `'${String(value)}'` | |
| return `'${String(value).replace(/'/g, '\'\'')}'` |
|
|
||
| const match = findEnum(c, table, enums) | ||
| if (match?.values.length) { | ||
| typeScriptType = match.values.map(v => `'${v}'`).join(' | ') |
There was a problem hiding this comment.
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.
| typeScriptType = match.values.map(v => `'${v}'`).join(' | ') | |
| typeScriptType = match.values.map(v => `'${String(v).replace(/'/g, "\\'")}'`).join(' | ') |
| mysql: (name: string) => `\`${name}\``, | ||
| clickhouse: (name: string) => `\`${name}\``, | ||
| mssql: (name: string) => `[${name}]`, | ||
| postgres: (name: string) => `"${name}"`, | ||
| } | ||
|
|
||
| export function quoteIdentifier(name: string, dialect: ConnectionType) { |
There was a problem hiding this comment.
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.
| 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 { |
| const enumValues = match.values.map((v) => { | ||
| if (/^[a-z]\w*$/i.test(v)) | ||
| return ` ${v}` | ||
| return ` ${sanitize(v)} @map("${v}")` |
There was a problem hiding this comment.
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.
| return ` ${sanitize(v)} @map("${v}")` | |
| const mappedValue = v.replace(/"/g, '\\"') | |
| return ` ${sanitize(v)} @map("${mappedValue}")` |
| 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 } |
There was a problem hiding this comment.
Variable 'existing' is of type date, object or regular expression, but it is compared to an expression of type null.
| 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 } |
…t/copy-table-queryAndSchema
…aming convention in SQL columns
…eters for improved readability
…t/copy-table-queryAndSchema
…annabespace/conar into feat/copy-table-queryAndSchema
… for undefined types
…removing null checks
…umn and relationship handling









Description of Changes
-> 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 )
Now users can easily copy schema or queries
Closes #26 (If applicable, delete this line if not)
Checklist
Notes to reviewer
Screen Recording
Screen.Recording.2025-12-31.at.10.mp4
cc: @letstri @geekyharsh05