Skip to content

Commit c3077ff

Browse files
committed
Full Alpha Stable for building SQL (PostgreSQL) to NestJS backend
- with_entities variable for building the relations between the tables using TypeORM - with_crud now it's active - with_jwt_auth edits This version contains completed nestjs app with limited features
1 parent 55f1892 commit c3077ff

File tree

13 files changed

+157
-99
lines changed

13 files changed

+157
-99
lines changed

src/app/(docs)/layout.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import "nextra-theme-docs/style-prefixed.css";
22
import { Footer, Layout, Navbar } from "nextra-theme-docs";
33
import { Banner, Head } from "nextra/components";
44
import { getPageMap } from "nextra/page-map";
5+
import Image from "next/image";
6+
import logo from "@/assets/images/logo/logo.png";
57

68
export const metadata = {
79
// Define your metadata here
@@ -11,7 +13,11 @@ export const metadata = {
1113
const banner = <Banner storageKey="some-key">Nextra 4.0 is released 🎉</Banner>;
1214
const navbar = (
1315
<Navbar
14-
logo={<b>Nextra</b>}
16+
logo={
17+
<>
18+
<Image alt="logo" src={logo} width={"40"} height={"40"} /> Dev-Git
19+
</>
20+
}
1521
// ... Your additional navbar options
1622
/>
1723
);

src/app/api/generate/route.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export async function POST(request: NextRequest) {
1010
const formData = await request.formData();
1111
const file = formData.get('file') as File;
1212
const config = JSON.parse(formData.get('config') as string) as GenerationConfig;
13-
13+
1414
if (!file) {
1515
return NextResponse.json(
1616
{ error: 'No SQL file provided' },
@@ -27,8 +27,13 @@ export async function POST(request: NextRequest) {
2727
}
2828

2929
// Read file content
30-
const sqlContent = await file.text();
31-
30+
let sqlContent = await file.text();
31+
//
32+
const charsToRemove = ['"', '`'];
33+
for (const ch of charsToRemove) {
34+
sqlContent = sqlContent.replaceAll(ch, '');
35+
}
36+
3237
if (!sqlContent.trim()) {
3338
return NextResponse.json(
3439
{ error: 'SQL file is empty' },
@@ -67,8 +72,8 @@ export async function POST(request: NextRequest) {
6772
} catch (error) {
6873
console.error('Generation error:', error);
6974
return NextResponse.json(
70-
{
71-
error: 'Failed to generate project',
75+
{
76+
error: 'Failed to generate project',
7277
details: error instanceof Error ? error.message : 'Unknown error'
7378
},
7479
{ status: 500 }

src/app/api/parse/route.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export async function POST(request: NextRequest) {
66
try {
77
const formData = await request.formData();
88
const file = formData.get('file') as File;
9-
9+
1010
if (!file) {
1111
return NextResponse.json(
1212
{ error: 'No SQL file provided' },
@@ -15,8 +15,13 @@ export async function POST(request: NextRequest) {
1515
}
1616

1717
// Read file content
18-
const sqlContent = await file.text();
19-
18+
let sqlContent = await file.text();
19+
//
20+
const charsToRemove = ['"', '`'];
21+
for (const ch of charsToRemove) {
22+
sqlContent = sqlContent.replaceAll(ch, '');
23+
}
24+
2025
if (!sqlContent.trim()) {
2126
return NextResponse.json(
2227
{ error: 'SQL file is empty' },
@@ -45,8 +50,8 @@ export async function POST(request: NextRequest) {
4550
} catch (error) {
4651
console.error('Parse error:', error);
4752
return NextResponse.json(
48-
{
49-
error: 'Failed to parse SQL file',
53+
{
54+
error: 'Failed to parse SQL file',
5055
details: error instanceof Error ? error.message : 'Unknown error'
5156
},
5257
{ status: 500 }

src/shared/components/AnimatedNetworkNodes.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const AnimatedNetworkNodes: React.FC = () => {
9494
<span className="text-white/60">{" > "}</span>
9595
<span className="text-amber-600/60">{"git"}</span>
9696
<sup className="text-slate-600/50">
97-
<em>{" beta "}</em>
97+
<em>{" alpha "}</em>
9898
</sup>
9999
</div>
100100
<div className={styles.networkRight} ref={networkRightRef}></div>

src/shared/components/MiniDrawer.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export const MiniDrawer = ({
7171
: page.route.endsWith("docs");
7272

7373
return (
74-
<div className="px-2 py-3" key={`${page.route}-${index}`}>
74+
<div className="px-2 py-2" key={`${page.route}-${index}`}>
7575
{!isPrefetchable && (
7676
<Link
7777
prefetch={true}

src/shared/components/configuration-panel.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,30 @@ export function ConfigurationPanel({
4444
</CardTitle>
4545
{/* <CardDescription>
4646
Customize your generated NestJS application
47-
</CardDescription> */}
47+
</CardDescription> */}
4848
</CardHeader>
4949
<CardContent className="space-y-6">
5050
{/* Database Selection */}
5151
<div className="space-y-3">
52-
<label className="text-sm font-medium text-slate-900 dark:text-slate-100">
52+
<div className="w-full h-10 bg-slate-100 dark:bg-slate-700 border border-slate-500 border-dashed rounded-lg items-center flex justify-center">
53+
<label className="flex gap-2 text-sm font-medium text-slate-900 dark:text-slate-100">
54+
Select Backend Framework
55+
<p className="text-amber-500 font-bold">Soon!</p>
56+
</label>
57+
</div>
58+
<div className="w-full h-10 bg-slate-100 dark:bg-slate-700 border border-slate-500 border-dashed rounded-lg items-center flex justify-center">
59+
<label className="flex gap-2 text-sm font-medium text-slate-900 dark:text-slate-100">
60+
Select ORM Type
61+
<p className="text-amber-500 font-bold">Soon!</p>
62+
</label>
63+
</div>
64+
<div className="text-sm font-medium text-slate-900 dark:text-slate-100">
5365
Output Database Type
54-
</label>
66+
<p className="text-xs text-slate-500 dark:text-slate-400">
67+
Choose the target database for your generated application
68+
</p>
69+
</div>
70+
5571
<Select
5672
value={config.database_type.toString()}
5773
onValueChange={(value) =>
@@ -66,8 +82,8 @@ export function ConfigurationPanel({
6682
db.soon ? (
6783
<div
6884
key={db.id}
69-
className={`flex items-center space-x-2 relative w-full cursor-default select-none rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 ${
70-
db.soon ? "bg-slate-50" : ""
85+
className={`flex items-center space-x-2 relative w-full cursor-default select-none py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 ${
86+
db.soon ? "bg-slate-50 dark:bg-slate-700" : ""
7187
}`}
7288
>
7389
<span>{db.icon}</span>
@@ -87,22 +103,6 @@ export function ConfigurationPanel({
87103
)}
88104
</SelectContent>
89105
</Select>
90-
91-
<div className="w-full h-10 bg-slate-100 border border-slate-500 border-dashed rounded-lg items-center flex justify-center">
92-
<label className="flex gap-2 text-sm font-medium text-slate-900 dark:text-slate-100">
93-
Select ORM Type
94-
<p className="text-amber-500 font-bold">Soon!</p>
95-
</label>
96-
</div>
97-
<div className="w-full h-10 bg-slate-100 border border-slate-500 border-dashed rounded-lg items-center flex justify-center">
98-
<label className="flex gap-2 text-sm font-medium text-slate-900 dark:text-slate-100">
99-
Select Backend Framework
100-
<p className="text-amber-500 font-bold">Soon!</p>
101-
</label>
102-
</div>
103-
<p className="text-xs text-slate-500 dark:text-slate-400">
104-
Choose the target database for your generated application
105-
</p>
106106
</div>
107107

108108
{/* Feature Toggles */}

src/shared/components/file-upload.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export function FileUpload({
5959
<div
6060
{...getRootProps()}
6161
className={cn(
62-
"border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-all duration-200 bg-white",
62+
"border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-all duration-200",
6363
isDragActive && !isDragReject
6464
? "border-indigo-500 bg-indigo-50 dark:bg-slate-950/20"
6565
: "border-slate-300 dark:border-slate-700 hover:border-indigo-400 hover:bg-slate-50 dark:hover:bg-slate-800/50",

src/shared/components/generator-interface.tsx

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export function GeneratorInterface() {
1414
const [selectedFile, setSelectedFile] = useState<File | null>(null);
1515
const [config, setConfig] = useState<GenerationConfig>({
1616
database_type: 1, // PostgreSQL default
17+
with_entities: true,
1718
with_crud: true,
1819
full_validations: true,
1920
date_fields: false,
@@ -171,18 +172,18 @@ export function GeneratorInterface() {
171172
<span className="text-white">{" > "}</span>
172173
<span className="text-amber-600">{"git"}</span>
173174
<sup className="text-slate-600">
174-
<em>{" beta "}</em>
175+
<em>{" alpha "}</em>
175176
</sup>
176177
</h2>
177178
<h2 className="text-4xl font-bold text-white mb-4">
178179
One Click - Generate Complete Backend Applications
179180
</h2>
180181
<p className="text-xl text-slate-400 max-w-2xl mx-auto">
181-
Transform your SQL schemas into production-ready backends
182-
with authentication, CRUD operations, and comprehensive features!
182+
Transform your SQL schemas into production-ready backends with
183+
authentication, CRUD operations, and comprehensive features!
183184
</p>
184185
<p className="text-xl text-red-400 max-w-2xl mx-auto">
185-
Beta: SQL to NestJS
186+
Alpha: SQL to NestJS
186187
</p>
187188
</motion.div>
188189

@@ -196,17 +197,32 @@ export function GeneratorInterface() {
196197
>
197198
{/* File Upload */}
198199
<div className="space-y-4">
199-
<h3 className="text-lg font-semibold text-white">
200-
1. Upload SQL Schema{" "}
201-
<a
202-
className="text-blue-400"
203-
target="_blank"
204-
href="https://onecompiler.com/"
205-
>
206-
{" "}
207-
Use OneCompiler.com Site
208-
</a>
209-
</h3>
200+
<div className="w-full">
201+
<h3 className="text-lg font-semibold text-white">
202+
1. Upload SQL Schema
203+
</h3>
204+
<p className="text-white flex flex-wrap items-center">
205+
Use
206+
<a
207+
className="text-blue-400 px-1 underline hover:text-blue-300"
208+
target="_blank"
209+
rel="noopener noreferrer"
210+
href="https://onecompiler.com/"
211+
>
212+
OneCompiler.com
213+
</a>
214+
or
215+
<a
216+
className="text-blue-400 px-1 underline hover:text-blue-300"
217+
target="_blank"
218+
rel="noopener noreferrer"
219+
href="https://dbdiagram.io/"
220+
>
221+
dbdiagram.io
222+
</a>
223+
</p>
224+
</div>
225+
210226
<FileUpload
211227
onFileSelect={handleFileSelect}
212228
selectedFile={selectedFile}

src/shared/utils/code-generator.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,17 @@ export class CodeGenerator {
3131

3232
// Generate entities and modules for each table
3333
for (const table of parsedSchema.tables) {
34-
await this.generateTableFiles(zip, table, templateData);
34+
this.generatedTables.push(table.name);
35+
if(config.with_entities) await this.generateTableFiles(zip, table, templateData);
36+
if(config.with_crud) await this.generateCRUDFiles(zip, table, templateData);
3537
}
3638

3739
// Generate authentication module
38-
if (config.with_jwt_auth) await this.generateAuthModule(zip, templateData);
39-
40-
// Generate utility files
41-
await this.generateUtilityFiles(zip, templateData);
40+
if (config.with_jwt_auth) {
41+
await this.generateAuthModule(zip, templateData);
42+
// Generate utility files
43+
await this.generateUtilityFiles(zip, templateData);
44+
}
4245

4346
// Generate configuration files
4447
await this.generateConfigFiles(zip, templateData);
@@ -124,13 +127,15 @@ export class CodeGenerator {
124127
}
125128

126129
private async generateTableFiles(zip: JSZip, table: TableSchema, data: TemplateData): Promise<void> {
127-
this.generatedTables.push(table.name);
128-
const modulePath = `src/modules/${table.name}`;
129130
const entitiesPath = `src/entities`;
130131

131132
// Entity
132133
zip.file(`${entitiesPath}/${table.name}.entity.ts`,
133134
this.templateGenerator.generateEntity(table, data));
135+
}
136+
137+
private async generateCRUDFiles(zip: JSZip, table: TableSchema, data: TemplateData): Promise<void> {
138+
const modulePath = `src/modules/${table.name}`;
134139

135140
// Controller
136141
zip.file(`${modulePath}/${table.name}.controller.ts`,
@@ -152,6 +157,7 @@ export class CodeGenerator {
152157
this.templateGenerator.generateModule(table, data));
153158
}
154159

160+
155161
private async generateAuthModule(zip: JSZip, data: TemplateData): Promise<void> {
156162
const authPath = 'src/modules/auth';
157163
const usersTable = this.generatedTables.filter((val) => val.toLowerCase().includes("user"));
@@ -386,7 +392,7 @@ export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);`);
386392
${data.userRoles.map(role => `${role.toUpperCase()} = '${role}'`).join(',\n ')}
387393
}`);
388394

389-
// Utilities
395+
// date.util
390396
zip.file('src/utils/date.util.ts', `export class DateUtil {
391397
static toUTC(date: Date): Date {
392398
return new Date(date.getTime() + date.getTimezoneOffset() * 60000);

src/shared/utils/constants.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,23 @@ export const DATABASE_CONFIGS: DatabaseConfig[] = [
5555
];
5656

5757
export const FEATURES = [
58-
{ key: "with_crud" as const, label: "CRUD Operations", desc: 'Generate complete CRUD operations for all tables', icon: "🔧", status: "✅" },
58+
{ key: "with_entities" as const, label: "Entities & Schemas", desc: 'Generate all the tables with their relations', icon: "⛁", status: "✅", canEdit: false },
59+
{ key: "with_crud" as const, label: "CRUD Operations", desc: 'Generate complete CRUD operations for all tables', icon: "🔧", status: "✅", canEdit: false },
60+
{ key: "with_swagger" as const, label: "Swagger/OpenAPI Docs", desc: 'Generate Swagger/OpenAPI documentation', icon: "📚", status: "✅", canEdit: true },
5961
{
6062
key: "full_validations" as const,
6163
label: "Field Validations",
6264
desc: 'Add comprehensive field validations (email, unique, required, etc.)',
6365
icon: "🔍",
64-
status: "✅"
66+
status: "✅",
67+
canEdit: true,
6568
},
66-
{ key: "date_fields" as const, label: "Date Fields-Columns", desc: 'Add "createdAt" & "updatedAt" fields or columns for all the tables', icon: "📆", status: "✅" },
67-
{ key: "with_swagger" as const, label: "Swagger/OpenAPI Docs", desc: 'Generate Swagger/OpenAPI documentation', icon: "📚", status: "✅" },
68-
{ key: "with_ftp" as const, label: "FTP Support", desc: 'Include FTP configuration and file handling utilities', icon: "📁", status: "Soon!" },
69-
{ key: "with_google_auth" as const, label: "Google OAuth", desc: 'Add Google OAuth 2.0 authentication setup', icon: "🔑", status: "Soon!" },
70-
{ key: "with_jwt_auth" as const, label: "JWT Auth", desc: 'Add JWT auth strategy', icon: "🔐", status: "Soon!" },
69+
{ key: "with_jwt_auth" as const, label: "JWT Auth", desc: 'Add JWT auth strategy', icon: "🔐", status: "Soon!", canEdit: true },
70+
{ key: "date_fields" as const, label: "Date Fields Columns", desc: 'Add "createdAt" & "updatedAt" fields or columns for all the tables', icon: "📆", status: "Soon!", canEdit: true },
71+
{ key: "with_ftp" as const, label: "FTP Support", desc: 'Include FTP configuration and file handling utilities', icon: "📁", status: "Soon!", canEdit: true },
72+
{ key: "with_google_auth" as const, label: "Google OAuth", desc: 'Add Google OAuth 2.0 authentication setup', icon: "🇬", status: "Soon!", canEdit: true },
7173
];
7274

73-
7475
export const TYPE_MAPPINGS = {
7576
postgresql: {
7677
'VARCHAR': 'string',

0 commit comments

Comments
 (0)