@diagramers/cli 1.0.25 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -75,8 +75,9 @@ class ProjectExtender {
75
75
  ];
76
76
  }
77
77
  async listFeatures() {
78
- console.log(chalk_1.default.blue('📋 Available features:'));
78
+ console.log(chalk_1.default.blue('�� Available features and templates:'));
79
79
  console.log('');
80
+ console.log(chalk_1.default.green('🔧 Features:'));
80
81
  this.features.forEach(feature => {
81
82
  console.log(chalk_1.default.green(` ${feature.name}`));
82
83
  console.log(chalk_1.default.gray(` ${feature.description}`));
@@ -85,6 +86,18 @@ class ProjectExtender {
85
86
  }
86
87
  console.log('');
87
88
  });
89
+ console.log(chalk_1.default.blue('📦 Module Templates:'));
90
+ console.log(chalk_1.default.green(' --module <name> --crud --fields field1,field2'));
91
+ console.log(chalk_1.default.gray(' Generate complete module with CRUD operations'));
92
+ console.log('');
93
+ console.log(chalk_1.default.blue('🗄️ Database Templates:'));
94
+ console.log(chalk_1.default.green(' --table <name> --fields field1,field2 --type mongodb'));
95
+ console.log(chalk_1.default.gray(' Generate database table/collection schema'));
96
+ console.log('');
97
+ console.log(chalk_1.default.blue('🔗 Relation Templates:'));
98
+ console.log(chalk_1.default.green(' --relation <name> --type mongodb'));
99
+ console.log(chalk_1.default.gray(' Generate database relations and references'));
100
+ console.log('');
88
101
  }
89
102
  async addFeature(featureName) {
90
103
  const feature = this.features.find(f => f.name === featureName);
@@ -108,6 +121,38 @@ class ProjectExtender {
108
121
  console.log(chalk_1.default.green(`✅ Feature '${featureName}' added successfully!`));
109
122
  console.log(chalk_1.default.blue(`📝 Main configuration updated to include ${featureName} feature`));
110
123
  }
124
+ async generateModule(moduleName, options = {}) {
125
+ const projectPath = process.cwd();
126
+ // Check if module already exists
127
+ const modulePath = path.join(projectPath, 'src', 'modules', moduleName);
128
+ if (await fs.pathExists(modulePath)) {
129
+ throw new Error(`Module '${moduleName}' already exists in this project.`);
130
+ }
131
+ console.log(chalk_1.default.blue(`📁 Creating module structure for: ${moduleName}`));
132
+ // Create module directory structure
133
+ await this.createModuleStructure(projectPath, moduleName, options);
134
+ // Generate CRUD operations if requested
135
+ if (options.crud) {
136
+ await this.generateCRUDOperations(projectPath, moduleName, options);
137
+ }
138
+ // Update main application to include the module
139
+ await this.registerModule(projectPath, moduleName);
140
+ console.log(chalk_1.default.green(`✅ Module '${moduleName}' generated successfully!`));
141
+ }
142
+ async generateTable(tableName, options = {}) {
143
+ const projectPath = process.cwd();
144
+ console.log(chalk_1.default.blue(`🗄️ Generating table schema for: ${tableName}`));
145
+ // Create table schema based on database type
146
+ await this.createTableSchema(projectPath, tableName, options);
147
+ console.log(chalk_1.default.green(`✅ Table '${tableName}' generated successfully!`));
148
+ }
149
+ async generateRelations(relationName, options = {}) {
150
+ const projectPath = process.cwd();
151
+ console.log(chalk_1.default.blue(`🔗 Generating relations for: ${relationName}`));
152
+ // Create relation definitions
153
+ await this.createRelations(projectPath, relationName, options);
154
+ console.log(chalk_1.default.green(`✅ Relations '${relationName}' generated successfully!`));
155
+ }
111
156
  async createFeatureStructure(projectPath, feature) {
112
157
  const featurePath = path.join(projectPath, 'src', 'features', feature.name);
113
158
  // Create basic feature structure
@@ -195,6 +240,637 @@ export interface ${this.capitalizeFirst(feature.name)}Data {
195
240
  `;
196
241
  await fs.writeFile(path.join(featurePath, 'types', `${feature.name}-types.ts`), typesContent);
197
242
  }
243
+ async createModuleStructure(projectPath, moduleName, options) {
244
+ const modulePath = path.join(projectPath, 'src', 'modules', moduleName);
245
+ // Create module directory structure
246
+ const structure = {
247
+ 'entities': 'Data models and interfaces',
248
+ 'schemas': 'Database schemas and validation',
249
+ 'services': 'Business logic and data access',
250
+ 'controllers': 'HTTP request handlers',
251
+ 'routes': 'API route definitions'
252
+ };
253
+ for (const [dir, description] of Object.entries(structure)) {
254
+ const dirPath = path.join(modulePath, dir);
255
+ await fs.ensureDir(dirPath);
256
+ // Create index file
257
+ const indexContent = `// ${description} for ${moduleName} module
258
+ export * from './${moduleName}.${dir.slice(0, -1)}';
259
+ `;
260
+ await fs.writeFile(path.join(dirPath, 'index.ts'), indexContent);
261
+ }
262
+ // Create main entity
263
+ await this.createEntity(modulePath, moduleName, options);
264
+ // Create schema
265
+ await this.createSchema(modulePath, moduleName, options);
266
+ // Create service
267
+ await this.createService(modulePath, moduleName, options);
268
+ // Create controller
269
+ await this.createController(modulePath, moduleName, options);
270
+ // Create routes
271
+ await this.createRoutes(modulePath, moduleName, options);
272
+ }
273
+ async createEntity(modulePath, moduleName, options) {
274
+ const entityName = this.capitalizeFirst(moduleName);
275
+ const fields = options.fields || ['name', 'description'];
276
+ const entityContent = `import { BaseEntity } from '../../../shared/types/base-entity';
277
+
278
+ export interface I${entityName} extends BaseEntity {
279
+ ${fields.map((field) => ` ${field}: string;`).join('\n')}
280
+ }
281
+
282
+ export interface I${entityName}Create {
283
+ ${fields.map((field) => ` ${field}: string;`).join('\n')}
284
+ }
285
+
286
+ export interface I${entityName}Update {
287
+ ${fields.map((field) => ` ${field}?: string;`).join('\n')}
288
+ }
289
+ `;
290
+ await fs.writeFile(path.join(modulePath, 'entities', `${moduleName}.entity.ts`), entityContent);
291
+ }
292
+ async createSchema(modulePath, moduleName, options) {
293
+ const entityName = this.capitalizeFirst(moduleName);
294
+ const fields = options.fields || ['name', 'description'];
295
+ const schemaContent = `import mongoose, { Schema, Document } from 'mongoose';
296
+ import { I${entityName} } from '../entities/${moduleName}.entity';
297
+
298
+ export interface I${entityName}Document extends Omit<I${entityName}, '_id'>, Document {}
299
+
300
+ const ${moduleName}Schema = new Schema({
301
+ ${fields.map((field) => ` ${field}: {
302
+ type: String,
303
+ required: true,
304
+ trim: true
305
+ }`).join(',\n')}
306
+ }, {
307
+ timestamps: true,
308
+ toJSON: {
309
+ transform: function(doc, ret) {
310
+ return ret;
311
+ }
312
+ }
313
+ });
314
+
315
+ // Indexes
316
+ ${fields.map((field) => `${moduleName}Schema.index({ ${field}: 1 });`).join('\n')}
317
+
318
+ export const ${entityName}Model = mongoose.model<I${entityName}Document>('${entityName}', ${moduleName}Schema);
319
+ `;
320
+ await fs.writeFile(path.join(modulePath, 'schemas', `${moduleName}.schema.ts`), schemaContent);
321
+ }
322
+ async createService(modulePath, moduleName, options) {
323
+ const entityName = this.capitalizeFirst(moduleName);
324
+ const serviceContent = `import { Result } from '../../../shared/types/result';
325
+ import { ${entityName}Model, I${entityName}Document } from '../schemas/${moduleName}.schema';
326
+ import { I${entityName}, I${entityName}Create, I${entityName}Update } from '../entities/${moduleName}.entity';
327
+
328
+ export class ${entityName}Service {
329
+ /**
330
+ * Get all ${moduleName}s
331
+ */
332
+ async getAll(): Promise<Result<I${entityName}[]>> {
333
+ try {
334
+ const ${moduleName}s = await ${entityName}Model.find({ status: 1 }).lean();
335
+ const converted${entityName}s = ${moduleName}s.map(${moduleName} => ({
336
+ ...${moduleName},
337
+ _id: ${moduleName}._id?.toString() || ''
338
+ })) as I${entityName}[];
339
+ return Result.success(converted${entityName}s);
340
+ } catch (error: any) {
341
+ return Result.error('Failed to fetch ${moduleName}s', error.message);
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Get ${moduleName} by ID
347
+ */
348
+ async getById(id: string): Promise<Result<I${entityName} | null>> {
349
+ try {
350
+ const ${moduleName} = await ${entityName}Model.findOne({ _id: id, status: 1 });
351
+ if (!${moduleName}) {
352
+ return Result.error('${entityName} not found', '${entityName} with the specified ID does not exist');
353
+ }
354
+ const ${moduleName}Obj = ${moduleName}.toObject();
355
+ const converted${entityName} = {
356
+ ...${moduleName}Obj,
357
+ _id: ${moduleName}Obj._id?.toString() || ''
358
+ } as I${entityName};
359
+ return Result.success(converted${entityName});
360
+ } catch (error: any) {
361
+ return Result.error('Failed to fetch ${moduleName}', error.message);
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Create new ${moduleName}
367
+ */
368
+ async create(${moduleName}Data: I${entityName}Create): Promise<Result<I${entityName}>> {
369
+ try {
370
+ const ${moduleName} = new ${entityName}Model({
371
+ ...${moduleName}Data,
372
+ status: 1
373
+ });
374
+
375
+ const saved${entityName} = await ${moduleName}.save();
376
+ const ${moduleName}Obj = saved${entityName}.toObject();
377
+
378
+ const converted${entityName} = {
379
+ ...${moduleName}Obj,
380
+ _id: ${moduleName}Obj._id?.toString() || ''
381
+ } as I${entityName};
382
+
383
+ return Result.success(converted${entityName});
384
+ } catch (error: any) {
385
+ return Result.error('Failed to create ${moduleName}', error.message);
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Update ${moduleName}
391
+ */
392
+ async update(id: string, ${moduleName}Data: I${entityName}Update): Promise<Result<I${entityName} | null>> {
393
+ try {
394
+ const ${moduleName} = await ${entityName}Model.findOne({ _id: id, status: 1 });
395
+ if (!${moduleName}) {
396
+ return Result.error('${entityName} not found', '${entityName} with the specified ID does not exist');
397
+ }
398
+
399
+ Object.assign(${moduleName}, ${moduleName}Data);
400
+ const updated${entityName} = await ${moduleName}.save();
401
+
402
+ const ${moduleName}Obj = updated${entityName}.toObject();
403
+
404
+ const converted${entityName} = {
405
+ ...${moduleName}Obj,
406
+ _id: ${moduleName}Obj._id?.toString() || ''
407
+ } as I${entityName};
408
+
409
+ return Result.success(converted${entityName});
410
+ } catch (error: any) {
411
+ return Result.error('Failed to update ${moduleName}', error.message);
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Delete ${moduleName} (soft delete)
417
+ */
418
+ async delete(id: string): Promise<Result<boolean>> {
419
+ try {
420
+ const ${moduleName} = await ${entityName}Model.findOne({ _id: id, status: 1 });
421
+ if (!${moduleName}) {
422
+ return Result.error('${entityName} not found', '${entityName} with the specified ID does not exist');
423
+ }
424
+
425
+ ${moduleName}.status = 0;
426
+ await ${moduleName}.save();
427
+
428
+ return Result.success(true);
429
+ } catch (error: any) {
430
+ return Result.error('Failed to delete ${moduleName}', error.message);
431
+ }
432
+ }
433
+ }
434
+ `;
435
+ await fs.writeFile(path.join(modulePath, 'services', `${moduleName}.service.ts`), serviceContent);
436
+ }
437
+ async createController(modulePath, moduleName, options) {
438
+ const entityName = this.capitalizeFirst(moduleName);
439
+ const controllerContent = `import { Request, Response } from 'express';
440
+ import { ${entityName}Service } from '../services/${moduleName}.service';
441
+ import { I${entityName}Create, I${entityName}Update } from '../entities/${moduleName}.entity';
442
+
443
+ /**
444
+ * @swagger
445
+ * components:
446
+ * schemas:
447
+ * ${entityName}:
448
+ * type: object
449
+ * properties:
450
+ * _id:
451
+ * type: string
452
+ * name:
453
+ * type: string
454
+ * description:
455
+ * type: string
456
+ * createdAt:
457
+ * type: string
458
+ * format: date-time
459
+ * updatedAt:
460
+ * type: string
461
+ * format: date-time
462
+ */
463
+
464
+ export class ${entityName}Controller {
465
+ constructor(private service: ${entityName}Service) {}
466
+
467
+ /**
468
+ * @swagger
469
+ * /api/${moduleName}s:
470
+ * get:
471
+ * summary: Get all ${moduleName}s
472
+ * tags: [${entityName}s]
473
+ * responses:
474
+ * 200:
475
+ * description: List of ${moduleName}s
476
+ * content:
477
+ * application/json:
478
+ * schema:
479
+ * type: object
480
+ * properties:
481
+ * Data:
482
+ * type: array
483
+ * items:
484
+ * $ref: '#/components/schemas/${entityName}'
485
+ * StatusCode:
486
+ * type: number
487
+ * Message:
488
+ * type: string
489
+ */
490
+ async getAll(req: Request, res: Response): Promise<void> {
491
+ try {
492
+ const result = await this.service.getAll();
493
+ res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
494
+ } catch (error: any) {
495
+ res.status(500).json({ error: error.message });
496
+ }
497
+ }
498
+
499
+ /**
500
+ * @swagger
501
+ * /api/${moduleName}s/{id}:
502
+ * get:
503
+ * summary: Get ${moduleName} by ID
504
+ * tags: [${entityName}s]
505
+ * parameters:
506
+ * - in: path
507
+ * name: id
508
+ * required: true
509
+ * schema:
510
+ * type: string
511
+ * responses:
512
+ * 200:
513
+ * description: ${entityName} details
514
+ * content:
515
+ * application/json:
516
+ * schema:
517
+ * type: object
518
+ * properties:
519
+ * Data:
520
+ * $ref: '#/components/schemas/${entityName}'
521
+ * StatusCode:
522
+ * type: number
523
+ * Message:
524
+ * type: string
525
+ */
526
+ async getById(req: Request, res: Response): Promise<void> {
527
+ try {
528
+ const { id } = req.params;
529
+ const result = await this.service.getById(id);
530
+ res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
531
+ } catch (error: any) {
532
+ res.status(500).json({ error: error.message });
533
+ }
534
+ }
535
+
536
+ /**
537
+ * @swagger
538
+ * /api/${moduleName}s:
539
+ * post:
540
+ * summary: Create new ${moduleName}
541
+ * tags: [${entityName}s]
542
+ * requestBody:
543
+ * required: true
544
+ * content:
545
+ * application/json:
546
+ * schema:
547
+ * type: object
548
+ * properties:
549
+ * name:
550
+ * type: string
551
+ * description:
552
+ * type: string
553
+ * responses:
554
+ * 201:
555
+ * description: ${entityName} created successfully
556
+ * content:
557
+ * application/json:
558
+ * schema:
559
+ * type: object
560
+ * properties:
561
+ * Data:
562
+ * $ref: '#/components/schemas/${entityName}'
563
+ * StatusCode:
564
+ * type: number
565
+ * Message:
566
+ * type: string
567
+ */
568
+ async create(req: Request, res: Response): Promise<void> {
569
+ try {
570
+ const ${moduleName}Data: I${entityName}Create = req.body;
571
+ const result = await this.service.create(${moduleName}Data);
572
+ res.status(result.StatusCode === 1000 ? 201 : 400).json(result);
573
+ } catch (error: any) {
574
+ res.status(500).json({ error: error.message });
575
+ }
576
+ }
577
+
578
+ /**
579
+ * @swagger
580
+ * /api/${moduleName}s/{id}:
581
+ * put:
582
+ * summary: Update ${moduleName}
583
+ * tags: [${entityName}s]
584
+ * parameters:
585
+ * - in: path
586
+ * name: id
587
+ * required: true
588
+ * schema:
589
+ * type: string
590
+ * requestBody:
591
+ * required: true
592
+ * content:
593
+ * application/json:
594
+ * schema:
595
+ * type: object
596
+ * properties:
597
+ * name:
598
+ * type: string
599
+ * description:
600
+ * type: string
601
+ * responses:
602
+ * 200:
603
+ * description: ${entityName} updated successfully
604
+ * content:
605
+ * application/json:
606
+ * schema:
607
+ * type: object
608
+ * properties:
609
+ * Data:
610
+ * $ref: '#/components/schemas/${entityName}'
611
+ * StatusCode:
612
+ * type: number
613
+ * Message:
614
+ * type: string
615
+ */
616
+ async update(req: Request, res: Response): Promise<void> {
617
+ try {
618
+ const { id } = req.params;
619
+ const ${moduleName}Data: I${entityName}Update = req.body;
620
+ const result = await this.service.update(id, ${moduleName}Data);
621
+ res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
622
+ } catch (error: any) {
623
+ res.status(500).json({ error: error.message });
624
+ }
625
+ }
626
+
627
+ /**
628
+ * @swagger
629
+ * /api/${moduleName}s/{id}:
630
+ * delete:
631
+ * summary: Delete ${moduleName}
632
+ * tags: [${entityName}s]
633
+ * parameters:
634
+ * - in: path
635
+ * name: id
636
+ * required: true
637
+ * schema:
638
+ * type: string
639
+ * responses:
640
+ * 200:
641
+ * description: ${entityName} deleted successfully
642
+ * content:
643
+ * application/json:
644
+ * schema:
645
+ * type: object
646
+ * properties:
647
+ * Data:
648
+ * type: boolean
649
+ * StatusCode:
650
+ * type: number
651
+ * Message:
652
+ * type: string
653
+ */
654
+ async delete(req: Request, res: Response): Promise<void> {
655
+ try {
656
+ const { id } = req.params;
657
+ const result = await this.service.delete(id);
658
+ res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
659
+ } catch (error: any) {
660
+ res.status(500).json({ error: error.message });
661
+ }
662
+ }
663
+ }
664
+ `;
665
+ await fs.writeFile(path.join(modulePath, 'controllers', `${moduleName}.controller.ts`), controllerContent);
666
+ }
667
+ async createRoutes(modulePath, moduleName, options) {
668
+ const entityName = this.capitalizeFirst(moduleName);
669
+ const routesContent = `import { Router } from 'express';
670
+ import { ${entityName}Controller } from '../controllers/${moduleName}.controller';
671
+ import { ${entityName}Service } from '../services/${moduleName}.service';
672
+
673
+ const router = Router();
674
+ const service = new ${entityName}Service();
675
+ const controller = new ${entityName}Controller(service);
676
+
677
+ // ${entityName} routes
678
+ router.get('/', controller.getAll.bind(controller));
679
+ router.get('/:id', controller.getById.bind(controller));
680
+ router.post('/', controller.create.bind(controller));
681
+ router.put('/:id', controller.update.bind(controller));
682
+ router.delete('/:id', controller.delete.bind(controller));
683
+
684
+ export default router;
685
+ `;
686
+ await fs.writeFile(path.join(modulePath, 'routes', `${moduleName}.routes.ts`), routesContent);
687
+ }
688
+ async generateCRUDOperations(projectPath, moduleName, options) {
689
+ console.log(chalk_1.default.blue(`🔄 Generating CRUD operations for ${moduleName}...`));
690
+ // CRUD operations are already included in the service and controller generation
691
+ }
692
+ async registerModule(projectPath, moduleName) {
693
+ console.log(chalk_1.default.blue(`📝 Registering ${moduleName} module in main application...`));
694
+ // Update main routes index to include the new module
695
+ const routesIndexPath = path.join(projectPath, 'src', 'modules', 'index.ts');
696
+ if (await fs.pathExists(routesIndexPath)) {
697
+ let content = await fs.readFile(routesIndexPath, 'utf8');
698
+ // Add import for the new module
699
+ const importStatement = `import ${moduleName}Routes from './${moduleName}/routes/${moduleName}.routes';`;
700
+ if (!content.includes(importStatement)) {
701
+ // Find the last import statement and add after it
702
+ const importRegex = /import.*from.*['"];?\s*$/gm;
703
+ const matches = [...content.matchAll(importRegex)];
704
+ if (matches.length > 0) {
705
+ const lastImport = matches[matches.length - 1];
706
+ const insertIndex = lastImport.index + lastImport[0].length;
707
+ content = content.slice(0, insertIndex) + '\n' + importStatement + content.slice(insertIndex);
708
+ }
709
+ }
710
+ // Add route registration
711
+ const routeRegistration = `app.use('/api/${moduleName}s', ${moduleName}Routes);`;
712
+ if (!content.includes(routeRegistration)) {
713
+ // Find where routes are registered and add after
714
+ const routeRegex = /app\.use\(.*\);?\s*$/gm;
715
+ const matches = [...content.matchAll(routeRegex)];
716
+ if (matches.length > 0) {
717
+ const lastRoute = matches[matches.length - 1];
718
+ const insertIndex = lastRoute.index + lastRoute[0].length;
719
+ content = content.slice(0, insertIndex) + '\n' + routeRegistration + content.slice(insertIndex);
720
+ }
721
+ }
722
+ await fs.writeFile(routesIndexPath, content);
723
+ }
724
+ }
725
+ async createTableSchema(projectPath, tableName, options) {
726
+ const entityName = this.capitalizeFirst(tableName);
727
+ const fields = options.fields || ['name', 'description'];
728
+ const dbType = options.type || 'mongodb';
729
+ if (dbType === 'mongodb') {
730
+ await this.createMongoDBSchema(projectPath, tableName, fields);
731
+ }
732
+ else {
733
+ await this.createSQLSchema(projectPath, tableName, fields, dbType);
734
+ }
735
+ }
736
+ async createMongoDBSchema(projectPath, tableName, fields) {
737
+ const schemaPath = path.join(projectPath, 'src', 'schemas', `${tableName}.schema.ts`);
738
+ await fs.ensureDir(path.dirname(schemaPath));
739
+ const entityName = this.capitalizeFirst(tableName);
740
+ const schemaContent = `import mongoose, { Schema, Document } from 'mongoose';
741
+
742
+ export interface I${entityName}Document extends Document {
743
+ ${fields.map(field => ` ${field}: string;`).join('\n')}
744
+ createdAt: Date;
745
+ updatedAt: Date;
746
+ }
747
+
748
+ const ${tableName}Schema = new Schema({
749
+ ${fields.map(field => ` ${field}: {
750
+ type: String,
751
+ required: true,
752
+ trim: true
753
+ }`).join(',\n')}
754
+ }, {
755
+ timestamps: true
756
+ });
757
+
758
+ // Indexes
759
+ ${fields.map(field => `${tableName}Schema.index({ ${field}: 1 });`).join('\n')}
760
+
761
+ export const ${entityName}Model = mongoose.model<I${entityName}Document>('${entityName}', ${tableName}Schema);
762
+ `;
763
+ await fs.writeFile(schemaPath, schemaContent);
764
+ }
765
+ async createSQLSchema(projectPath, tableName, fields, dbType) {
766
+ const schemaPath = path.join(projectPath, 'src', 'schemas', `${tableName}.sql`);
767
+ await fs.ensureDir(path.dirname(schemaPath));
768
+ const entityName = this.capitalizeFirst(tableName);
769
+ const schemaContent = `-- ${entityName} table schema for ${dbType.toUpperCase()}
770
+ CREATE TABLE ${tableName}s (
771
+ id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
772
+ ${fields.map(field => ` ${field} VARCHAR(255) NOT NULL,`).join('\n')}
773
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
774
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
775
+ );
776
+
777
+ -- Indexes
778
+ ${fields.map(field => `CREATE INDEX idx_${tableName}_${field} ON ${tableName}s(${field});`).join('\n')}
779
+ `;
780
+ await fs.writeFile(schemaPath, schemaContent);
781
+ }
782
+ async createRelations(projectPath, relationName, options) {
783
+ const dbType = options.type || 'mongodb';
784
+ const relationPath = path.join(projectPath, 'src', 'schemas', 'relations', `${relationName}.relations.ts`);
785
+ await fs.ensureDir(path.dirname(relationPath));
786
+ if (dbType === 'mongodb') {
787
+ await this.createMongoDBRelations(relationPath, relationName);
788
+ }
789
+ else {
790
+ await this.createSQLRelations(relationPath, relationName, dbType);
791
+ }
792
+ }
793
+ async createMongoDBRelations(relationPath, relationName) {
794
+ const relationContent = `// MongoDB relations for ${relationName}
795
+ import mongoose from 'mongoose';
796
+
797
+ // Example: One-to-Many relationship
798
+ // const userSchema = new mongoose.Schema({
799
+ // name: String,
800
+ // email: String,
801
+ // posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
802
+ // });
803
+
804
+ // const postSchema = new mongoose.Schema({
805
+ // title: String,
806
+ // content: String,
807
+ // author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
808
+ // });
809
+
810
+ // Example: Many-to-Many relationship
811
+ // const categorySchema = new mongoose.Schema({
812
+ // name: String,
813
+ // products: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Product' }]
814
+ // });
815
+
816
+ // const productSchema = new mongoose.Schema({
817
+ // name: String,
818
+ // price: Number,
819
+ // categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }]
820
+ // });
821
+
822
+ export const ${relationName}Relations = {
823
+ // Define your relations here
824
+ // User: userSchema,
825
+ // Post: postSchema,
826
+ // Category: categorySchema,
827
+ // Product: productSchema
828
+ };
829
+ `;
830
+ await fs.writeFile(relationPath, relationContent);
831
+ }
832
+ async createSQLRelations(relationPath, relationName, dbType) {
833
+ const relationContent = `-- SQL relations for ${relationName} (${dbType.toUpperCase()})
834
+
835
+ -- Example: One-to-Many relationship
836
+ -- CREATE TABLE users (
837
+ -- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
838
+ -- name VARCHAR(255) NOT NULL,
839
+ -- email VARCHAR(255) UNIQUE NOT NULL
840
+ -- );
841
+
842
+ -- CREATE TABLE posts (
843
+ -- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
844
+ -- title VARCHAR(255) NOT NULL,
845
+ -- content TEXT,
846
+ -- user_id INT,
847
+ -- FOREIGN KEY (user_id) REFERENCES users(id)
848
+ -- );
849
+
850
+ -- Example: Many-to-Many relationship
851
+ -- CREATE TABLE categories (
852
+ -- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
853
+ -- name VARCHAR(255) NOT NULL
854
+ -- );
855
+
856
+ -- CREATE TABLE products (
857
+ -- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
858
+ -- name VARCHAR(255) NOT NULL,
859
+ -- price DECIMAL(10,2)
860
+ -- );
861
+
862
+ -- CREATE TABLE product_categories (
863
+ -- product_id INT,
864
+ -- category_id INT,
865
+ -- PRIMARY KEY (product_id, category_id),
866
+ -- FOREIGN KEY (product_id) REFERENCES products(id),
867
+ -- FOREIGN KEY (category_id) REFERENCES categories(id)
868
+ -- );
869
+
870
+ -- Add your relations here
871
+ `;
872
+ await fs.writeFile(relationPath, relationContent);
873
+ }
198
874
  async addDependencies(dependencies) {
199
875
  console.log(chalk_1.default.blue('📦 Installing dependencies...'));
200
876
  // This would typically run npm install with the dependencies