@diagramers/cli 1.0.16 → 1.0.18

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.
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateRelation = generateRelation;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ async function generateRelation(table1, table2, relationType = 'one-to-one') {
40
+ // Validate table names
41
+ if (!table1 || !table2 || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(table1) || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(table2)) {
42
+ throw new Error('Invalid table names. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
43
+ }
44
+ const table1Capitalized = table1.charAt(0).toUpperCase() + table1.slice(1);
45
+ const table2Capitalized = table2.charAt(0).toUpperCase() + table2.slice(1);
46
+ const currentDir = process.cwd();
47
+ // Check for required API project structure
48
+ const requiredDirs = ['src/entities', 'src/schemas'];
49
+ const missingDirs = requiredDirs.filter(dir => !fs.existsSync(path.join(currentDir, dir)));
50
+ if (missingDirs.length > 0) {
51
+ throw new Error(`This command should be run from a diagramers API project. Missing directories: ${missingDirs.join(', ')}`);
52
+ }
53
+ // Check if both tables exist
54
+ const table1EntityPath = path.join(currentDir, 'src/entities', `${table1}.ts`);
55
+ const table2EntityPath = path.join(currentDir, 'src/entities', `${table2}.ts`);
56
+ const table1SchemaPath = path.join(currentDir, 'src/schemas', `${table1}.ts`);
57
+ const table2SchemaPath = path.join(currentDir, 'src/schemas', `${table2}.ts`);
58
+ if (!fs.existsSync(table1EntityPath) || !fs.existsSync(table2EntityPath)) {
59
+ throw new Error(`Both tables must exist before creating relationships. Missing: ${!fs.existsSync(table1EntityPath) ? table1 : ''} ${!fs.existsSync(table2EntityPath) ? table2 : ''}`);
60
+ }
61
+ console.log(`🔗 Creating ${relationType} relationship between ${table1} and ${table2}...`);
62
+ // Update entities
63
+ console.log('📝 Updating entities...');
64
+ updateEntity(table1EntityPath, table1Capitalized, table2Capitalized, relationType, 'forward');
65
+ updateEntity(table2EntityPath, table2Capitalized, table1Capitalized, relationType, 'reverse');
66
+ // Update schemas
67
+ console.log('📋 Updating schemas...');
68
+ updateSchema(table1SchemaPath, table1Capitalized, table2Capitalized, relationType, 'forward');
69
+ updateSchema(table2SchemaPath, table2Capitalized, table1Capitalized, relationType, 'reverse');
70
+ console.log('✅ Relationship created successfully!');
71
+ console.log(`🔗 ${table1} ↔ ${table2} (${relationType})`);
72
+ }
73
+ function updateEntity(entityPath, tableCapitalized, relatedTableCapitalized, relationType, direction) {
74
+ let entityContent = fs.readFileSync(entityPath, 'utf8');
75
+ // Add import for the related interface
76
+ const importStatement = `import { I${relatedTableCapitalized} } from './${direction === 'forward' ? relatedTableCapitalized.toLowerCase() : relatedTableCapitalized.toLowerCase()}';`;
77
+ if (!entityContent.includes(importStatement)) {
78
+ // Find the last import statement and add after it
79
+ const importRegex = /import.*from.*['"];?\s*$/gm;
80
+ const matches = [...entityContent.matchAll(importRegex)];
81
+ if (matches.length > 0) {
82
+ const lastImport = matches[matches.length - 1];
83
+ const insertIndex = lastImport.index + lastImport[0].length;
84
+ entityContent = entityContent.slice(0, insertIndex) + '\n' + importStatement + entityContent.slice(insertIndex);
85
+ }
86
+ }
87
+ // Add relationship fields based on type
88
+ const interfaceRegex = /export interface I\w+ extends mongoose\.Document \{([^}]*)\}/s;
89
+ const match = entityContent.match(interfaceRegex);
90
+ if (match) {
91
+ const interfaceContent = match[1];
92
+ const newFields = generateEntityFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
93
+ // Add new fields before the closing brace
94
+ const updatedInterfaceContent = interfaceContent.trim() + '\n ' + newFields;
95
+ entityContent = entityContent.replace(interfaceRegex, `export interface I${tableCapitalized} extends mongoose.Document {$1${updatedInterfaceContent}\n}`);
96
+ }
97
+ fs.writeFileSync(entityPath, entityContent);
98
+ }
99
+ function updateSchema(schemaPath, tableCapitalized, relatedTableCapitalized, relationType, direction) {
100
+ let schemaContent = fs.readFileSync(schemaPath, 'utf8');
101
+ // Add import for the related schema
102
+ const importStatement = `import { ${relatedTableCapitalized}Entity } from './${direction === 'forward' ? relatedTableCapitalized.toLowerCase() : relatedTableCapitalized.toLowerCase()}';`;
103
+ if (!schemaContent.includes(importStatement)) {
104
+ // Find the last import statement and add after it
105
+ const importRegex = /import.*from.*['"];?\s*$/gm;
106
+ const matches = [...schemaContent.matchAll(importRegex)];
107
+ if (matches.length > 0) {
108
+ const lastImport = matches[matches.length - 1];
109
+ const insertIndex = lastImport.index + lastImport[0].length;
110
+ schemaContent = schemaContent.slice(0, insertIndex) + '\n' + importStatement + schemaContent.slice(insertIndex);
111
+ }
112
+ }
113
+ // Add schema fields based on relationship type
114
+ const schemaRegex = /export const \w+Schema = new mongoose\.Schema\(([^)]*),/s;
115
+ const match = schemaContent.match(schemaRegex);
116
+ if (match) {
117
+ const schemaFields = match[1];
118
+ const newFields = generateSchemaFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
119
+ // Add new fields before the closing brace
120
+ const updatedSchemaFields = schemaFields.trim() + '\n ' + newFields;
121
+ schemaContent = schemaContent.replace(schemaRegex, `export const ${tableCapitalized.toLowerCase()}Schema = new mongoose.Schema(${updatedSchemaFields},`);
122
+ }
123
+ // Add virtual fields and population methods
124
+ const modelRegex = /export const \w+Entity = mongoose\.model<.*>\(.*\);?\s*$/;
125
+ const virtualFields = generateVirtualFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
126
+ if (virtualFields) {
127
+ schemaContent = schemaContent.replace(modelRegex, `${virtualFields}\n\n$&`);
128
+ }
129
+ fs.writeFileSync(schemaPath, schemaContent);
130
+ }
131
+ function generateEntityFields(tableCapitalized, relatedTableCapitalized, relationType, direction) {
132
+ switch (relationType) {
133
+ case 'one-to-one':
134
+ if (direction === 'forward') {
135
+ return `${relatedTableCapitalized.toLowerCase()}Id: ObjectId,\n ${relatedTableCapitalized.toLowerCase()}?: I${relatedTableCapitalized}`;
136
+ }
137
+ else {
138
+ return `${tableCapitalized.toLowerCase()}Id: ObjectId,\n ${tableCapitalized.toLowerCase()}?: I${tableCapitalized}`;
139
+ }
140
+ case 'one-to-many':
141
+ if (direction === 'forward') {
142
+ return `${relatedTableCapitalized.toLowerCase()}Id: ObjectId,\n ${relatedTableCapitalized.toLowerCase()}?: I${relatedTableCapitalized}`;
143
+ }
144
+ else {
145
+ return `${tableCapitalized.toLowerCase()}s?: I${tableCapitalized}[]`;
146
+ }
147
+ case 'many-to-many':
148
+ if (direction === 'forward') {
149
+ return `${relatedTableCapitalized.toLowerCase()}Ids: ObjectId[],\n ${relatedTableCapitalized.toLowerCase()}s?: I${relatedTableCapitalized}[]`;
150
+ }
151
+ else {
152
+ return `${tableCapitalized.toLowerCase()}Ids: ObjectId[],\n ${tableCapitalized.toLowerCase()}s?: I${tableCapitalized}[]`;
153
+ }
154
+ default:
155
+ return '';
156
+ }
157
+ }
158
+ function generateSchemaFields(tableCapitalized, relatedTableCapitalized, relationType, direction) {
159
+ switch (relationType) {
160
+ case 'one-to-one':
161
+ if (direction === 'forward') {
162
+ return `${relatedTableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}',\n required: false\n }`;
163
+ }
164
+ else {
165
+ return `${tableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${tableCapitalized.toLowerCase()}',\n required: false\n }`;
166
+ }
167
+ case 'one-to-many':
168
+ if (direction === 'forward') {
169
+ return `${relatedTableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}',\n required: false\n }`;
170
+ }
171
+ else {
172
+ return ''; // No field needed for reverse one-to-many
173
+ }
174
+ case 'many-to-many':
175
+ if (direction === 'forward') {
176
+ return `${relatedTableCapitalized.toLowerCase()}Ids: [{\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}'\n }]`;
177
+ }
178
+ else {
179
+ return `${tableCapitalized.toLowerCase()}Ids: [{\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${tableCapitalized.toLowerCase()}'\n }]`;
180
+ }
181
+ default:
182
+ return '';
183
+ }
184
+ }
185
+ function generateVirtualFields(tableCapitalized, relatedTableCapitalized, relationType, direction) {
186
+ switch (relationType) {
187
+ case 'one-to-one':
188
+ if (direction === 'forward') {
189
+ return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '${relatedTableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
190
+ }
191
+ else {
192
+ return `// Virtual populate for ${tableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '${tableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
193
+ }
194
+ case 'one-to-many':
195
+ if (direction === 'forward') {
196
+ return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '${relatedTableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
197
+ }
198
+ else {
199
+ return `// Virtual populate for ${tableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}s', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '_id',\n foreignField: '${tableCapitalized.toLowerCase()}Id'\n});`;
200
+ }
201
+ case 'many-to-many':
202
+ if (direction === 'forward') {
203
+ return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}s', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '${relatedTableCapitalized.toLowerCase()}Ids',\n foreignField: '_id'\n});`;
204
+ }
205
+ else {
206
+ return `// Virtual populate for ${tableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}s', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '${tableCapitalized.toLowerCase()}Ids',\n foreignField: '_id'\n});`;
207
+ }
208
+ default:
209
+ return '';
210
+ }
211
+ }
212
+ //# sourceMappingURL=relation-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation-generator.js","sourceRoot":"","sources":["../../src/services/relation-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function generateTable(tableName: string): Promise<void>;
2
+ //# sourceMappingURL=table-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-generator.d.ts","sourceRoot":"","sources":["../../src/services/table-generator.ts"],"names":[],"mappings":"AAGA,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCpE"}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateTable = generateTable;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ async function generateTable(tableName) {
40
+ // Validate table name
41
+ if (!tableName || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(tableName)) {
42
+ throw new Error('Invalid table name. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
43
+ }
44
+ const tableNameCapitalized = tableName.charAt(0).toUpperCase() + tableName.slice(1);
45
+ const currentDir = process.cwd();
46
+ // Check for required API project structure
47
+ const requiredDirs = [
48
+ 'src/entities',
49
+ 'src/schemas'
50
+ ];
51
+ const missingDirs = requiredDirs.filter(dir => !fs.existsSync(path.join(currentDir, dir)));
52
+ if (missingDirs.length > 0) {
53
+ throw new Error(`This command should be run from a diagramers API project. Missing directories: ${missingDirs.join(', ')}`);
54
+ }
55
+ console.log('📝 Creating entity...');
56
+ const entityContent = generateEntityContent(tableName, tableNameCapitalized);
57
+ fs.writeFileSync(path.join(currentDir, 'src/entities', `${tableName}.ts`), entityContent);
58
+ console.log('📋 Creating schema...');
59
+ const schemaContent = generateSchemaContent(tableName, tableNameCapitalized);
60
+ fs.writeFileSync(path.join(currentDir, 'src/schemas', `${tableName}.ts`), schemaContent);
61
+ // Update dbcontext to include the new entity
62
+ updateDbContext(currentDir, tableName, tableNameCapitalized);
63
+ console.log('✅ Table generation completed!');
64
+ console.log(`📊 Entity: src/entities/${tableName}.ts`);
65
+ console.log(`📋 Schema: src/schemas/${tableName}.ts`);
66
+ console.log('🔄 dbcontext.ts updated');
67
+ }
68
+ function generateEntityContent(tableName, tableNameCapitalized) {
69
+ return `import * as mongoose from 'mongoose';
70
+ import { ObjectId } from "bson";
71
+
72
+ export interface I${tableNameCapitalized} extends mongoose.Document {
73
+ _id: ObjectId,
74
+ name: string,
75
+ description?: string,
76
+ status: number,
77
+ createdAt: Date,
78
+ updatedAt: Date
79
+ }`;
80
+ }
81
+ function generateSchemaContent(tableName, tableNameCapitalized) {
82
+ return `import * as mongoose from 'mongoose';
83
+ import { I${tableNameCapitalized} } from '../entities/${tableName}';
84
+
85
+ export const ${tableName}Schema = new mongoose.Schema(
86
+ {
87
+ name: {
88
+ type: mongoose.SchemaTypes.String,
89
+ required: true,
90
+ },
91
+ description: {
92
+ type: mongoose.SchemaTypes.String,
93
+ required: false,
94
+ },
95
+ status: {
96
+ type: mongoose.SchemaTypes.Number,
97
+ default: 1,
98
+ }
99
+ },
100
+ { timestamps: true, suppressReservedKeysWarning: true },
101
+ );
102
+
103
+ export const ${tableNameCapitalized}Entity = mongoose.model<I${tableNameCapitalized}>('${tableName}', ${tableName}Schema);`;
104
+ }
105
+ function updateDbContext(currentDir, tableName, tableNameCapitalized) {
106
+ const dbcontextPath = path.join(currentDir, 'src/helpers/dbcontext.ts');
107
+ if (!fs.existsSync(dbcontextPath)) {
108
+ console.log('⚠️ dbcontext.ts not found, skipping dbcontext update');
109
+ return;
110
+ }
111
+ let dbcontextContent = fs.readFileSync(dbcontextPath, 'utf8');
112
+ // Add import
113
+ const importStatement = `import { ${tableNameCapitalized}Entity } from '../schemas/${tableName}';`;
114
+ if (!dbcontextContent.includes(importStatement)) {
115
+ // Find the last import statement and add after it
116
+ const importRegex = /import.*from.*['"];?\s*$/gm;
117
+ const matches = [...dbcontextContent.matchAll(importRegex)];
118
+ if (matches.length > 0) {
119
+ const lastImport = matches[matches.length - 1];
120
+ const insertIndex = lastImport.index + lastImport[0].length;
121
+ dbcontextContent = dbcontextContent.slice(0, insertIndex) + '\n' + importStatement + dbcontextContent.slice(insertIndex);
122
+ }
123
+ }
124
+ // Add to dbcontext object
125
+ const dbcontextObjectRegex = /export\s+default\s*\{([^}]*)\}/s;
126
+ const match = dbcontextContent.match(dbcontextObjectRegex);
127
+ if (match) {
128
+ const objectContent = match[1];
129
+ if (!objectContent.includes(`${tableNameCapitalized}Entity`)) {
130
+ const newObjectContent = objectContent.trim() + `,\n ${tableNameCapitalized}Entity`;
131
+ dbcontextContent = dbcontextContent.replace(dbcontextObjectRegex, `export default {$1${newObjectContent}\n}`);
132
+ }
133
+ }
134
+ fs.writeFileSync(dbcontextPath, dbcontextContent);
135
+ console.log('📊 Updated dbcontext.ts');
136
+ }
137
+ //# sourceMappingURL=table-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-generator.js","sourceRoot":"","sources":["../../src/services/table-generator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagramers/cli",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Diagramers CLI - Command-line tools for managing Diagramers projects",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,5 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { generateModule } from '../services/api-generator';
3
+ import { generateTable } from '../services/table-generator';
4
+ import { generateRelation } from '../services/relation-generator';
3
5
  import { processTemplate } from '../services/template-processor';
4
6
  import chalk from 'chalk';
5
7
 
@@ -38,5 +40,37 @@ export function apiCommand(program: Command) {
38
40
  }
39
41
  });
40
42
 
43
+ // Generate table command
44
+ api
45
+ .command('generate:table <name>')
46
+ .description('Generate a new database table with entity and schema only')
47
+ .action(async (name: string) => {
48
+ try {
49
+ console.log(chalk.blue(`🚀 Generating table: ${name}`));
50
+ await generateTable(name);
51
+ console.log(chalk.green(`✅ Table '${name}' generated successfully!`));
52
+ } catch (error: any) {
53
+ console.error(chalk.red(`❌ Error generating table: ${error.message}`));
54
+ process.exit(1);
55
+ }
56
+ });
57
+
58
+ // Generate relation command
59
+ api
60
+ .command('generate:relation <table1> <table2> [type]')
61
+ .description('Generate a relationship between two existing tables')
62
+ .option('-t, --type <type>', 'Relationship type: one-to-one, one-to-many, many-to-many', 'one-to-one')
63
+ .action(async (table1: string, table2: string, options: any) => {
64
+ try {
65
+ const relationType = options.type || 'one-to-one';
66
+ console.log(chalk.blue(`🔗 Creating ${relationType} relationship between ${table1} and ${table2}...`));
67
+ await generateRelation(table1, table2, relationType);
68
+ console.log(chalk.green(`✅ Relationship created successfully!`));
69
+ } catch (error: any) {
70
+ console.error(chalk.red(`❌ Error creating relationship: ${error.message}`));
71
+ process.exit(1);
72
+ }
73
+ });
74
+
41
75
  return api;
42
76
  }
package/src/index.ts CHANGED
@@ -28,6 +28,8 @@ Examples:
28
28
  $ diagramers update
29
29
  $ diagramers extend --feature auth
30
30
  $ diagramers api generate:module product
31
+ $ diagramers api generate:table category
32
+ $ diagramers api generate:relation product category one-to-many
31
33
  $ diagramers api process:template my-api-project
32
34
  `);
33
35
 
@@ -0,0 +1,203 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ export type RelationType = 'one-to-one' | 'one-to-many' | 'many-to-many';
5
+
6
+ export async function generateRelation(table1: string, table2: string, relationType: RelationType = 'one-to-one'): Promise<void> {
7
+ // Validate table names
8
+ if (!table1 || !table2 || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(table1) || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(table2)) {
9
+ throw new Error('Invalid table names. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
10
+ }
11
+
12
+ const table1Capitalized = table1.charAt(0).toUpperCase() + table1.slice(1);
13
+ const table2Capitalized = table2.charAt(0).toUpperCase() + table2.slice(1);
14
+ const currentDir = process.cwd();
15
+
16
+ // Check for required API project structure
17
+ const requiredDirs = ['src/entities', 'src/schemas'];
18
+ const missingDirs = requiredDirs.filter(dir => !fs.existsSync(path.join(currentDir, dir)));
19
+ if (missingDirs.length > 0) {
20
+ throw new Error(`This command should be run from a diagramers API project. Missing directories: ${missingDirs.join(', ')}`);
21
+ }
22
+
23
+ // Check if both tables exist
24
+ const table1EntityPath = path.join(currentDir, 'src/entities', `${table1}.ts`);
25
+ const table2EntityPath = path.join(currentDir, 'src/entities', `${table2}.ts`);
26
+ const table1SchemaPath = path.join(currentDir, 'src/schemas', `${table1}.ts`);
27
+ const table2SchemaPath = path.join(currentDir, 'src/schemas', `${table2}.ts`);
28
+
29
+ if (!fs.existsSync(table1EntityPath) || !fs.existsSync(table2EntityPath)) {
30
+ throw new Error(`Both tables must exist before creating relationships. Missing: ${!fs.existsSync(table1EntityPath) ? table1 : ''} ${!fs.existsSync(table2EntityPath) ? table2 : ''}`);
31
+ }
32
+
33
+ console.log(`🔗 Creating ${relationType} relationship between ${table1} and ${table2}...`);
34
+
35
+ // Update entities
36
+ console.log('📝 Updating entities...');
37
+ updateEntity(table1EntityPath, table1Capitalized, table2Capitalized, relationType, 'forward');
38
+ updateEntity(table2EntityPath, table2Capitalized, table1Capitalized, relationType, 'reverse');
39
+
40
+ // Update schemas
41
+ console.log('📋 Updating schemas...');
42
+ updateSchema(table1SchemaPath, table1Capitalized, table2Capitalized, relationType, 'forward');
43
+ updateSchema(table2SchemaPath, table2Capitalized, table1Capitalized, relationType, 'reverse');
44
+
45
+ console.log('✅ Relationship created successfully!');
46
+ console.log(`🔗 ${table1} ↔ ${table2} (${relationType})`);
47
+ }
48
+
49
+ function updateEntity(entityPath: string, tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): void {
50
+ let entityContent = fs.readFileSync(entityPath, 'utf8');
51
+
52
+ // Add import for the related interface
53
+ const importStatement = `import { I${relatedTableCapitalized} } from './${direction === 'forward' ? relatedTableCapitalized.toLowerCase() : relatedTableCapitalized.toLowerCase()}';`;
54
+ if (!entityContent.includes(importStatement)) {
55
+ // Find the last import statement and add after it
56
+ const importRegex = /import.*from.*['"];?\s*$/gm;
57
+ const matches = [...entityContent.matchAll(importRegex)];
58
+ if (matches.length > 0) {
59
+ const lastImport = matches[matches.length - 1];
60
+ const insertIndex = lastImport.index! + lastImport[0].length;
61
+ entityContent = entityContent.slice(0, insertIndex) + '\n' + importStatement + entityContent.slice(insertIndex);
62
+ }
63
+ }
64
+
65
+ // Add relationship fields based on type
66
+ const interfaceRegex = /export interface I\w+ extends mongoose\.Document \{([^}]*)\}/s;
67
+ const match = entityContent.match(interfaceRegex);
68
+
69
+ if (match) {
70
+ const interfaceContent = match[1];
71
+ const newFields = generateEntityFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
72
+
73
+ // Add new fields before the closing brace
74
+ const updatedInterfaceContent = interfaceContent.trim() + '\n ' + newFields;
75
+ entityContent = entityContent.replace(interfaceRegex, `export interface I${tableCapitalized} extends mongoose.Document {$1${updatedInterfaceContent}\n}`);
76
+ }
77
+
78
+ fs.writeFileSync(entityPath, entityContent);
79
+ }
80
+
81
+ function updateSchema(schemaPath: string, tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): void {
82
+ let schemaContent = fs.readFileSync(schemaPath, 'utf8');
83
+
84
+ // Add import for the related schema
85
+ const importStatement = `import { ${relatedTableCapitalized}Entity } from './${direction === 'forward' ? relatedTableCapitalized.toLowerCase() : relatedTableCapitalized.toLowerCase()}';`;
86
+ if (!schemaContent.includes(importStatement)) {
87
+ // Find the last import statement and add after it
88
+ const importRegex = /import.*from.*['"];?\s*$/gm;
89
+ const matches = [...schemaContent.matchAll(importRegex)];
90
+ if (matches.length > 0) {
91
+ const lastImport = matches[matches.length - 1];
92
+ const insertIndex = lastImport.index! + lastImport[0].length;
93
+ schemaContent = schemaContent.slice(0, insertIndex) + '\n' + importStatement + schemaContent.slice(insertIndex);
94
+ }
95
+ }
96
+
97
+ // Add schema fields based on relationship type
98
+ const schemaRegex = /export const \w+Schema = new mongoose\.Schema\(([^)]*),/s;
99
+ const match = schemaContent.match(schemaRegex);
100
+
101
+ if (match) {
102
+ const schemaFields = match[1];
103
+ const newFields = generateSchemaFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
104
+
105
+ // Add new fields before the closing brace
106
+ const updatedSchemaFields = schemaFields.trim() + '\n ' + newFields;
107
+ schemaContent = schemaContent.replace(schemaRegex, `export const ${tableCapitalized.toLowerCase()}Schema = new mongoose.Schema(${updatedSchemaFields},`);
108
+ }
109
+
110
+ // Add virtual fields and population methods
111
+ const modelRegex = /export const \w+Entity = mongoose\.model<.*>\(.*\);?\s*$/;
112
+ const virtualFields = generateVirtualFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
113
+
114
+ if (virtualFields) {
115
+ schemaContent = schemaContent.replace(modelRegex, `${virtualFields}\n\n$&`);
116
+ }
117
+
118
+ fs.writeFileSync(schemaPath, schemaContent);
119
+ }
120
+
121
+ function generateEntityFields(tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): string {
122
+ switch (relationType) {
123
+ case 'one-to-one':
124
+ if (direction === 'forward') {
125
+ return `${relatedTableCapitalized.toLowerCase()}Id: ObjectId,\n ${relatedTableCapitalized.toLowerCase()}?: I${relatedTableCapitalized}`;
126
+ } else {
127
+ return `${tableCapitalized.toLowerCase()}Id: ObjectId,\n ${tableCapitalized.toLowerCase()}?: I${tableCapitalized}`;
128
+ }
129
+
130
+ case 'one-to-many':
131
+ if (direction === 'forward') {
132
+ return `${relatedTableCapitalized.toLowerCase()}Id: ObjectId,\n ${relatedTableCapitalized.toLowerCase()}?: I${relatedTableCapitalized}`;
133
+ } else {
134
+ return `${tableCapitalized.toLowerCase()}s?: I${tableCapitalized}[]`;
135
+ }
136
+
137
+ case 'many-to-many':
138
+ if (direction === 'forward') {
139
+ return `${relatedTableCapitalized.toLowerCase()}Ids: ObjectId[],\n ${relatedTableCapitalized.toLowerCase()}s?: I${relatedTableCapitalized}[]`;
140
+ } else {
141
+ return `${tableCapitalized.toLowerCase()}Ids: ObjectId[],\n ${tableCapitalized.toLowerCase()}s?: I${tableCapitalized}[]`;
142
+ }
143
+
144
+ default:
145
+ return '';
146
+ }
147
+ }
148
+
149
+ function generateSchemaFields(tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): string {
150
+ switch (relationType) {
151
+ case 'one-to-one':
152
+ if (direction === 'forward') {
153
+ return `${relatedTableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}',\n required: false\n }`;
154
+ } else {
155
+ return `${tableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${tableCapitalized.toLowerCase()}',\n required: false\n }`;
156
+ }
157
+
158
+ case 'one-to-many':
159
+ if (direction === 'forward') {
160
+ return `${relatedTableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}',\n required: false\n }`;
161
+ } else {
162
+ return ''; // No field needed for reverse one-to-many
163
+ }
164
+
165
+ case 'many-to-many':
166
+ if (direction === 'forward') {
167
+ return `${relatedTableCapitalized.toLowerCase()}Ids: [{\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}'\n }]`;
168
+ } else {
169
+ return `${tableCapitalized.toLowerCase()}Ids: [{\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${tableCapitalized.toLowerCase()}'\n }]`;
170
+ }
171
+
172
+ default:
173
+ return '';
174
+ }
175
+ }
176
+
177
+ function generateVirtualFields(tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): string {
178
+ switch (relationType) {
179
+ case 'one-to-one':
180
+ if (direction === 'forward') {
181
+ return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '${relatedTableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
182
+ } else {
183
+ return `// Virtual populate for ${tableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '${tableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
184
+ }
185
+
186
+ case 'one-to-many':
187
+ if (direction === 'forward') {
188
+ return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '${relatedTableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
189
+ } else {
190
+ return `// Virtual populate for ${tableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}s', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '_id',\n foreignField: '${tableCapitalized.toLowerCase()}Id'\n});`;
191
+ }
192
+
193
+ case 'many-to-many':
194
+ if (direction === 'forward') {
195
+ return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}s', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '${relatedTableCapitalized.toLowerCase()}Ids',\n foreignField: '_id'\n});`;
196
+ } else {
197
+ return `// Virtual populate for ${tableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}s', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '${tableCapitalized.toLowerCase()}Ids',\n foreignField: '_id'\n});`;
198
+ }
199
+
200
+ default:
201
+ return '';
202
+ }
203
+ }