Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
f90324c
feat: added ability to copy table schema & query (filters or without …
Rudra-Sankha-Sinhamahapatra Dec 31, 2025
e9e365e
fix: using cn
Rudra-Sankha-Sinhamahapatra Dec 31, 2025
877bc49
feat: adds enum support & added parsing for special char or hypens ta…
Rudra-Sankha-Sinhamahapatra Jan 2, 2026
ffd302b
feat: add label property to columns and update related components for…
letstri Jan 2, 2026
8f57b15
feat: refactor copy dialog to use tabs for format selection and updat…
letstri Jan 2, 2026
f56bb17
feat: adds data types support and added size calculation on columns
Rudra-Sankha-Sinhamahapatra Jan 2, 2026
2423a7d
feat: adds foreign key support
Rudra-Sankha-Sinhamahapatra Jan 2, 2026
4e9eb62
fix: merge conflicts
Rudra-Sankha-Sinhamahapatra Jan 6, 2026
09dd7ef
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 6, 2026
4fed82d
fix: query formatting, prisma where, syntaxes, added mappings
Rudra-Sankha-Sinhamahapatra Jan 7, 2026
255c557
refactor: removed eslint expect error
Rudra-Sankha-Sinhamahapatra Jan 7, 2026
1863f6c
chore: merge with main
Rudra-Sankha-Sinhamahapatra Jan 7, 2026
207542f
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 8, 2026
fa1aebf
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 8, 2026
75b365b
refactor: merge with main
Rudra-Sankha-Sinhamahapatra Jan 10, 2026
3803285
fix: merge conflicts
Rudra-Sankha-Sinhamahapatra Jan 23, 2026
2583117
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 23, 2026
1ee614e
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 26, 2026
06c2a9c
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 26, 2026
8944ab6
fix: prisma 1 to many relationship
Rudra-Sankha-Sinhamahapatra Jan 26, 2026
4dc0687
feat: adds foreign key relationship on drizzle
Rudra-Sankha-Sinhamahapatra Jan 26, 2026
7b144d7
feat: added lengths for columns in zod and prisma
Rudra-Sankha-Sinhamahapatra Jan 26, 2026
ff850e9
feat: adds indexes support
Rudra-Sankha-Sinhamahapatra Jan 26, 2026
39e0041
refactor: moved generators to separate folders
Rudra-Sankha-Sinhamahapatra Jan 26, 2026
74194d4
feat: add change-case package and update sidebar link component
letstri Jan 26, 2026
3882b9c
refactor: streamline schema generation functions
letstri Jan 26, 2026
82e1097
fix: alignments of table structure and added null for ts
Rudra-Sankha-Sinhamahapatra Jan 27, 2026
7834dbe
fix: changing drizzle case to camelCase
Rudra-Sankha-Sinhamahapatra Jan 27, 2026
1760716
feat: adds camelCase to zod & ts schema
Rudra-Sankha-Sinhamahapatra Jan 27, 2026
c6cf086
refactor: replaced toPascalCase with pascalCase
Rudra-Sankha-Sinhamahapatra Jan 27, 2026
9d60380
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
ba825d2
fix: prisma model name & key conventions
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
bbfc467
fix: handles drizzle for special cases
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
be6af9b
fix: handles special case for ts,zod,kysely
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
a218d0e
fix: using unknown for json type on fields of zod & ts
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
a72f401
fix: moving definitions to bottom
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
6f192b2
fix: zod import
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
c6925d2
fix: prisma file structure spacing
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
c1392c3
fix: revert back to correct sql enums position
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
2c2a556
fix: prisma schema structue formattin
Rudra-Sankha-Sinhamahapatra Jan 28, 2026
b0ea8a6
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 28, 2026
a85ff49
refactor: improved copy functionality and refactor format handling
letstri Jan 28, 2026
e09e94f
refactor: enhance dialog structure and copy button integration
letstri Jan 28, 2026
1c3026f
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 29, 2026
fb2d7bd
refactor: reorganize Prisma filter value type and update max length n…
letstri Jan 29, 2026
9ffaa1a
refactor: update query generation functions to use destructured param…
letstri Jan 30, 2026
b21db98
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri Jan 30, 2026
ff35936
refactor(dialects): introduce cold dialects
letstri Jan 30, 2026
cb5d26d
refactor(generators): update query and schema functions
letstri Jan 30, 2026
88688d7
feat: adds db onUpdate CasCade,onDelete CasCade & 1 to 1 relationship
Rudra-Sankha-Sinhamahapatra Jan 30, 2026
f84a58e
fix: merge conflict
Rudra-Sankha-Sinhamahapatra Jan 30, 2026
8918c39
feat(schema): adds default and SERIAL for postgres
Rudra-Sankha-Sinhamahapatra Jan 30, 2026
8be8930
refactor(dialects): rename getColdKysely to getColdDialect for clarity
letstri Jan 31, 2026
033f1f6
Merge branch 'feat/copy-table-queryAndSchema' of https://github.com/w…
letstri Jan 31, 2026
3619ce6
refactor(generators): streamline enum handling in schema generation
letstri Jan 31, 2026
ada1a45
refactor(generators): update getColumnType to return 'any' as default…
letstri Jan 31, 2026
70f29aa
refactor(generators): enhance schema generation and type handling acr…
letstri Jan 31, 2026
de11555
refactor(generators): simplify type handling in schema generation by …
letstri Jan 31, 2026
3fbaa9d
refactor(generators): optimize schema generation by consolidating col…
letstri Jan 31, 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
269 changes: 269 additions & 0 deletions apps/desktop/src/entities/database/utils/generators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
import type { ActiveFilter } from '@conar/shared/filters'
import type { Column } from './table'
import * as templates from './templates'

type GeneratorFormat = 'ts' | 'zod' | 'prisma' | 'sql' | 'drizzle' | 'kysely'

const TYPE_MAPPINGS: Record<GeneratorFormat, (type: string) => string> = {
ts: (t) => {
if (/int|float|decimal|number|double/i.test(t))
return 'number'
if (/bool/i.test(t))
return 'boolean'
if (/date|time/i.test(t))
return 'Date'
if (/json/i.test(t))
return 'any'
return 'string'
},
zod: (t) => {
if (/int|float|decimal|number|double/i.test(t))
return 'z.number()'
if (/bool/i.test(t))
return 'z.boolean()'
if (/date|time/i.test(t))
return 'z.date()'
if (/json/i.test(t))
return 'z.any()'
return 'z.string()'
},
prisma: (t) => {
if (/int/i.test(t))
return 'Int'
if (/float|double/i.test(t))
return 'Float'
if (/decimal/i.test(t))
return 'Decimal'
if (/bool/i.test(t))
return 'Boolean'
if (/date|timestamp/i.test(t))
return 'DateTime'
if (/json/i.test(t))
return 'Json'
return 'String'
},
drizzle: (t) => {
if (/serial/i.test(t))
return 'serial'
if (/int/i.test(t))
return 'integer'
if (/text/i.test(t))
return 'text'
if (/varchar/i.test(t))
return 'varchar'
if (/bool/i.test(t))
return 'boolean'
if (/timestamp/i.test(t))
return 'timestamp'
if (/date/i.test(t))
return 'date'
if (/json/i.test(t))
return 'json'
return 'text'
},
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
sql: t => t,
kysely: t => t,
}

function getColumnType(type: string | undefined, format: GeneratorFormat): string {
if (!type)
return 'any'
const mapper = TYPE_MAPPINGS[format]
return mapper ? mapper(type) : type
}

function formatValue(value: unknown): string {
if (value === null)
return 'NULL'
if (typeof value === 'string')
return `'${value.replace(/'/g, '\'\'')}'`
if (typeof value === 'number')
return String(value)
if (typeof value === 'boolean')
return value ? 'TRUE' : 'FALSE'
if (value instanceof Date)
return `'${value.toISOString()}'`
return `'${String(value)}'`
}

export function generateQuerySQL(table: string, filters: ActiveFilter[]) {
const whereClauses = filters.map((f) => {
const col = f.column
const op = f.ref.operator

if (f.ref.hasValue === false)
return `${col} ${op}`

const val = f.ref.isArray
? `(${f.values.map(formatValue).join(', ')})`
: formatValue(f.values[0])

return `${col} ${op} ${val}`
}).join(' AND ')
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated

return templates.sqlQueryTemplate(table, whereClauses)
}

export function generateQueryPrisma(table: string, filters: ActiveFilter[]) {
const where = filters.reduce((acc, f) => {
let value = f.values[0] as string | number | boolean | Date | object | null
const op = f.ref.operator.toUpperCase()

if (f.ref.isArray) {
if (op === 'IN')
value = { in: f.values }
else if (op === 'NOT IN')
value = { notIn: f.values }
}
else if (f.ref.hasValue === false) {
if (op === 'IS NULL')
value = null
else if (op === 'IS NOT NULL')
value = { not: null }
}
else {
const opMap: Record<string, string> = {
'=': 'equals',
'!=': 'not',
'>': 'gt',
'>=': 'gte',
'<': 'lt',
'<=': 'lte',
'LIKE': 'contains',
'ILIKE': 'contains',
}
if (opMap[op]) {
value = opMap[op] === 'equals' ? value : { [opMap[op]]: value }
}
}
return { ...acc, [f.column]: value }
}, {})

const jsonWhere = Object.keys(where).length > 0
? JSON.stringify(where, null, 2).replace(/"([^"]+)":/g, '$1:')
: '{}'

return templates.prismaQueryTemplate(table, jsonWhere)
}

export function generateQueryDrizzle(table: string, filters: ActiveFilter[]) {
const conditions = filters.map((f) => {
const op = f.ref.operator.toUpperCase()
const col = `${table}.${f.column}`
const val = JSON.stringify(f.values[0])
const arrVal = JSON.stringify(f.values)

switch (op) {
case '=': return `eq(${col}, ${val})`
case '!=': return `ne(${col}, ${val})`
case '>': return `gt(${col}, ${val})`
case '>=': return `gte(${col}, ${val})`
case '<': return `lt(${col}, ${val})`
case '<=': return `lte(${col}, ${val})`
case 'IS NULL': return `isNull(${col})`
case 'IS NOT NULL': return `isNotNull(${col})`
case 'IN': return `inArray(${col}, ${arrVal})`
case 'NOT IN': return `notInArray(${col}, ${arrVal})`
case 'LIKE': return `like(${col}, ${val})`
case 'ILIKE': return `ilike(${col}, ${val})`
default: return undefined
}
}).filter(Boolean).join(', ')

return templates.drizzleQueryTemplate(table, conditions)
}

export function generateQueryKysely(table: string, filters: ActiveFilter[]) {
const conditions = filters.map((f) => {
const op = f.ref.operator.toUpperCase()
const col = f.column

if (f.ref.hasValue === false) {
return `'${col}', '${f.ref.operator.toLowerCase()}'`
}
else if (f.ref.isArray) {
const method = op === 'IN' ? 'in' : 'not in'
return `'${col}', '${method}', ${JSON.stringify(f.values)}`
}
else {
return `'${col}', '${f.ref.operator}', ${formatValue(f.values[0])}`
}
}).filter(Boolean).join(').where(')

return templates.kyselyQueryTemplate(table, conditions)
}

export function generateSchemaSQL(table: string, columns: Column[]) {
const cols = columns.map((c) => {
const parts = [c.id, c.type]
if (!c.isNullable)
parts.push('NOT NULL')

if (c.primaryKey)
parts.push('PRIMARY KEY')
return ` ${parts.join(' ')}`
}).join(',\n')

return templates.sqlSchemaTemplate(table, cols)
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated

export function generateSchemaTypeScript(table: string, columns: Column[]) {
const cols = columns.map(c =>
` ${c.id}${c.isNullable ? '?' : ''}: ${getColumnType(c.type, 'ts')};`,
).join('\n')

return templates.typeScriptSchemaTemplate(table, cols)
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated

export function generateSchemaZod(table: string, columns: Column[]) {
const cols = columns.map((c) => {
let t = getColumnType(c.type, 'zod')
if (c.isNullable)
t += '.nullable()'
return ` ${c.id}: ${t},`
}).join('\n')

return templates.zodSchemaTemplate(table, cols)
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated

export function generateSchemaPrisma(table: string, columns: Column[]) {
const cols = columns.map((c) => {
const prismaType = getColumnType(c.type, 'prisma')
const parts = [c.id, prismaType + (c.isNullable ? '?' : '')]
if (c.primaryKey) {
parts.push('@id')
if (prismaType === 'Int')
parts.push('@default(autoincrement())')
}
return ` ${parts.join(' ')}`
}).join('\n')

return templates.prismaSchemaTemplate(table, cols)
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated

export function generateSchemaDrizzle(table: string, columns: Column[]) {
const imports = new Set(columns.map(c => getColumnType(c.type, 'drizzle')))

const cols = columns.map((c) => {
const typeFunc = getColumnType(c.type, 'drizzle')
let chain = `${typeFunc}('${c.id}')`
if (!c.isNullable)
chain += '.notNull()'
if (c.primaryKey)
chain += '.primaryKey()'
return ` ${c.id}: ${chain},`
}).join('\n')

return templates.drizzleSchemaTemplate(table, Array.from(imports), cols)
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated

export function generateSchemaKysely(table: string, columns: Column[]) {
const body = columns.map((c) => {
const tsType = getColumnType(c.type, 'ts')
const isGenerated = c.primaryKey
const typeDef = isGenerated ? `Generated<${tsType}>` : tsType
return ` ${c.id}: ${typeDef};`
}).join('\n')

return templates.kyselySchemaTemplate(table, body)
}
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
71 changes: 71 additions & 0 deletions apps/desktop/src/entities/database/utils/templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
export function sqlSchemaTemplate(table: string, columns: string) {
return `CREATE TABLE ${table} (
${columns}
);`
}

export function typeScriptSchemaTemplate(table: string, columns: string) {
return `export interface ${table} {
${columns}
}`
}

export function zodSchemaTemplate(table: string, columns: string) {
return `import { z } from 'zod';

export const ${table}Schema = z.object({
${columns}
});

export type ${table} = z.infer<typeof ${table}Schema>;`
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
}

export function prismaSchemaTemplate(table: string, columns: string) {
return `model ${table} {
${columns}
}`
}

export function drizzleSchemaTemplate(table: string, imports: string[], columns: string) {
return `import { ${imports.join(', ')}, pgTable } from 'drizzle-orm/pg-core';

export const ${table} = pgTable('${table}', {
${columns}
});`
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
}

export function kyselySchemaTemplate(table: string, body: string) {
return `import { Generated } from 'kysely';

export interface ${table}Table {
${body}
}

export interface Database {
${table}: ${table}Table;
Comment thread
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
}`
}

export function sqlQueryTemplate(table: string, where: string) {
return where
? `SELECT * FROM ${table} WHERE ${where};`
: `SELECT * FROM ${table};`
}

export function prismaQueryTemplate(table: string, whereObj: string) {
return whereObj !== '{}'
? `await prisma.${table}.findMany({ where: ${whereObj} })`
: `await prisma.${table}.findMany()`
}

export function drizzleQueryTemplate(table: string, conditions: string) {
return conditions
? `await db.select().from(${table}).where(and(${conditions}))`
: `await db.select().from(${table})`
}

export function kyselyQueryTemplate(table: string, conditions: string) {
return conditions
? `await db.selectFrom('${table}').selectAll().where(${conditions}).execute()`
: `await db.selectFrom('${table}').selectAll().execute()`
}
Loading