Skip to content

Commit

Permalink
feat: Implemented CLI functionality for generating and deleting CRUD …
Browse files Browse the repository at this point in the history
…operations. Updated README with CLI documentation
  • Loading branch information
fadhlaouir committed Mar 18, 2024
1 parent bf9b221 commit 95bde0d
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 39 deletions.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ API Documentation [Swagger]
## Features

- Authentication and Authorization
- JWT Tokens, make requests with a token after login with `Authorization` header with value `Bearer yourToken` where `yourToken` will be returned in Login response.
- JWT Tokens, make requests with a token after login with `Authorization` header with value `Bearer yourToken` where `yourToken` will be returned in the Login response.
- Role Manage
- Update Profile/Password User Account
- Reset Password Mail using `nodemailer`
Expand All @@ -49,7 +49,7 @@ API Documentation [Swagger]
- Included API collection for Postman.
- Light-weight project.
- Linting with [Eslint](https://eslint.org/). (Airbnb style)
- Included CLI for generate CRUD operations.
- Included CLI for generating CRUD operations.
- husky for pre-commit hooks and lint-staged for running linters on git staged files.

## Software Requirements
Expand Down Expand Up @@ -169,9 +169,11 @@ If you need to add more controllers to the project just create a new file in `sr
2. Run the following command:

```bash
npm run generate-crud
npm run crud-operation
```

See the [CLI README](cli/README.md) section for more details on how to use the CLI to generate or delete CRUD operations.

Follow the prompts to select the CRUD type (empty or minimal) and provide the entity name. The tool will generate the necessary files for the CRUD operations based on your selection.

## Linting and Formatting
Expand Down Expand Up @@ -212,3 +214,15 @@ This project is open-sourced software licensed under the MIT License. See the LI
## Support

For any inquiries or issues, please contact [Support Email](raed.fadhlaoui@hotmail.com).

- **Optimization**: Improved readability by reorganizing the content and ensuring consistency in formatting.
- **Documentation Update**: Reflects the changes made to the CLI commands for generating and deleting CRUD operations.
- **Bug Fixes**: Resolved issues related to the CLI commands and the project structure.
- **Feature Addition**: Added support for generating empty and minimal CRUD operations using the CLI.
- **Code Quality**: Improved code quality by adding linting and formatting tools.
- **Security**: Updated dependencies to address security vulnerabilities.
- **Testing**: Added support for running tests using Jest.
- **Performance**: Improved performance by optimizing the code and removing unnecessary dependencies.
- **Refactoring**: Refactored the code to improve readability and maintainability.
- **Dependency Update**: Updated dependencies to their latest versions.
- **Configuration**: Updated the configuration files to reflect the changes made to the project structure.
55 changes: 55 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## CLI Commands

### How to Use CRUD Operations

To generate or delete CRUD operations, you can use the CLI provided in this project. The CLI allows you to automate the process of creating or removing CRUD (Create, Read, Update, Delete) operations for entities within a MongoDB database.

### Usage

#### Running the CLI

To run the CLI, execute the following command:

```bash
npm run crud-operation
```

Selecting Action
Upon running the CLI, you will be prompted to select an action to perform. You can choose between generating CRUD operations or deleting existing CRUD operations.

#### Generating CRUD Operations

If you select the option to generate CRUD operations, the CLI will guide you through the process. You will be prompted to enter the name of the entity for which you want to generate CRUD operations. Additionally, you will need to specify the type of CRUD operations you want to generate, whether empty or minimal.

#### Empty CRUD Operations

Empty CRUD operations include the basic structure for Create, Read, Update, and Delete operations. This option provides a starting point for implementing custom logic for each operation.

#### Minimal CRUD Operations

Minimal CRUD operations include a simplified version of Create, Read, Update, and Delete operations. This option provides basic functionality with minimal boilerplate code.

#### Deleting CRUD Operations

If you select the option to delete CRUD operations, the CLI will prompt you to enter the name of the entity for which you want to delete CRUD operations. Once confirmed, the CLI will remove all associated CRUD files for the specified entity.

### Example

Here's an example of how you can use the CLI to generate CRUD operations:

Run the CLI:

```bash
npm run crud-operation
```

1. Select the action "Generate CRUD."
2. Enter the name of the entity (e.g., "user") for which you want to generate CRUD operations.
3. Choose the type of CRUD operations (empty or minimal).
4. Follow the prompts to complete the generation process.

### Note

Ensure that you have the necessary permissions and dependencies installed before running the CLI. Additionally, make sure to review the generated CRUD files and modify them according to your application's requirements.

This documentation provides a clear overview of how to use the CLI to generate or delete CRUD operations in the project. Adjustments have been made to reflect the changes made in this version, including the implementation of delete CRUD and the change from `npm run generate-crud` to `npm run crud-operation`.
58 changes: 58 additions & 0 deletions cli/_/deleteCrud.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const fs = require('fs').promises;
const path = require('path');

/**
* Function to delete CRUD.
* @param {string} entity - The entity to delete CRUD for.
* @returns {Promise<void>} - A Promise that resolves when CRUD is deleted successfully
*/
async function deleteCrud(entity) {
try {
// Define the paths for model, controller, and route files
const modelPath = path.join(
__dirname,
'..',
'src',
'models',
`${entity}.model.js`,
);
const controllerPath = path.join(
__dirname,
'..',
'src',
'controllers',
`${entity}.controller.js`,
);
const routePath = path.join(
__dirname,
'..',
'src',
'routes',
`${entity}.route.js`,
);

// Remove the model, controller, and route files
await Promise.all([
fs.unlink(modelPath),
fs.unlink(controllerPath),
fs.unlink(routePath),
]);

// Remove routes reference from server.js
const serverFilePath = path.join(__dirname, '..', 'server.js');
let serverFileContent = await fs.readFile(serverFilePath, 'utf-8');
serverFileContent = serverFileContent.replace(
`const ${entity}Routes = require('./src/routes/${entity}.route');\napp.use('/v1/api', ${entity}Routes);\n`,
'',
);
await fs.writeFile(serverFilePath, serverFileContent);

console.log('CRUD deleted successfully for entity:', entity);
} catch (error) {
// Handle errors
console.error('An error occurred while deleting CRUD:', error);
throw error;
}
}

module.exports = { deleteCrud };
2 changes: 1 addition & 1 deletion cli/generateEmptyCrud.js → cli/_/generateEmptyCrud.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async function generateEmptyCrud(entity) {
]);

// Add route to server.js
const lineToAdd = `const ${entity}Routes = require('./src/routes/${entity}.route');\n\napp.use('/v1/api', ${entity}Routes);\n`;
const lineToAdd = `const ${entity}Routes = require('./src/routes/${entity}.route');\napp.use('/v1/api', ${entity}Routes);\n`;
try {
const serverFilePath = path.join('server.js');
let serverFileContent = await fs.readFile(serverFilePath, 'utf-8');
Expand Down
File renamed without changes.
File renamed without changes.
115 changes: 83 additions & 32 deletions cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,94 +5,145 @@
const inquirer = require('inquirer'); // For prompting user input

// Local helpers and functions
const { generateEmptyCrud } = require('./generateEmptyCrud'); // Function to generate empty CRUD
const { generateMinimalCrud } = require('./generateMinimalCrud'); // Function to generate minimal CRUD
const { isEntityExists } = require('./helpers'); // Function to check if entity already exists
const { generateEmptyCrud } = require('./_/generateEmptyCrud'); // Function to generate empty CRUD
const { generateMinimalCrud } = require('./_/generateMinimalCrud'); // Function to generate minimal CRUD
const { deleteCrud } = require('./_/deleteCrud'); // Function to delete CRUD
const { isEntityExists } = require('./_/helpers'); // Function to check if entity already exists

/* -------------------------------------------------------------------------- */
/* MAIN */
/* -------------------------------------------------------------------------- */
/**
* Main function to handle the CLI input and generate CRUD based on the user input.
* It prompts the user for the entity name and CRUD type, performs validation,
* checks if the entity already exists, and generates CRUD based on user input.
* @returns {Promise<void>} - A Promise that resolves when CRUD is generated successfully
* Main function to handle the CLI input for generating or deleting CRUD operations.
* It prompts the user for the action to perform and handles the corresponding action.
* @returns {Promise<void>} - A Promise that resolves when the action is performed successfully
*/
async function main() {
try {
// Parse command line arguments
const args = process.argv.slice(2);
// Interactive prompt for selecting action
const actionPrompt = {
type: 'list',
name: 'action',
message: 'Select action:',
choices: ['Generate CRUD', 'Delete CRUD', 'Exit'],
};

// Check if command is valid
if (args.length < 1 || args[0] !== 'generate') {
console.log('Invalid command. Use "generate" command.');
process.exit(1);
const { action } = await inquirer.prompt(actionPrompt);

switch (action) {
case 'Generate CRUD':
await generateCrud();
break;
case 'Delete CRUD':
await deleteCrudAction();
break;
case 'Exit':
console.log('Exiting...');
process.exit(0);
break;
default:
console.log('Invalid action:', action);
process.exit(1);
}
} catch (error) {
// Handle errors
console.error('An error occurred:', error);
process.exit(1);
}
}

/**
* Function to handle the CRUD generation process.
* @returns {Promise<void>} - A Promise that resolves when CRUD is generated successfully
*/
async function generateCrud() {
try {
// Prompt user to enter entity name
const entityPrompt = {
type: 'input',
name: 'entity',
message: 'Enter entity name:',
validate: async (input) => {
// Trim leading and trailing whitespace
const trimmedInput = input.trim();

// Check if entity name is empty after trimming
if (!trimmedInput) {
return 'Entity name cannot be empty';
}

// Check if entity name contains only alphanumeric characters and underscores
if (!/^[a-zA-Z0-9_]+$/.test(trimmedInput)) {
return 'Entity name can only contain letters, numbers, and underscores';
}

// Check if entity name already exists
const entityExists = await isEntityExists(trimmedInput);
if (entityExists) {
return `Entity "${trimmedInput}" already exists. Cannot generate CRUD.`;
}

// Validation passed
return true;
},
};

// Get entity name from user input
const { entity } = await inquirer.prompt(entityPrompt);

// Prompt user to select CRUD type
const commandPrompt = {
type: 'list',
name: 'command',
message: 'Select CRUD type:',
choices: ['empty', 'minimal'],
};

// Get CRUD type from user input
const { command } = await inquirer.prompt(commandPrompt);

// Generate CRUD based on user input
switch (command) {
case 'empty':
await generateEmptyCrud(entity, generateEmptyCrud);
await generateEmptyCrud(entity);
console.log('Empty CRUD generated successfully for entity:', entity);
console.log('Exiting...');
process.exit(0);
break;
case 'minimal':
await generateMinimalCrud(entity, generateMinimalCrud);
await generateMinimalCrud(entity);
console.log('Minimal CRUD generated successfully for entity:', entity);
console.log('Exiting...');
process.exit(0);
break;
default:
console.log('Invalid command:', command);
process.exit(1);
}
} catch (error) {
// Handle errors
console.error('An error occurred:', error);
console.error('An error occurred during CRUD generation:', error);
process.exit(1);
}
}

/**
* Function to handle the CRUD deletion process.
* @returns {Promise<void>} - A Promise that resolves when CRUD is deleted successfully
*/
async function deleteCrudAction() {
try {
// Prompt user to enter entity name for deletion
const entityPrompt = {
type: 'input',
name: 'entity',
message: 'Enter entity name to delete CRUD:',
validate: async (input) => {
const trimmedInput = input.trim();
if (!trimmedInput) {
return 'Entity name cannot be empty';
}
return true;
},
};

const { entity } = await inquirer.prompt(entityPrompt);
await deleteCrud(entity);
} catch (error) {
console.error('An error occurred during CRUD deletion:', error);
process.exit(1);
}
}

// Invoke main function
main();
// Invoke main function if the script is run directly
if (require.main === module) {
main();
}

module.exports = { generateCrud, deleteCrudAction };
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"scripts": {
"start": "NODE_ENV=production && node server.js",
"develop": "SET NODE_ENV=development && nodemon server.js",
"generate-crud": "node cli/index.js generate",
"create-operation": "node cli/index.js generate",
"lint:check": "eslint --ext .js,.jsx,.ts,.tsx .",
"format:check": "prettier --check .",
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx --fix .",
Expand Down
4 changes: 2 additions & 2 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* -------------------------------------------------------------------------- */
/* Dependencies */
/* -------------------------------------------------------------------------- */

// Packages
const express = require('express');
const dotenv = require('dotenv');
Expand Down Expand Up @@ -44,8 +43,9 @@ app.use(express.static(path.join(__dirname, 'uploads')));
app.use(cors());

// Require APIs
const authRoutes = require('./src/routes/auth.route');
const userRoutes = require('./src/routes/user.route');
const authRoutes = require('./src/routes/auth.route');


// local APIs
app.use('/v1/api', authRoutes);
Expand Down

0 comments on commit 95bde0d

Please sign in to comment.