-
-
Notifications
You must be signed in to change notification settings - Fork 108
feat(schema): adds table schema & query copy #275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
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 e9e365e
fix: using cn
Rudra-Sankha-Sinhamahapatra 877bc49
feat: adds enum support & added parsing for special char or hypens ta…
Rudra-Sankha-Sinhamahapatra ffd302b
feat: add label property to columns and update related components for…
letstri 8f57b15
feat: refactor copy dialog to use tabs for format selection and updat…
letstri f56bb17
feat: adds data types support and added size calculation on columns
Rudra-Sankha-Sinhamahapatra 2423a7d
feat: adds foreign key support
Rudra-Sankha-Sinhamahapatra 4e9eb62
fix: merge conflicts
Rudra-Sankha-Sinhamahapatra 09dd7ef
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri 4fed82d
fix: query formatting, prisma where, syntaxes, added mappings
Rudra-Sankha-Sinhamahapatra 255c557
refactor: removed eslint expect error
Rudra-Sankha-Sinhamahapatra 1863f6c
chore: merge with main
Rudra-Sankha-Sinhamahapatra 207542f
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra fa1aebf
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra 75b365b
refactor: merge with main
Rudra-Sankha-Sinhamahapatra 3803285
fix: merge conflicts
Rudra-Sankha-Sinhamahapatra 2583117
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra 1ee614e
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra 06c2a9c
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri 8944ab6
fix: prisma 1 to many relationship
Rudra-Sankha-Sinhamahapatra 4dc0687
feat: adds foreign key relationship on drizzle
Rudra-Sankha-Sinhamahapatra 7b144d7
feat: added lengths for columns in zod and prisma
Rudra-Sankha-Sinhamahapatra ff850e9
feat: adds indexes support
Rudra-Sankha-Sinhamahapatra 39e0041
refactor: moved generators to separate folders
Rudra-Sankha-Sinhamahapatra 74194d4
feat: add change-case package and update sidebar link component
letstri 3882b9c
refactor: streamline schema generation functions
letstri 82e1097
fix: alignments of table structure and added null for ts
Rudra-Sankha-Sinhamahapatra 7834dbe
fix: changing drizzle case to camelCase
Rudra-Sankha-Sinhamahapatra 1760716
feat: adds camelCase to zod & ts schema
Rudra-Sankha-Sinhamahapatra c6cf086
refactor: replaced toPascalCase with pascalCase
Rudra-Sankha-Sinhamahapatra 9d60380
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
Rudra-Sankha-Sinhamahapatra ba825d2
fix: prisma model name & key conventions
Rudra-Sankha-Sinhamahapatra bbfc467
fix: handles drizzle for special cases
Rudra-Sankha-Sinhamahapatra be6af9b
fix: handles special case for ts,zod,kysely
Rudra-Sankha-Sinhamahapatra a218d0e
fix: using unknown for json type on fields of zod & ts
Rudra-Sankha-Sinhamahapatra a72f401
fix: moving definitions to bottom
Rudra-Sankha-Sinhamahapatra 6f192b2
fix: zod import
Rudra-Sankha-Sinhamahapatra c6925d2
fix: prisma file structure spacing
Rudra-Sankha-Sinhamahapatra c1392c3
fix: revert back to correct sql enums position
Rudra-Sankha-Sinhamahapatra 2c2a556
fix: prisma schema structue formattin
Rudra-Sankha-Sinhamahapatra b0ea8a6
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri a85ff49
refactor: improved copy functionality and refactor format handling
letstri e09e94f
refactor: enhance dialog structure and copy button integration
letstri 1c3026f
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri fb2d7bd
refactor: reorganize Prisma filter value type and update max length n…
letstri 9ffaa1a
refactor: update query generation functions to use destructured param…
letstri b21db98
Merge branch 'main' of https://github.com/wannabespace/conar into fea…
letstri ff35936
refactor(dialects): introduce cold dialects
letstri cb5d26d
refactor(generators): update query and schema functions
letstri 88688d7
feat: adds db onUpdate CasCade,onDelete CasCade & 1 to 1 relationship
Rudra-Sankha-Sinhamahapatra f84a58e
fix: merge conflict
Rudra-Sankha-Sinhamahapatra 8918c39
feat(schema): adds default and SERIAL for postgres
Rudra-Sankha-Sinhamahapatra 8be8930
refactor(dialects): rename getColdKysely to getColdDialect for clarity
letstri 033f1f6
Merge branch 'feat/copy-table-queryAndSchema' of https://github.com/w…
letstri 3619ce6
refactor(generators): streamline enum handling in schema generation
letstri ada1a45
refactor(generators): update getColumnType to return 'any' as default…
letstri 70f29aa
refactor(generators): enhance schema generation and type handling acr…
letstri de11555
refactor(generators): simplify type handling in schema generation by …
letstri 3fbaa9d
refactor(generators): optimize schema generation by consolidating col…
letstri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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' | ||
| }, | ||
| 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 ') | ||
|
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) | ||
| } | ||
|
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) | ||
| } | ||
|
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) | ||
| } | ||
|
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) | ||
| } | ||
|
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) | ||
| } | ||
|
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) | ||
| } | ||
|
Rudra-Sankha-Sinhamahapatra marked this conversation as resolved.
Outdated
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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>;` | ||
|
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} | ||
| });` | ||
|
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; | ||
|
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()` | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.