micro-generate 1.3.10 → 1.3.12
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.
- package/README.md +83 -9
- package/dist/cli/generators/add-mongo-generator.d.ts +4 -0
- package/dist/cli/generators/add-mongo-generator.js +212 -0
- package/dist/cli/generators/add-mongo-generator.js.map +1 -0
- package/dist/cli/generators/add-mysql-generator.d.ts +4 -0
- package/dist/cli/generators/add-mysql-generator.js +221 -0
- package/dist/cli/generators/add-mysql-generator.js.map +1 -0
- package/dist/cli/generators/add-redis-generator.d.ts +1 -0
- package/dist/cli/generators/add-redis-generator.js +100 -0
- package/dist/cli/generators/add-redis-generator.js.map +1 -0
- package/dist/cli/generators/feature-generator.js +26 -338
- package/dist/cli/generators/feature-generator.js.map +1 -1
- package/dist/cli/generators/init-generator.js +31 -649
- package/dist/cli/generators/init-generator.js.map +1 -1
- package/dist/cli/generators/model-generator.d.ts +6 -0
- package/dist/cli/generators/model-generator.js +50 -0
- package/dist/cli/generators/model-generator.js.map +1 -0
- package/dist/cli/index.js +71 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/templates/feature/mongoModel.template.d.ts +6 -0
- package/dist/cli/templates/feature/mongoModel.template.js +57 -0
- package/dist/cli/templates/feature/mongoModel.template.js.map +1 -0
- package/dist/cli/templates/feature/mysqlModel.template.d.ts +6 -0
- package/dist/cli/templates/feature/mysqlModel.template.js +62 -0
- package/dist/cli/templates/feature/mysqlModel.template.js.map +1 -0
- package/dist/cli/templates/feature/resolvers.template.d.ts +1 -0
- package/dist/cli/templates/feature/resolvers.template.js +21 -0
- package/dist/cli/templates/feature/resolvers.template.js.map +1 -0
- package/dist/cli/templates/feature/service.template.d.ts +11 -0
- package/dist/cli/templates/feature/service.template.js +68 -0
- package/dist/cli/templates/feature/service.template.js.map +1 -0
- package/dist/cli/templates/feature/typeDefs.template.d.ts +1 -0
- package/dist/cli/templates/feature/typeDefs.template.js +24 -0
- package/dist/cli/templates/feature/typeDefs.template.js.map +1 -0
- package/dist/cli/templates/project/api.template.d.ts +1 -0
- package/dist/cli/templates/project/api.template.js +40 -0
- package/dist/cli/templates/project/api.template.js.map +1 -0
- package/dist/cli/templates/project/config.template.d.ts +1 -0
- package/dist/cli/templates/project/config.template.js +12 -0
- package/dist/cli/templates/project/config.template.js.map +1 -0
- package/dist/cli/templates/project/featuresIndex.template.d.ts +1 -0
- package/dist/cli/templates/project/featuresIndex.template.js +4 -0
- package/dist/cli/templates/project/featuresIndex.template.js.map +1 -0
- package/dist/cli/templates/project/index.template.d.ts +8 -0
- package/dist/cli/templates/project/index.template.js +104 -0
- package/dist/cli/templates/project/index.template.js.map +1 -0
- package/dist/cli/templates/project/mongo.template.d.ts +1 -0
- package/dist/cli/templates/project/mongo.template.js +51 -0
- package/dist/cli/templates/project/mongo.template.js.map +1 -0
- package/dist/cli/templates/project/mongoClient.template.d.ts +1 -0
- package/dist/cli/templates/project/mongoClient.template.js +21 -0
- package/dist/cli/templates/project/mongoClient.template.js.map +1 -0
- package/dist/cli/templates/project/mysqlClient.template.d.ts +1 -0
- package/dist/cli/templates/project/mysqlClient.template.js +18 -0
- package/dist/cli/templates/project/mysqlClient.template.js.map +1 -0
- package/dist/cli/templates/project/redis.template.d.ts +1 -0
- package/dist/cli/templates/project/redis.template.js +255 -0
- package/dist/cli/templates/project/redis.template.js.map +1 -0
- package/dist/cli/templates/project/sanitize.template.d.ts +1 -0
- package/dist/cli/templates/project/sanitize.template.js +11 -0
- package/dist/cli/templates/project/sanitize.template.js.map +1 -0
- package/dist/cli/templates/project/skill.template.d.ts +1 -0
- package/dist/cli/templates/project/skill.template.js +147 -0
- package/dist/cli/templates/project/skill.template.js.map +1 -0
- package/dist/cli/templates/project/tsconfig.template.d.ts +1 -0
- package/dist/cli/templates/project/tsconfig.template.js +17 -0
- package/dist/cli/templates/project/tsconfig.template.js.map +1 -0
- package/dist/core/MicroserviceServer.d.ts +4 -0
- package/dist/core/MicroserviceServer.js +13 -0
- package/dist/core/MicroserviceServer.js.map +1 -1
- package/dist/database/mysql.d.ts +23 -0
- package/dist/database/mysql.js +68 -0
- package/dist/database/mysql.js.map +1 -0
- package/dist/database/redis.d.ts +1 -1
- package/dist/database/redis.js +6 -8
- package/dist/database/redis.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { redisTemplate } from '../templates/project/redis.template.js';
|
|
5
|
+
export const addRedis = async () => {
|
|
6
|
+
const projectRoot = process.cwd();
|
|
7
|
+
const indexPath = path.join(projectRoot, 'src', 'index.ts');
|
|
8
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
9
|
+
// 1. Validations
|
|
10
|
+
if (!await fs.pathExists(indexPath)) {
|
|
11
|
+
console.error(chalk.red('❌ src/index.ts not found. Are you in the root of the project?'));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const redisConnectorPath = path.join(projectRoot, 'src', 'database', 'redis.ts');
|
|
15
|
+
if (await fs.pathExists(redisConnectorPath)) {
|
|
16
|
+
console.warn(chalk.yellow('⚠️ Redis is already configured in this project.'));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
console.log(chalk.blue('Adding Redis support to your project...'));
|
|
20
|
+
try {
|
|
21
|
+
// 2. Create src/database/redis.ts
|
|
22
|
+
await fs.ensureDir(path.dirname(redisConnectorPath));
|
|
23
|
+
await fs.writeFile(redisConnectorPath, redisTemplate);
|
|
24
|
+
console.log(chalk.green('✅ Created src/database/redis.ts'));
|
|
25
|
+
// 3. Add to package.json dependencies
|
|
26
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
27
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
28
|
+
packageJson.dependencies = packageJson.dependencies || {};
|
|
29
|
+
if (!packageJson.dependencies.ioredis) {
|
|
30
|
+
packageJson.dependencies.ioredis = '^5.3.2';
|
|
31
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
32
|
+
console.log(chalk.green('✅ Added ioredis to package.json dependencies'));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log(chalk.blue('ℹ️ ioredis is already in package.json dependencies'));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 4. Update .env and .env.example files
|
|
39
|
+
const envVars = `
|
|
40
|
+
# Redis Config
|
|
41
|
+
REDIS_HOST=localhost
|
|
42
|
+
REDIS_PORT=6379
|
|
43
|
+
REDIS_PASSWORD=
|
|
44
|
+
REDIS_DB=0
|
|
45
|
+
`;
|
|
46
|
+
const updateEnvFile = async (fileName) => {
|
|
47
|
+
const envPath = path.join(projectRoot, fileName);
|
|
48
|
+
if (await fs.pathExists(envPath)) {
|
|
49
|
+
let content = await fs.readFile(envPath, 'utf-8');
|
|
50
|
+
if (!content.includes('REDIS_HOST')) {
|
|
51
|
+
// Append envVars ensuring correct spacing
|
|
52
|
+
content = content.trimEnd() + '\n' + envVars;
|
|
53
|
+
await fs.writeFile(envPath, content);
|
|
54
|
+
console.log(chalk.green(`✅ Added Redis variables to ${fileName}`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
await updateEnvFile('.env');
|
|
59
|
+
await updateEnvFile('.env.example');
|
|
60
|
+
// 5. Inject Redis setup in src/index.ts
|
|
61
|
+
let indexContent = await fs.readFile(indexPath, 'utf-8');
|
|
62
|
+
// Check and inject import
|
|
63
|
+
const importStatement = `import { createRedisConnector } from './database/redis.js';\n`;
|
|
64
|
+
if (!indexContent.includes('createRedisConnector')) {
|
|
65
|
+
indexContent = importStatement + indexContent;
|
|
66
|
+
console.log(chalk.green('✅ Injected Redis import in src/index.ts'));
|
|
67
|
+
}
|
|
68
|
+
// Check and inject instantiation
|
|
69
|
+
const redisInit = `const redisConnector = createRedisConnector({
|
|
70
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
71
|
+
port: parseInt(process.env.REDIS_PORT || '6379'),
|
|
72
|
+
password: process.env.REDIS_PASSWORD,
|
|
73
|
+
db: parseInt(process.env.REDIS_DB || '0')
|
|
74
|
+
});\n\n`;
|
|
75
|
+
if (!indexContent.includes('const redisConnector =')) {
|
|
76
|
+
const serverInstantiationRegex = /const\s+server\s*=\s*new\s+MicroserviceServer/;
|
|
77
|
+
if (indexContent.match(serverInstantiationRegex)) {
|
|
78
|
+
indexContent = indexContent.replace(serverInstantiationRegex, (match) => `${redisInit}${match}`);
|
|
79
|
+
console.log(chalk.green('✅ Injected redisConnector instantiation in src/index.ts'));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.warn(chalk.yellow('⚠️ Could not find MicroserviceServer instantiation in src/index.ts. You might need to manually instantiate redisConnector.'));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Check and inject parameter in MicroserviceServer constructor options
|
|
86
|
+
if (!indexContent.includes('redisConnector:')) {
|
|
87
|
+
const serverConstructorOptionsRegex = /new\s+MicroserviceServer\s*\(\{/;
|
|
88
|
+
if (indexContent.match(serverConstructorOptionsRegex)) {
|
|
89
|
+
indexContent = indexContent.replace(serverConstructorOptionsRegex, (match) => `${match}\n redisConnector: redisConnector,`);
|
|
90
|
+
console.log(chalk.green('✅ Injected redisConnector into MicroserviceServer configuration in src/index.ts'));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
await fs.writeFile(indexPath, indexContent);
|
|
94
|
+
console.log(chalk.green('🎉 Redis support added successfully! Please run npm install to update your local dependencies.'));
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error(chalk.red('❌ An error occurred while adding Redis:'), error);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=add-redis-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-redis-generator.js","sourceRoot":"","sources":["../../../src/cli/generators/add-redis-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
+
import { getTypeDefsTemplate } from '../templates/feature/typeDefs.template.js';
|
|
5
|
+
import { getResolversTemplate } from '../templates/feature/resolvers.template.js';
|
|
6
|
+
import { getServiceTemplate } from '../templates/feature/service.template.js';
|
|
7
|
+
import { getMongoModelTemplate } from '../templates/feature/mongoModel.template.js';
|
|
8
|
+
import { getMySQLModelTemplate } from '../templates/feature/mysqlModel.template.js';
|
|
9
|
+
import { mysqlClientTemplate } from '../templates/project/mysqlClient.template.js';
|
|
4
10
|
// Helper for generating Mongo model content
|
|
5
11
|
async function generateModel(options) {
|
|
6
12
|
const { entityName, featurePath, dbConnectionName } = options;
|
|
@@ -10,67 +16,11 @@ async function generateModel(options) {
|
|
|
10
16
|
await fs.ensureDir(modelsPath);
|
|
11
17
|
const toPascalCase = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
12
18
|
const toKebabCase = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
13
|
-
// Simple pluralizer fallback
|
|
14
19
|
const pluralize = (s) => s.endsWith('s') ? s : s + 's';
|
|
15
20
|
const modelName = toPascalCase(entityName);
|
|
16
21
|
const fileName = `${toKebabCase(entityName)}.model.ts`;
|
|
17
22
|
const collectionName = pluralize(entityName).toLowerCase();
|
|
18
|
-
|
|
19
|
-
if (dbConnectionName) {
|
|
20
|
-
// SECONDARY CONNECTION: Export function to get model (lazy loading)
|
|
21
|
-
modelContent = `import { Schema, Document, Model } from 'mongoose';
|
|
22
|
-
import { getSecondaryConnection } from '../../../database/mongo/client.js';
|
|
23
|
-
|
|
24
|
-
export interface I${modelName} extends Document {
|
|
25
|
-
createdAt: Date;
|
|
26
|
-
updatedAt: Date;
|
|
27
|
-
// TODO: Add your custom fields here
|
|
28
|
-
[key: string]: any;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const ${modelName}Schema: Schema = new Schema({
|
|
32
|
-
// TODO: Define your schema fields
|
|
33
|
-
}, {
|
|
34
|
-
timestamps: true,
|
|
35
|
-
collection: '${collectionName}'
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
let ${modelName}Model: Model<I${modelName}>;
|
|
39
|
-
|
|
40
|
-
export function get${modelName}Model(): Model<I${modelName}> {
|
|
41
|
-
if (${modelName}Model) return ${modelName}Model;
|
|
42
|
-
|
|
43
|
-
const connection = getSecondaryConnection('${dbConnectionName}');
|
|
44
|
-
if (!connection) {
|
|
45
|
-
throw new Error('Database connection "${dbConnectionName}" not found');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
${modelName}Model = connection.model<I${modelName}>('${modelName}', ${modelName}Schema);
|
|
49
|
-
return ${modelName}Model;
|
|
50
|
-
}
|
|
51
|
-
`;
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
// DEFAULT CONNECTION: Export model directly
|
|
55
|
-
modelContent = `import mongoose, { Schema, Document } from 'mongoose';
|
|
56
|
-
|
|
57
|
-
export interface I${modelName} extends Document {
|
|
58
|
-
createdAt: Date;
|
|
59
|
-
updatedAt: Date;
|
|
60
|
-
// TODO: Add your custom fields here
|
|
61
|
-
[key: string]: any;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const ${modelName}Schema: Schema = new Schema({
|
|
65
|
-
// TODO: Define your schema fields
|
|
66
|
-
}, {
|
|
67
|
-
timestamps: true,
|
|
68
|
-
collection: '${collectionName}'
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
export const ${modelName}Model = mongoose.model<I${modelName}>('${modelName}', ${modelName}Schema);
|
|
72
|
-
`;
|
|
73
|
-
}
|
|
23
|
+
const modelContent = getMongoModelTemplate({ modelName, collectionName, dbConnectionName });
|
|
74
24
|
const filePath = path.join(modelsPath, fileName);
|
|
75
25
|
await fs.writeFile(filePath, modelContent);
|
|
76
26
|
return fileName; // Return filename to use in service import
|
|
@@ -84,70 +34,11 @@ async function generateMySQLModel(options) {
|
|
|
84
34
|
await fs.ensureDir(modelsPath);
|
|
85
35
|
const toPascalCase = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
86
36
|
const toKebabCase = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
87
|
-
// Simple pluralizer fallback
|
|
88
37
|
const pluralize = (s) => s.endsWith('s') ? s : s + 's';
|
|
89
38
|
const modelName = toPascalCase(entityName);
|
|
90
39
|
const fileName = `${toKebabCase(entityName)}.model.ts`;
|
|
91
40
|
const tableName = pluralize(entityName).toLowerCase();
|
|
92
|
-
|
|
93
|
-
const importStatement = dbConnectionName
|
|
94
|
-
? `import { getSecondaryMySQLConnection } from '../client.js';`
|
|
95
|
-
: `import getDefaultMySQLConnection from '../client.js';`;
|
|
96
|
-
const connectionLogic = dbConnectionName
|
|
97
|
-
? `const sequelize = getSecondaryMySQLConnection('${dbConnectionName}');`
|
|
98
|
-
: `const sequelize = getDefaultMySQLConnection();`;
|
|
99
|
-
const connectionNameLog = dbConnectionName || 'default';
|
|
100
|
-
const modelContent = `import { DataTypes, Model, Optional } from 'sequelize';
|
|
101
|
-
${importStatement}
|
|
102
|
-
|
|
103
|
-
interface ${modelName}Attributes {
|
|
104
|
-
id: number;
|
|
105
|
-
name: string;
|
|
106
|
-
createdAt?: Date;
|
|
107
|
-
updatedAt?: Date;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
interface ${modelName}CreationAttributes extends Optional<${modelName}Attributes, 'id'> {}
|
|
111
|
-
|
|
112
|
-
export class ${modelName} extends Model<${modelName}Attributes, ${modelName}CreationAttributes> implements ${modelName}Attributes {
|
|
113
|
-
public id!: number;
|
|
114
|
-
public name!: string;
|
|
115
|
-
public readonly createdAt!: Date;
|
|
116
|
-
public readonly updatedAt!: Date;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let initialized = false;
|
|
120
|
-
|
|
121
|
-
export function get${modelName}Model() {
|
|
122
|
-
if (initialized) return ${modelName};
|
|
123
|
-
|
|
124
|
-
${connectionLogic}
|
|
125
|
-
if (!sequelize) {
|
|
126
|
-
throw new Error('Database connection "${connectionNameLog}" not found or not initialized');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
${modelName}.init(
|
|
130
|
-
{
|
|
131
|
-
id: {
|
|
132
|
-
type: DataTypes.INTEGER.UNSIGNED,
|
|
133
|
-
autoIncrement: true,
|
|
134
|
-
primaryKey: true,
|
|
135
|
-
},
|
|
136
|
-
name: {
|
|
137
|
-
type: DataTypes.STRING(128),
|
|
138
|
-
allowNull: false,
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
tableName: '${tableName}',
|
|
143
|
-
sequelize,
|
|
144
|
-
}
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
initialized = true;
|
|
148
|
-
return ${modelName};
|
|
149
|
-
}
|
|
150
|
-
`;
|
|
41
|
+
const modelContent = getMySQLModelTemplate({ modelName, tableName, dbConnectionName });
|
|
151
42
|
const filePath = path.join(modelsPath, fileName);
|
|
152
43
|
await fs.writeFile(filePath, modelContent);
|
|
153
44
|
return fileName;
|
|
@@ -161,30 +52,7 @@ export const generateFeature = async (options) => {
|
|
|
161
52
|
}
|
|
162
53
|
await fs.ensureDir(featurePath);
|
|
163
54
|
const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
164
|
-
const toKebabCase = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
165
55
|
const pascalName = capitalize(name);
|
|
166
|
-
// TypeDefs
|
|
167
|
-
const typeDefsContent = `export const typeDefs = \`#graphql
|
|
168
|
-
type ${pascalName} {
|
|
169
|
-
id: ID!
|
|
170
|
-
name: String
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
type ${pascalName}Response {
|
|
174
|
-
success: Boolean!
|
|
175
|
-
message: String!
|
|
176
|
-
data: ${pascalName}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
type Query {
|
|
180
|
-
${name}s: [${pascalName}]
|
|
181
|
-
${name}(id: ID!): ${pascalName}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
type Mutation {
|
|
185
|
-
create${pascalName}(name: String!): ${pascalName}Response
|
|
186
|
-
}
|
|
187
|
-
\`;`;
|
|
188
56
|
// Model Generation
|
|
189
57
|
let generatedModelFileName = '';
|
|
190
58
|
if (useMongo) {
|
|
@@ -192,211 +60,31 @@ export const generateFeature = async (options) => {
|
|
|
192
60
|
generatedModelFileName = generatedModelFileName.replace('.ts', '.js');
|
|
193
61
|
}
|
|
194
62
|
if (useMySQL) {
|
|
195
|
-
// Use mysqlDbConnectionName specifically for MySQL
|
|
196
|
-
generatedModelFileName = await generateMySQLModel({ ...options, dbConnectionName: mysqlDbConnectionName, entityName: name, featurePath });
|
|
197
|
-
generatedModelFileName = generatedModelFileName.replace('.ts', '.js');
|
|
198
|
-
}
|
|
199
|
-
// Service
|
|
200
|
-
let serviceImports = '';
|
|
201
|
-
let serviceClassBody = '';
|
|
202
|
-
if (useMongo) {
|
|
203
|
-
// Import from centralized location: ../../database/mongo/models/NAME.model.js
|
|
204
|
-
serviceImports += `import { ${dbConnectionName ? `get${pascalName}Model` : `${pascalName}Model`}, I${pascalName} } from '../../database/mongo/models/${generatedModelFileName}';\n`;
|
|
205
|
-
// Define how to access the model
|
|
206
|
-
const modelAccess = dbConnectionName ? `get${pascalName}Model()` : `${pascalName}Model`;
|
|
207
|
-
serviceClassBody += `
|
|
208
|
-
async getAll(): Promise<I${pascalName}[]> {
|
|
209
|
-
return ${modelAccess}.find();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async create(name: string): Promise<I${pascalName}> {
|
|
213
|
-
return ${modelAccess}.create({ name });
|
|
214
|
-
}
|
|
215
|
-
`;
|
|
216
|
-
}
|
|
217
|
-
else if (useMySQL) {
|
|
218
63
|
// Ensure MySQL Client exists
|
|
219
64
|
const clientPath = path.join(process.cwd(), 'src', 'database', 'mysql', 'client.ts');
|
|
220
65
|
if (!await fs.pathExists(clientPath)) {
|
|
221
66
|
console.log(chalk.yellow('MySQL client not found. Creating default client...'));
|
|
222
67
|
await fs.ensureDir(path.dirname(clientPath));
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
export interface MySQLConfig {
|
|
226
|
-
name?: string; // 'default' or others
|
|
227
|
-
database: string;
|
|
228
|
-
user: string;
|
|
229
|
-
password?: string;
|
|
230
|
-
host: string;
|
|
231
|
-
port: number;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export class MySQLConnector {
|
|
235
|
-
private connections: Map<string, Sequelize> = new Map();
|
|
236
|
-
private configs: MySQLConfig[];
|
|
237
|
-
|
|
238
|
-
constructor(configs: MySQLConfig[]) {
|
|
239
|
-
this.configs = configs;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
public async connect(): Promise<void> {
|
|
243
|
-
for (const config of this.configs) {
|
|
244
|
-
const sequelize = new Sequelize(config.database, config.user, config.password, {
|
|
245
|
-
host: config.host,
|
|
246
|
-
port: config.port,
|
|
247
|
-
dialect: 'mysql',
|
|
248
|
-
logging: process.env.NODE_ENV === 'development' ? console.log : false,
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
await sequelize.authenticate();
|
|
253
|
-
console.log(\`MySQL Connection (\${config.name || 'default'}) established successfully.\`);
|
|
254
|
-
this.connections.set(config.name || 'default', sequelize);
|
|
255
|
-
} catch (error) {
|
|
256
|
-
console.error(\`Unable to connect to the MySQL database (\${config.name || 'default'}):\`, error);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
public getConnection(name: string = 'default'): Sequelize | undefined {
|
|
262
|
-
return this.connections.get(name);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
public getSecondaryConnection(name: string): Sequelize | undefined {
|
|
266
|
-
return this.connections.get(name);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
let mysqlConnector: MySQLConnector | null = null;
|
|
271
|
-
|
|
272
|
-
export const setMySQLConnector = (connector: MySQLConnector) => {
|
|
273
|
-
mysqlConnector = connector;
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
export const getMySQLConnector = (): MySQLConnector => {
|
|
277
|
-
if (!mysqlConnector) throw new Error('MySQL Connector not initialized');
|
|
278
|
-
return mysqlConnector;
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
export const getSecondaryMySQLConnection = (name: string): Sequelize | undefined => {
|
|
282
|
-
return getMySQLConnector().getSecondaryConnection(name);
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
export default () => {
|
|
286
|
-
try {
|
|
287
|
-
return getMySQLConnector().getConnection('default');
|
|
288
|
-
} catch (e) {
|
|
289
|
-
// Fallback for single DB scenarios or before init
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
`;
|
|
294
|
-
await fs.writeFile(clientPath, mysqlClientContent);
|
|
68
|
+
await fs.writeFile(clientPath, mysqlClientTemplate);
|
|
295
69
|
}
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
serviceClassBody += `
|
|
300
|
-
async getAll(): Promise<${pascalName}[]> {
|
|
301
|
-
return ${modelAccess}.findAll();
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
async create(name: string): Promise<${pascalName}> {
|
|
305
|
-
return ${modelAccess}.create({ name });
|
|
306
|
-
}
|
|
307
|
-
`;
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
// In-memory or Redis-only fallback for types
|
|
311
|
-
serviceClassBody += `
|
|
312
|
-
async getAll(): Promise<any[]> {
|
|
313
|
-
return [{ id: '1', name: 'Test (No Mongo/MySQL)' }];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async create(name: string): Promise<any> {
|
|
317
|
-
return { id: Math.random().toString(), name };
|
|
318
|
-
}
|
|
319
|
-
`;
|
|
320
|
-
}
|
|
321
|
-
if (useRedis) {
|
|
322
|
-
// Import from src/database/redis.js which matches user structure
|
|
323
|
-
serviceImports += `import { getRedisConnector, createRedisRepository } from '../../database/redis.js';\n`;
|
|
324
|
-
// Add repository property to class
|
|
325
|
-
// Logic to determine client access method
|
|
326
|
-
const redisDbNum = options.redisDb || 0;
|
|
327
|
-
// Let's check `src/database/redis/client.ts` or usage.
|
|
328
|
-
// Existing template used `getRedisClient`.
|
|
329
|
-
// In my Redis implementation, `createRedisConnector` returns the connector instance.
|
|
330
|
-
// If `getRedisClient` in the project returns the connector, then we can do .getConnection(N).
|
|
331
|
-
// However, the previous code in feature-generator.ts was:
|
|
332
|
-
// private redis = createRedisRepository(getRedisClient, '${name}:');
|
|
333
|
-
// This suggests createdRedisRepository expects a function ?
|
|
334
|
-
// Let's assume looking at standard micro-generate pattern:
|
|
335
|
-
// createRedisRepository(getConnectionFn, prefix).
|
|
336
|
-
// IF we want to support dynamic db, we might need to wrap it.
|
|
337
|
-
// Let's assume `getRedisClient` returns the *Connector* in the new world?
|
|
338
|
-
// No, `getRedisClient` usually returns the *Client* (ioredis instance) in simple setups.
|
|
339
|
-
// BUT my new `RedisConnector` has `getClient()` and `getConnection(n)`.
|
|
340
|
-
// Let's assume the user's `src/database/redis/client.ts` helps here.
|
|
341
|
-
// WAIT - I haven't seen `src/database/redis/client.ts`.
|
|
342
|
-
// The `server.ts` uses `createRedisConnector`.
|
|
343
|
-
// The feature generator standard template assumes `../../database/redis/client.js` exists.
|
|
344
|
-
// I should use `redisConnector` pattern if possible.
|
|
345
|
-
// If I look at `server.ts`, it imports `createRedisConnector`.
|
|
346
|
-
// The feature generator imports `getRedisClient` from `../../database/redis/client.js`.
|
|
347
|
-
if (redisDbNum > 0) {
|
|
348
|
-
serviceClassBody = `
|
|
349
|
-
private redis = createRedisRepository(
|
|
350
|
-
async () => {
|
|
351
|
-
return getRedisConnector().getConnection(${redisDbNum});
|
|
352
|
-
},
|
|
353
|
-
'${name}:'
|
|
354
|
-
);
|
|
355
|
-
` + serviceClassBody;
|
|
356
|
-
}
|
|
357
|
-
else {
|
|
358
|
-
serviceClassBody = `
|
|
359
|
-
private redis = createRedisRepository(
|
|
360
|
-
async () => {
|
|
361
|
-
return getRedisConnector().getConnection(0);
|
|
362
|
-
},
|
|
363
|
-
'${name}:'
|
|
364
|
-
);
|
|
365
|
-
` + serviceClassBody;
|
|
366
|
-
}
|
|
367
|
-
serviceClassBody += `
|
|
368
|
-
async getCache(key: string): Promise<any> {
|
|
369
|
-
return this.redis.find(key);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
async setCache(key: string, value: string): Promise<any> {
|
|
373
|
-
return this.redis.saveTTL(key, value, 3600);
|
|
374
|
-
}
|
|
375
|
-
`;
|
|
70
|
+
// Use mysqlDbConnectionName specifically for MySQL
|
|
71
|
+
generatedModelFileName = await generateMySQLModel({ ...options, dbConnectionName: mysqlDbConnectionName, entityName: name, featurePath });
|
|
72
|
+
generatedModelFileName = generatedModelFileName.replace('.ts', '.js');
|
|
376
73
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const result = await ${name}Service.create(name);
|
|
392
|
-
return {
|
|
393
|
-
success: true,
|
|
394
|
-
message: '${pascalName} created successfully',
|
|
395
|
-
data: result,
|
|
396
|
-
};
|
|
397
|
-
},
|
|
398
|
-
},
|
|
399
|
-
};`;
|
|
74
|
+
// Service
|
|
75
|
+
const serviceContent = getServiceTemplate({
|
|
76
|
+
name,
|
|
77
|
+
pascalName,
|
|
78
|
+
useMongo,
|
|
79
|
+
useRedis,
|
|
80
|
+
useMySQL,
|
|
81
|
+
dbConnectionName,
|
|
82
|
+
generatedModelFileName,
|
|
83
|
+
redisDb: options.redisDb
|
|
84
|
+
});
|
|
85
|
+
// TypeDefs & Resolvers
|
|
86
|
+
const typeDefsContent = getTypeDefsTemplate(name, pascalName);
|
|
87
|
+
const resolversContent = getResolversTemplate(name, pascalName);
|
|
400
88
|
await fs.writeFile(path.join(featurePath, 'typeDefs.ts'), typeDefsContent);
|
|
401
89
|
await fs.writeFile(path.join(featurePath, 'resolvers.ts'), resolversContent);
|
|
402
90
|
await fs.writeFile(path.join(featurePath, 'service.ts'), serviceContent);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-generator.js","sourceRoot":"","sources":["../../../src/cli/generators/feature-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-generator.js","sourceRoot":"","sources":["../../../src/cli/generators/feature-generator.ts"],"names":[],"mappings":"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"}
|