nodejs-quickstart-structure 1.8.2 → 1.9.0
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/CHANGELOG.md +13 -1
- package/README.md +12 -7
- package/docs/generateCase.md +189 -141
- package/docs/generatorFlow.md +7 -3
- package/docs/ruleDevelop.md +5 -0
- package/lib/modules/caching-setup.js +16 -12
- package/lib/prompts.js +1 -1
- package/package.json +1 -1
- package/templates/clean-architecture/js/src/interfaces/routes/api.js +1 -1
- package/templates/common/Dockerfile +2 -2
- package/templates/common/README.md.ejs +4 -0
- package/templates/common/caching/clean/js/CreateUser.js.ejs +7 -3
- package/templates/common/caching/clean/js/GetAllUsers.js.ejs +9 -5
- package/templates/common/caching/clean/ts/createUser.ts.ejs +7 -3
- package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +9 -5
- package/templates/common/caching/js/memoryCache.js.ejs +60 -0
- package/templates/common/caching/ts/memoryCache.ts.ejs +64 -0
- package/templates/common/package.json.ejs +6 -2
- package/templates/mvc/js/src/controllers/userController.js.ejs +9 -7
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +9 -7
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.0] - 2026-02-22
|
|
9
|
+
### Added
|
|
10
|
+
- Implemented **Daily Template Vulnerability Audit** via GitHub Actions (`.github/workflows/daily-audit.yml`). A custom script now parses `package.json.ejs` daily to proactively scan for high-severity vulnerabilities in generated dependencies, ensuring generated projects are eternally secure.
|
|
11
|
+
- Added built-in **Memory Cache** (`node-cache`) integration as an alternative caching layer alongside Redis.
|
|
12
|
+
- Scaled up the generator matrix, now supporting over **160 Core Combinations** and **320 Total Scenarios** (including CI/CD pipelines).
|
|
13
|
+
- Configured dynamic cache service imports across both MVC and Clean Architecture controllers/usecases.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Fixed an ESLint TypeScript parsing error (`Type expected`) caused by unescaped EJS template variables in Clean Architecture usecases.
|
|
17
|
+
- Fixed a CLI execution bug where unquoted caching parameters (like `"Memory Cache"`) caused test validation failures.
|
|
18
|
+
- Updated the E2E Windows Validation test core to evaluate ESLint flat config files (`eslint.config.mjs`) instead of `.eslintrc.json`.
|
|
19
|
+
|
|
8
20
|
## [1.8.2] - 2026-02-22
|
|
9
21
|
### Fixed
|
|
10
22
|
- Hotfix: Changed `cpx2` command to its actual executable binary `cpx` in the build script. This resolves `sh: cpx2: not found` failures when running `npm run build` or `docker-compose up --build`.
|
|
@@ -101,4 +113,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
101
113
|
- Initial release of `nodejs-quickstart-structure`.
|
|
102
114
|
- Scaffolding for MVC and Clean Architecture.
|
|
103
115
|
- Support for Express.js.
|
|
104
|
-
- Database integration (MongoDB, MySQL, PostgreSQL)
|
|
116
|
+
- Database integration (MongoDB, MySQL, PostgreSQL)
|
package/README.md
CHANGED
|
@@ -6,6 +6,11 @@ A powerful CLI tool to scaffold production-ready Node.js microservices with buil
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
+
#### Security & Maintenance
|
|
10
|
+
When generating microservices, you inherit dependencies configured within `templates/common/package.json.ejs`. Since standard repository vulnerability scanners cannot natively parse EJS conditional tags, this generator implements a custom **Daily Template Vulnerability Audit** via GitHub Actions.
|
|
11
|
+
|
|
12
|
+
Every night, an extraction script compiles all possible template dependencies across all combinations (MongoDB, Kafka, Redis, Memory Cache, MySQL, PostgreSQL, etc) into a single map and performs a comprehensive `npm audit --audit-level=high`. If a severe vulnerability is ever identified in a third-party package utilized by the templates, the repository maintainers are instantly alerted to patch it, ensuring zero-day security gaps are mitigated instantly.
|
|
13
|
+
|
|
9
14
|
## Features
|
|
10
15
|
|
|
11
16
|
- **Interactive CLI**: Easy-to-use prompts to configure your project.
|
|
@@ -13,7 +18,7 @@ A powerful CLI tool to scaffold production-ready Node.js microservices with buil
|
|
|
13
18
|
- **Language Support**: Choose between **JavaScript** and **TypeScript**.
|
|
14
19
|
- **Database Integration**: Pre-configured setup for **MySQL**, **PostgreSQL**, or **MongoDB**.
|
|
15
20
|
- **Microservices Ready**: Optional **Kafka** integration for event-driven communication.
|
|
16
|
-
- **Caching Layer**:
|
|
21
|
+
- **Caching Layer**: Choose between **Redis** or built-in **Memory Cache** for data caching.
|
|
17
22
|
- **Dockerized**: Automatically generates `docker-compose.yml` for DB, Kafka, Redis, and Zookeeper.
|
|
18
23
|
- **Database Migrations/Schemas**: Integrated **Flyway** for SQL migrations or **Mongoose** schemas for MongoDB.
|
|
19
24
|
- **Professional Standards**: Generated projects come with highly professional, industry-standard tooling.
|
|
@@ -29,14 +34,14 @@ We don't just generate boilerplate; we generate **production-ready** foundations
|
|
|
29
34
|
- **⚓ Git Hooks**: `Husky` and `Lint-Staged` to ensure no bad code is ever committed.
|
|
30
35
|
- **🐳 DevOps**: Highly optimized **Multi-Stage Dockerfile** for small, secure production images.
|
|
31
36
|
|
|
32
|
-
## 🧩
|
|
37
|
+
## 🧩 160+ Project Combinations
|
|
33
38
|
|
|
34
39
|
The CLI supports a massive number of configurations to fit your exact needs:
|
|
35
40
|
|
|
36
|
-
- **
|
|
37
|
-
- **MVC Architecture**:
|
|
38
|
-
- **Clean Architecture**:
|
|
39
|
-
- **
|
|
41
|
+
- **160 Core Combinations**:
|
|
42
|
+
- **MVC Architecture**: 120 variants (Languages × View Engines × Databases × Communication Patterns × Caching)
|
|
43
|
+
- **Clean Architecture**: 40 variants (Languages × Databases × Communication Patterns × Caching)
|
|
44
|
+
- **320 Total Scenarios**:
|
|
40
45
|
- Every combination can be generated with or without **GitHub Actions CI/CD**, doubling the possibilities.
|
|
41
46
|
|
|
42
47
|
For a detailed list of all supported cases, check out [docs/generateCase.md](docs/generateCase.md).
|
|
@@ -67,7 +72,7 @@ The CLI will guide you through the following steps:
|
|
|
67
72
|
4. **Database**: `MySQL`, `PostgreSQL`, or `MongoDB`.
|
|
68
73
|
5. **Database Name**: The name of the initial database.
|
|
69
74
|
6. **Communication**: `REST APIs` (default) or `Kafka`.
|
|
70
|
-
7. **Caching**: `Redis
|
|
75
|
+
7. **Caching**: `None`, `Redis`, or `Memory Cache`.
|
|
71
76
|
8. **CI/CD**: `GitHub Actions`, `Jenkins`, `GitLab CI` or `None`.
|
|
72
77
|
|
|
73
78
|
## Generated Project Structure
|
package/docs/generateCase.md
CHANGED
|
@@ -1,141 +1,189 @@
|
|
|
1
|
-
# NodeJS Quickstart Generator - Test Cases
|
|
2
|
-
|
|
3
|
-
This document lists the **
|
|
4
|
-
|
|
5
|
-
## Summary
|
|
6
|
-
- **CI Providers**: `None`, `GitHub Actions`, `Jenkins`, `GitLab CI`
|
|
7
|
-
- **MVC Architecture**:
|
|
8
|
-
- **With Database (
|
|
9
|
-
- **No Database (12)**: 2 Lang × 3 View × 1 DB × 2 Comm = 12 * 1 (Caching: None) = 12
|
|
10
|
-
- **Clean Architecture**:
|
|
11
|
-
- **With Database (
|
|
12
|
-
- **No Database (4)**: 2 Lang × 1 View (None) × 1 DB × 2 Comm = 4 * 1 (Caching: None) = 4
|
|
13
|
-
|
|
14
|
-
**Total Core Combinations:
|
|
15
|
-
|
|
16
|
-
> **Note on CI/CD**: Each combination can be generated with or without CI/CD (`--ci-provider`), effectively doubling the state space.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## 1. MVC Architecture (
|
|
21
|
-
|
|
22
|
-
| # | Language | Architecture | View Engine | Database | Communication | Caching |
|
|
23
|
-
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
24
|
-
| 1 | JavaScript | MVC | None | MySQL | REST APIs | None |
|
|
25
|
-
| 2 | JavaScript | MVC | None | MySQL | REST APIs | Redis |
|
|
26
|
-
| 3 | JavaScript | MVC | None | MySQL |
|
|
27
|
-
| 4 | JavaScript | MVC | None | MySQL | Kafka |
|
|
28
|
-
| 5 | JavaScript | MVC | None |
|
|
29
|
-
| 6 | JavaScript | MVC | None |
|
|
30
|
-
| 7 | JavaScript | MVC | None | PostgreSQL |
|
|
31
|
-
| 8 | JavaScript | MVC | None | PostgreSQL |
|
|
32
|
-
| 9 | JavaScript | MVC | None |
|
|
33
|
-
| 10 | JavaScript | MVC | None |
|
|
34
|
-
| 11 | JavaScript | MVC | None |
|
|
35
|
-
| 12 | JavaScript | MVC | None |
|
|
36
|
-
| 13 | JavaScript | MVC |
|
|
37
|
-
| 14 | JavaScript | MVC |
|
|
38
|
-
| 15 | JavaScript | MVC |
|
|
39
|
-
| 16 | JavaScript | MVC |
|
|
40
|
-
| 17 | JavaScript | MVC |
|
|
41
|
-
| 18 | JavaScript | MVC |
|
|
42
|
-
| 19 | JavaScript | MVC |
|
|
43
|
-
| 20 | JavaScript | MVC |
|
|
44
|
-
| 21 | JavaScript | MVC | EJS |
|
|
45
|
-
| 22 | JavaScript | MVC | EJS |
|
|
46
|
-
| 23 | JavaScript | MVC | EJS |
|
|
47
|
-
| 24 | JavaScript | MVC | EJS |
|
|
48
|
-
| 25 | JavaScript | MVC |
|
|
49
|
-
| 26 | JavaScript | MVC |
|
|
50
|
-
| 27 | JavaScript | MVC |
|
|
51
|
-
| 28 | JavaScript | MVC |
|
|
52
|
-
| 29 | JavaScript | MVC |
|
|
53
|
-
| 30 | JavaScript | MVC |
|
|
54
|
-
| 31 | JavaScript | MVC |
|
|
55
|
-
| 32 | JavaScript | MVC |
|
|
56
|
-
| 33 | JavaScript | MVC |
|
|
57
|
-
| 34 | JavaScript | MVC |
|
|
58
|
-
| 35 | JavaScript | MVC |
|
|
59
|
-
| 36 | JavaScript | MVC |
|
|
60
|
-
| 37 |
|
|
61
|
-
| 38 |
|
|
62
|
-
| 39 |
|
|
63
|
-
| 40 |
|
|
64
|
-
| 41 |
|
|
65
|
-
| 42 |
|
|
66
|
-
| 43 |
|
|
67
|
-
| 44 |
|
|
68
|
-
| 45 |
|
|
69
|
-
| 46 |
|
|
70
|
-
| 47 |
|
|
71
|
-
| 48 |
|
|
72
|
-
| 49 |
|
|
73
|
-
| 50 |
|
|
74
|
-
| 51 |
|
|
75
|
-
| 52 |
|
|
76
|
-
| 53 |
|
|
77
|
-
| 54 |
|
|
78
|
-
| 55 |
|
|
79
|
-
| 56 |
|
|
80
|
-
| 57 |
|
|
81
|
-
| 58 |
|
|
82
|
-
| 59 |
|
|
83
|
-
| 60 |
|
|
84
|
-
| 61 | TypeScript | MVC |
|
|
85
|
-
| 62 | TypeScript | MVC |
|
|
86
|
-
| 63 | TypeScript | MVC |
|
|
87
|
-
| 64 | TypeScript | MVC |
|
|
88
|
-
| 65 | TypeScript | MVC |
|
|
89
|
-
| 66 | TypeScript | MVC |
|
|
90
|
-
| 67 | TypeScript | MVC |
|
|
91
|
-
| 68 | TypeScript | MVC |
|
|
92
|
-
| 69 | TypeScript | MVC |
|
|
93
|
-
| 70 | TypeScript | MVC |
|
|
94
|
-
| 71 | TypeScript | MVC |
|
|
95
|
-
| 72 | TypeScript | MVC |
|
|
96
|
-
| 73 |
|
|
97
|
-
| 74 |
|
|
98
|
-
| 75 |
|
|
99
|
-
| 76 |
|
|
100
|
-
| 77 |
|
|
101
|
-
| 78 |
|
|
102
|
-
| 79 | TypeScript | MVC | None | None | REST APIs | None |
|
|
103
|
-
| 80 | TypeScript | MVC | None | None | Kafka | None |
|
|
104
|
-
| 81 | TypeScript | MVC | EJS |
|
|
105
|
-
| 82 | TypeScript | MVC | EJS |
|
|
106
|
-
| 83 | TypeScript | MVC |
|
|
107
|
-
| 84 | TypeScript | MVC |
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
|
|
|
121
|
-
|
|
|
122
|
-
|
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
|
|
|
1
|
+
# NodeJS Quickstart Generator - Test Cases
|
|
2
|
+
|
|
3
|
+
This document lists the **160 possible project combinations** supported by the `nodejs-quickstart` CLI. These combinations cover all supported languages, architectures, databases, communication patterns, and caching options.
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
- **CI Providers**: `None`, `GitHub Actions`, `Jenkins`, `GitLab CI`
|
|
7
|
+
- **MVC Architecture**: 120 Combinations
|
|
8
|
+
- **With Database (108)**: 2 Lang × 3 View × 3 DB × 2 Comm = 36 * 3 (Caching: None/Redis/Memory Cache) = 108
|
|
9
|
+
- **No Database (12)**: 2 Lang × 3 View × 1 DB × 2 Comm = 12 * 1 (Caching: None) = 12
|
|
10
|
+
- **Clean Architecture**: 40 Combinations
|
|
11
|
+
- **With Database (36)**: 2 Lang × 1 View (None) × 3 DB × 2 Comm = 12 * 3 (Caching: None/Redis/Memory Cache) = 36
|
|
12
|
+
- **No Database (4)**: 2 Lang × 1 View (None) × 1 DB × 2 Comm = 4 * 1 (Caching: None) = 4
|
|
13
|
+
|
|
14
|
+
**Total Core Combinations: 160**
|
|
15
|
+
|
|
16
|
+
> **Note on CI/CD**: Each combination can be generated with or without CI/CD (`--ci-provider`), effectively doubling the state space.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. MVC Architecture (120 Cases)
|
|
21
|
+
|
|
22
|
+
| # | Language | Architecture | View Engine | Database | Communication | Caching |
|
|
23
|
+
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
24
|
+
| 1 | JavaScript | MVC | None | MySQL | REST APIs | None |
|
|
25
|
+
| 2 | JavaScript | MVC | None | MySQL | REST APIs | Redis |
|
|
26
|
+
| 3 | JavaScript | MVC | None | MySQL | REST APIs | Memory Cache |
|
|
27
|
+
| 4 | JavaScript | MVC | None | MySQL | Kafka | None |
|
|
28
|
+
| 5 | JavaScript | MVC | None | MySQL | Kafka | Redis |
|
|
29
|
+
| 6 | JavaScript | MVC | None | MySQL | Kafka | Memory Cache |
|
|
30
|
+
| 7 | JavaScript | MVC | None | PostgreSQL | REST APIs | None |
|
|
31
|
+
| 8 | JavaScript | MVC | None | PostgreSQL | REST APIs | Redis |
|
|
32
|
+
| 9 | JavaScript | MVC | None | PostgreSQL | REST APIs | Memory Cache |
|
|
33
|
+
| 10 | JavaScript | MVC | None | PostgreSQL | Kafka | None |
|
|
34
|
+
| 11 | JavaScript | MVC | None | PostgreSQL | Kafka | Redis |
|
|
35
|
+
| 12 | JavaScript | MVC | None | PostgreSQL | Kafka | Memory Cache |
|
|
36
|
+
| 13 | JavaScript | MVC | None | MongoDB | REST APIs | None |
|
|
37
|
+
| 14 | JavaScript | MVC | None | MongoDB | REST APIs | Redis |
|
|
38
|
+
| 15 | JavaScript | MVC | None | MongoDB | REST APIs | Memory Cache |
|
|
39
|
+
| 16 | JavaScript | MVC | None | MongoDB | Kafka | None |
|
|
40
|
+
| 17 | JavaScript | MVC | None | MongoDB | Kafka | Redis |
|
|
41
|
+
| 18 | JavaScript | MVC | None | MongoDB | Kafka | Memory Cache |
|
|
42
|
+
| 19 | JavaScript | MVC | None | None | REST APIs | None |
|
|
43
|
+
| 20 | JavaScript | MVC | None | None | Kafka | None |
|
|
44
|
+
| 21 | JavaScript | MVC | EJS | MySQL | REST APIs | None |
|
|
45
|
+
| 22 | JavaScript | MVC | EJS | MySQL | REST APIs | Redis |
|
|
46
|
+
| 23 | JavaScript | MVC | EJS | MySQL | REST APIs | Memory Cache |
|
|
47
|
+
| 24 | JavaScript | MVC | EJS | MySQL | Kafka | None |
|
|
48
|
+
| 25 | JavaScript | MVC | EJS | MySQL | Kafka | Redis |
|
|
49
|
+
| 26 | JavaScript | MVC | EJS | MySQL | Kafka | Memory Cache |
|
|
50
|
+
| 27 | JavaScript | MVC | EJS | PostgreSQL | REST APIs | None |
|
|
51
|
+
| 28 | JavaScript | MVC | EJS | PostgreSQL | REST APIs | Redis |
|
|
52
|
+
| 29 | JavaScript | MVC | EJS | PostgreSQL | REST APIs | Memory Cache |
|
|
53
|
+
| 30 | JavaScript | MVC | EJS | PostgreSQL | Kafka | None |
|
|
54
|
+
| 31 | JavaScript | MVC | EJS | PostgreSQL | Kafka | Redis |
|
|
55
|
+
| 32 | JavaScript | MVC | EJS | PostgreSQL | Kafka | Memory Cache |
|
|
56
|
+
| 33 | JavaScript | MVC | EJS | MongoDB | REST APIs | None |
|
|
57
|
+
| 34 | JavaScript | MVC | EJS | MongoDB | REST APIs | Redis |
|
|
58
|
+
| 35 | JavaScript | MVC | EJS | MongoDB | REST APIs | Memory Cache |
|
|
59
|
+
| 36 | JavaScript | MVC | EJS | MongoDB | Kafka | None |
|
|
60
|
+
| 37 | JavaScript | MVC | EJS | MongoDB | Kafka | Redis |
|
|
61
|
+
| 38 | JavaScript | MVC | EJS | MongoDB | Kafka | Memory Cache |
|
|
62
|
+
| 39 | JavaScript | MVC | EJS | None | REST APIs | None |
|
|
63
|
+
| 40 | JavaScript | MVC | EJS | None | Kafka | None |
|
|
64
|
+
| 41 | JavaScript | MVC | Pug | MySQL | REST APIs | None |
|
|
65
|
+
| 42 | JavaScript | MVC | Pug | MySQL | REST APIs | Redis |
|
|
66
|
+
| 43 | JavaScript | MVC | Pug | MySQL | REST APIs | Memory Cache |
|
|
67
|
+
| 44 | JavaScript | MVC | Pug | MySQL | Kafka | None |
|
|
68
|
+
| 45 | JavaScript | MVC | Pug | MySQL | Kafka | Redis |
|
|
69
|
+
| 46 | JavaScript | MVC | Pug | MySQL | Kafka | Memory Cache |
|
|
70
|
+
| 47 | JavaScript | MVC | Pug | PostgreSQL | REST APIs | None |
|
|
71
|
+
| 48 | JavaScript | MVC | Pug | PostgreSQL | REST APIs | Redis |
|
|
72
|
+
| 49 | JavaScript | MVC | Pug | PostgreSQL | REST APIs | Memory Cache |
|
|
73
|
+
| 50 | JavaScript | MVC | Pug | PostgreSQL | Kafka | None |
|
|
74
|
+
| 51 | JavaScript | MVC | Pug | PostgreSQL | Kafka | Redis |
|
|
75
|
+
| 52 | JavaScript | MVC | Pug | PostgreSQL | Kafka | Memory Cache |
|
|
76
|
+
| 53 | JavaScript | MVC | Pug | MongoDB | REST APIs | None |
|
|
77
|
+
| 54 | JavaScript | MVC | Pug | MongoDB | REST APIs | Redis |
|
|
78
|
+
| 55 | JavaScript | MVC | Pug | MongoDB | REST APIs | Memory Cache |
|
|
79
|
+
| 56 | JavaScript | MVC | Pug | MongoDB | Kafka | None |
|
|
80
|
+
| 57 | JavaScript | MVC | Pug | MongoDB | Kafka | Redis |
|
|
81
|
+
| 58 | JavaScript | MVC | Pug | MongoDB | Kafka | Memory Cache |
|
|
82
|
+
| 59 | JavaScript | MVC | Pug | None | REST APIs | None |
|
|
83
|
+
| 60 | JavaScript | MVC | Pug | None | Kafka | None |
|
|
84
|
+
| 61 | TypeScript | MVC | None | MySQL | REST APIs | None |
|
|
85
|
+
| 62 | TypeScript | MVC | None | MySQL | REST APIs | Redis |
|
|
86
|
+
| 63 | TypeScript | MVC | None | MySQL | REST APIs | Memory Cache |
|
|
87
|
+
| 64 | TypeScript | MVC | None | MySQL | Kafka | None |
|
|
88
|
+
| 65 | TypeScript | MVC | None | MySQL | Kafka | Redis |
|
|
89
|
+
| 66 | TypeScript | MVC | None | MySQL | Kafka | Memory Cache |
|
|
90
|
+
| 67 | TypeScript | MVC | None | PostgreSQL | REST APIs | None |
|
|
91
|
+
| 68 | TypeScript | MVC | None | PostgreSQL | REST APIs | Redis |
|
|
92
|
+
| 69 | TypeScript | MVC | None | PostgreSQL | REST APIs | Memory Cache |
|
|
93
|
+
| 70 | TypeScript | MVC | None | PostgreSQL | Kafka | None |
|
|
94
|
+
| 71 | TypeScript | MVC | None | PostgreSQL | Kafka | Redis |
|
|
95
|
+
| 72 | TypeScript | MVC | None | PostgreSQL | Kafka | Memory Cache |
|
|
96
|
+
| 73 | TypeScript | MVC | None | MongoDB | REST APIs | None |
|
|
97
|
+
| 74 | TypeScript | MVC | None | MongoDB | REST APIs | Redis |
|
|
98
|
+
| 75 | TypeScript | MVC | None | MongoDB | REST APIs | Memory Cache |
|
|
99
|
+
| 76 | TypeScript | MVC | None | MongoDB | Kafka | None |
|
|
100
|
+
| 77 | TypeScript | MVC | None | MongoDB | Kafka | Redis |
|
|
101
|
+
| 78 | TypeScript | MVC | None | MongoDB | Kafka | Memory Cache |
|
|
102
|
+
| 79 | TypeScript | MVC | None | None | REST APIs | None |
|
|
103
|
+
| 80 | TypeScript | MVC | None | None | Kafka | None |
|
|
104
|
+
| 81 | TypeScript | MVC | EJS | MySQL | REST APIs | None |
|
|
105
|
+
| 82 | TypeScript | MVC | EJS | MySQL | REST APIs | Redis |
|
|
106
|
+
| 83 | TypeScript | MVC | EJS | MySQL | REST APIs | Memory Cache |
|
|
107
|
+
| 84 | TypeScript | MVC | EJS | MySQL | Kafka | None |
|
|
108
|
+
| 85 | TypeScript | MVC | EJS | MySQL | Kafka | Redis |
|
|
109
|
+
| 86 | TypeScript | MVC | EJS | MySQL | Kafka | Memory Cache |
|
|
110
|
+
| 87 | TypeScript | MVC | EJS | PostgreSQL | REST APIs | None |
|
|
111
|
+
| 88 | TypeScript | MVC | EJS | PostgreSQL | REST APIs | Redis |
|
|
112
|
+
| 89 | TypeScript | MVC | EJS | PostgreSQL | REST APIs | Memory Cache |
|
|
113
|
+
| 90 | TypeScript | MVC | EJS | PostgreSQL | Kafka | None |
|
|
114
|
+
| 91 | TypeScript | MVC | EJS | PostgreSQL | Kafka | Redis |
|
|
115
|
+
| 92 | TypeScript | MVC | EJS | PostgreSQL | Kafka | Memory Cache |
|
|
116
|
+
| 93 | TypeScript | MVC | EJS | MongoDB | REST APIs | None |
|
|
117
|
+
| 94 | TypeScript | MVC | EJS | MongoDB | REST APIs | Redis |
|
|
118
|
+
| 95 | TypeScript | MVC | EJS | MongoDB | REST APIs | Memory Cache |
|
|
119
|
+
| 96 | TypeScript | MVC | EJS | MongoDB | Kafka | None |
|
|
120
|
+
| 97 | TypeScript | MVC | EJS | MongoDB | Kafka | Redis |
|
|
121
|
+
| 98 | TypeScript | MVC | EJS | MongoDB | Kafka | Memory Cache |
|
|
122
|
+
| 99 | TypeScript | MVC | EJS | None | REST APIs | None |
|
|
123
|
+
| 100 | TypeScript | MVC | EJS | None | Kafka | None |
|
|
124
|
+
| 101 | TypeScript | MVC | Pug | MySQL | REST APIs | None |
|
|
125
|
+
| 102 | TypeScript | MVC | Pug | MySQL | REST APIs | Redis |
|
|
126
|
+
| 103 | TypeScript | MVC | Pug | MySQL | REST APIs | Memory Cache |
|
|
127
|
+
| 104 | TypeScript | MVC | Pug | MySQL | Kafka | None |
|
|
128
|
+
| 105 | TypeScript | MVC | Pug | MySQL | Kafka | Redis |
|
|
129
|
+
| 106 | TypeScript | MVC | Pug | MySQL | Kafka | Memory Cache |
|
|
130
|
+
| 107 | TypeScript | MVC | Pug | PostgreSQL | REST APIs | None |
|
|
131
|
+
| 108 | TypeScript | MVC | Pug | PostgreSQL | REST APIs | Redis |
|
|
132
|
+
| 109 | TypeScript | MVC | Pug | PostgreSQL | REST APIs | Memory Cache |
|
|
133
|
+
| 110 | TypeScript | MVC | Pug | PostgreSQL | Kafka | None |
|
|
134
|
+
| 111 | TypeScript | MVC | Pug | PostgreSQL | Kafka | Redis |
|
|
135
|
+
| 112 | TypeScript | MVC | Pug | PostgreSQL | Kafka | Memory Cache |
|
|
136
|
+
| 113 | TypeScript | MVC | Pug | MongoDB | REST APIs | None |
|
|
137
|
+
| 114 | TypeScript | MVC | Pug | MongoDB | REST APIs | Redis |
|
|
138
|
+
| 115 | TypeScript | MVC | Pug | MongoDB | REST APIs | Memory Cache |
|
|
139
|
+
| 116 | TypeScript | MVC | Pug | MongoDB | Kafka | None |
|
|
140
|
+
| 117 | TypeScript | MVC | Pug | MongoDB | Kafka | Redis |
|
|
141
|
+
| 118 | TypeScript | MVC | Pug | MongoDB | Kafka | Memory Cache |
|
|
142
|
+
| 119 | TypeScript | MVC | Pug | None | REST APIs | None |
|
|
143
|
+
| 120 | TypeScript | MVC | Pug | None | Kafka | None |
|
|
144
|
+
|
|
145
|
+
## 2. Clean Architecture (40 Cases)
|
|
146
|
+
*Note: Clean Architecture does not use server-side view engines (EJS/Pug).*
|
|
147
|
+
|
|
148
|
+
| # | Language | Architecture | View Engine | Database | Communication | Caching |
|
|
149
|
+
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
150
|
+
| 121 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs | None |
|
|
151
|
+
| 122 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs | Redis |
|
|
152
|
+
| 123 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs | Memory Cache |
|
|
153
|
+
| 124 | JavaScript | Clean Architecture | N/A | MySQL | Kafka | None |
|
|
154
|
+
| 125 | JavaScript | Clean Architecture | N/A | MySQL | Kafka | Redis |
|
|
155
|
+
| 126 | JavaScript | Clean Architecture | N/A | MySQL | Kafka | Memory Cache |
|
|
156
|
+
| 127 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs | None |
|
|
157
|
+
| 128 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs | Redis |
|
|
158
|
+
| 129 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs | Memory Cache |
|
|
159
|
+
| 130 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka | None |
|
|
160
|
+
| 131 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka | Redis |
|
|
161
|
+
| 132 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka | Memory Cache |
|
|
162
|
+
| 133 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs | None |
|
|
163
|
+
| 134 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs | Redis |
|
|
164
|
+
| 135 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs | Memory Cache |
|
|
165
|
+
| 136 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka | None |
|
|
166
|
+
| 137 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka | Redis |
|
|
167
|
+
| 138 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka | Memory Cache |
|
|
168
|
+
| 139 | JavaScript | Clean Architecture | N/A | None | REST APIs | None |
|
|
169
|
+
| 140 | JavaScript | Clean Architecture | N/A | None | Kafka | None |
|
|
170
|
+
| 141 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs | None |
|
|
171
|
+
| 142 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs | Redis |
|
|
172
|
+
| 143 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs | Memory Cache |
|
|
173
|
+
| 144 | TypeScript | Clean Architecture | N/A | MySQL | Kafka | None |
|
|
174
|
+
| 145 | TypeScript | Clean Architecture | N/A | MySQL | Kafka | Redis |
|
|
175
|
+
| 146 | TypeScript | Clean Architecture | N/A | MySQL | Kafka | Memory Cache |
|
|
176
|
+
| 147 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs | None |
|
|
177
|
+
| 148 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs | Redis |
|
|
178
|
+
| 149 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs | Memory Cache |
|
|
179
|
+
| 150 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka | None |
|
|
180
|
+
| 151 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka | Redis |
|
|
181
|
+
| 152 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka | Memory Cache |
|
|
182
|
+
| 153 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs | None |
|
|
183
|
+
| 154 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs | Redis |
|
|
184
|
+
| 155 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs | Memory Cache |
|
|
185
|
+
| 156 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka | None |
|
|
186
|
+
| 157 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka | Redis |
|
|
187
|
+
| 158 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka | Memory Cache |
|
|
188
|
+
| 159 | TypeScript | Clean Architecture | N/A | None | REST APIs | None |
|
|
189
|
+
| 160 | TypeScript | Clean Architecture | N/A | None | Kafka | None |
|
package/docs/generatorFlow.md
CHANGED
|
@@ -26,7 +26,7 @@ The generator prompts the user for the following configurations. These determine
|
|
|
26
26
|
| **Database** | `None`, `MySQL`, `PostgreSQL`, `MongoDB` | `None` | The primary database. |
|
|
27
27
|
| **Database Name** | Input String | `demo` | The name of the database to use/create. |
|
|
28
28
|
| **Communication**| `REST APIs`, `Kafka` | `REST APIs` | The primary communication method. |
|
|
29
|
-
| **Caching Layer**| `None`, `Redis` | `None` | (If DB selected) Caching solution. |
|
|
29
|
+
| **Caching Layer**| `None`, `Redis`, `Memory Cache` | `None` | (If DB selected) Caching solution. |
|
|
30
30
|
| **CI/CD Provider**| `None`, `GitHub Actions`, `Jenkins`| `None` | Setup for Continuous Integration/Deployment. |
|
|
31
31
|
|
|
32
32
|
## 3. Main Generator Flow
|
|
@@ -72,8 +72,12 @@ The `generateProject` function in `lib/generator.js` executes the following step
|
|
|
72
72
|
* **Redis**:
|
|
73
73
|
* Injects `ioredis` dependency into `package.json`.
|
|
74
74
|
* Generates `redisClient.{js|ts}` config.
|
|
75
|
-
* **MVC**: Injects caching logic into `userController`.
|
|
76
|
-
* **Clean Architecture**: Overwrites
|
|
75
|
+
* **MVC**: Injects generic caching logic into `userController`.
|
|
76
|
+
* **Clean Architecture**: Overwrites UseCases with caching-enabled versions.
|
|
77
|
+
* **Memory Cache**:
|
|
78
|
+
* Injects `node-cache` dependency.
|
|
79
|
+
* Generates `memoryCache.{js|ts}` config.
|
|
80
|
+
* **MVC/Clean**: Consumes the generic abstraction injected above.
|
|
77
81
|
12. **Database Connection Config**:
|
|
78
82
|
* Renders `database.{js|ts}` or `mongoose.{js|ts}` based on DB selection.
|
|
79
83
|
* Places it in `src/config` (MVC) or `src/infrastructure/database` (Clean Arch).
|
package/docs/ruleDevelop.md
CHANGED
|
@@ -6,22 +6,24 @@ export const setupCaching = async (templatesDir, targetDir, config) => {
|
|
|
6
6
|
const { caching, language, architecture } = config;
|
|
7
7
|
if (!caching || caching === 'None') return;
|
|
8
8
|
|
|
9
|
-
if (caching === 'Redis') {
|
|
9
|
+
if (caching === 'Redis' || caching === 'Memory Cache') {
|
|
10
10
|
const langExt = language === 'TypeScript' ? 'ts' : 'js';
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
const clientObj = caching === 'Redis'
|
|
12
|
+
? (language === 'TypeScript' ? 'redisClient.ts' : 'redisClient.js')
|
|
13
|
+
: (language === 'TypeScript' ? 'memoryCache.ts' : 'memoryCache.js');
|
|
14
|
+
const cacheSource = path.join(templatesDir, 'common', 'caching', langExt, `${clientObj}.ejs`);
|
|
13
15
|
|
|
14
|
-
let
|
|
16
|
+
let cacheTarget;
|
|
15
17
|
let loggerPath;
|
|
16
18
|
|
|
17
19
|
if (architecture === 'MVC') {
|
|
18
20
|
await fs.ensureDir(path.join(targetDir, 'src/config'));
|
|
19
|
-
|
|
21
|
+
cacheTarget = path.join(targetDir, 'src/config', clientObj);
|
|
20
22
|
loggerPath = language === 'TypeScript' ? '@/utils/logger' : '../utils/logger';
|
|
21
23
|
} else {
|
|
22
24
|
// Clean Architecture
|
|
23
25
|
await fs.ensureDir(path.join(targetDir, 'src/infrastructure/caching'));
|
|
24
|
-
|
|
26
|
+
cacheTarget = path.join(targetDir, 'src/infrastructure/caching', clientObj);
|
|
25
27
|
loggerPath = language === 'TypeScript' ? '@/infrastructure/log/logger' : '../log/logger';
|
|
26
28
|
|
|
27
29
|
// Overwrite UseCase with Caching Enabled
|
|
@@ -34,7 +36,8 @@ export const setupCaching = async (templatesDir, targetDir, config) => {
|
|
|
34
36
|
|
|
35
37
|
if (await fs.pathExists(useCaseSource)) {
|
|
36
38
|
const ucContent = await fs.readFile(useCaseSource, 'utf-8');
|
|
37
|
-
|
|
39
|
+
const renderedUc = ejs.render(ucContent, { caching });
|
|
40
|
+
await fs.writeFile(path.join(useCaseTargetDir, useCaseName), renderedUc);
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
// Also Overwrite CreateUser with Caching (Invalidation) Enabled
|
|
@@ -43,14 +46,15 @@ export const setupCaching = async (templatesDir, targetDir, config) => {
|
|
|
43
46
|
|
|
44
47
|
if (await fs.pathExists(createUserSource)) {
|
|
45
48
|
const createUserContent = await fs.readFile(createUserSource, 'utf-8');
|
|
46
|
-
|
|
49
|
+
const renderedCreateUser = ejs.render(createUserContent, { caching });
|
|
50
|
+
await fs.writeFile(path.join(useCaseTargetDir, createUserParams.name), renderedCreateUser);
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
if (await fs.pathExists(
|
|
51
|
-
const
|
|
52
|
-
const content = ejs.render(
|
|
53
|
-
await fs.writeFile(
|
|
54
|
+
if (await fs.pathExists(cacheSource)) {
|
|
55
|
+
const cacheTemplate = await fs.readFile(cacheSource, 'utf-8');
|
|
56
|
+
const content = ejs.render(cacheTemplate, { loggerPath });
|
|
57
|
+
await fs.writeFile(cacheTarget, content);
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
};
|
package/lib/prompts.js
CHANGED
|
@@ -66,7 +66,7 @@ export const getProjectDetails = async (options = {}) => {
|
|
|
66
66
|
type: 'list',
|
|
67
67
|
name: 'caching',
|
|
68
68
|
message: 'Caching Layer:',
|
|
69
|
-
choices: ['None', 'Redis'],
|
|
69
|
+
choices: ['None', 'Redis', 'Memory Cache'],
|
|
70
70
|
default: 'None',
|
|
71
71
|
when: (answers) => !options.caching && (options.database || answers.database) !== 'None'
|
|
72
72
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
|
-
const UserController = require('../controllers/
|
|
3
|
+
const UserController = require('../controllers/userController');
|
|
4
4
|
|
|
5
5
|
// Should inject dependencies here in a real app
|
|
6
6
|
const userController = new UserController();
|
|
@@ -9,7 +9,7 @@ COPY package*.json ./
|
|
|
9
9
|
COPY tsconfig*.json ./
|
|
10
10
|
|
|
11
11
|
# Install ALL dependencies (including devDeps for build)
|
|
12
|
-
RUN npm ci
|
|
12
|
+
RUN npm ci --no-audit --no-fund || npm ci --no-audit --no-fund || npm ci --no-audit --no-fund
|
|
13
13
|
|
|
14
14
|
COPY . .
|
|
15
15
|
|
|
@@ -28,7 +28,7 @@ ENV NODE_ENV=production
|
|
|
28
28
|
COPY package*.json ./
|
|
29
29
|
|
|
30
30
|
# Install ONLY production dependencies
|
|
31
|
-
RUN npm ci --only=production --ignore-scripts
|
|
31
|
+
RUN npm ci --only=production --ignore-scripts --no-audit --no-fund || npm ci --only=production --ignore-scripts --no-audit --no-fund || npm ci --only=production --ignore-scripts --no-audit --no-fund
|
|
32
32
|
|
|
33
33
|
# Copy built artifacts from builder
|
|
34
34
|
<% if (language === 'TypeScript') { %>
|
|
@@ -95,6 +95,10 @@ A Swagger UI for API documentation is available at:
|
|
|
95
95
|
This project uses **Redis** for caching.
|
|
96
96
|
- **Client**: `ioredis`
|
|
97
97
|
- **Connection**: Configured via `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD` in `.env`.
|
|
98
|
+
<% } else if (caching === 'Memory Cache') { -%>
|
|
99
|
+
## ⚡ Caching
|
|
100
|
+
This project uses **Memory Cache** for in-memory caching.
|
|
101
|
+
- **Client**: `node-cache`
|
|
98
102
|
<% } -%>
|
|
99
103
|
|
|
100
104
|
## 📝 Logging
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const User = require('../domain/models/User');
|
|
2
|
-
|
|
2
|
+
<%_ if (caching === 'Redis') { -%>
|
|
3
|
+
const cacheService = require('../infrastructure/caching/redisClient');
|
|
4
|
+
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
5
|
+
const cacheService = require('../infrastructure/caching/memoryCache');
|
|
6
|
+
<%_ } -%>
|
|
3
7
|
const logger = require('../infrastructure/log/logger');
|
|
4
8
|
|
|
5
9
|
class CreateUser {
|
|
@@ -12,10 +16,10 @@ class CreateUser {
|
|
|
12
16
|
const savedUser = await this.userRepository.save(user);
|
|
13
17
|
|
|
14
18
|
try {
|
|
15
|
-
await
|
|
19
|
+
await cacheService.del('users:all');
|
|
16
20
|
logger.info('Invalidated users:all cache');
|
|
17
21
|
} catch (error) {
|
|
18
|
-
logger.error('
|
|
22
|
+
logger.error('Cache error (del):', error);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
return savedUser;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<%_ if (caching === 'Redis') { -%>
|
|
2
|
+
const cacheService = require('../infrastructure/caching/redisClient');
|
|
3
|
+
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
4
|
+
const cacheService = require('../infrastructure/caching/memoryCache');
|
|
5
|
+
<%_ } -%>
|
|
2
6
|
const logger = require('../infrastructure/log/logger');
|
|
3
7
|
|
|
4
8
|
class GetAllUsers {
|
|
@@ -9,21 +13,21 @@ class GetAllUsers {
|
|
|
9
13
|
async execute() {
|
|
10
14
|
const cacheKey = 'users:all';
|
|
11
15
|
try {
|
|
12
|
-
const cachedUsers = await
|
|
16
|
+
const cachedUsers = await cacheService.get(cacheKey);
|
|
13
17
|
if (cachedUsers) {
|
|
14
18
|
logger.info('Serving users from cache');
|
|
15
19
|
return cachedUsers;
|
|
16
20
|
}
|
|
17
21
|
} catch (error) {
|
|
18
|
-
logger.error('
|
|
22
|
+
logger.error('Cache error (get):', error);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
const users = await this.userRepository.getUsers();
|
|
22
26
|
|
|
23
27
|
try {
|
|
24
|
-
await
|
|
28
|
+
await cacheService.set(cacheKey, users, 60);
|
|
25
29
|
} catch (error) {
|
|
26
|
-
logger.error('
|
|
30
|
+
logger.error('Cache error (set):', error);
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
return users;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { User } from '@/domain/user';
|
|
2
2
|
|
|
3
3
|
import { UserRepository } from '@/infrastructure/repositories/UserRepository';
|
|
4
|
-
|
|
4
|
+
<%_ if (caching === 'Redis') { -%>
|
|
5
|
+
import cacheService from '@/infrastructure/caching/redisClient';
|
|
6
|
+
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
7
|
+
import cacheService from '@/infrastructure/caching/memoryCache';
|
|
8
|
+
<%_ } -%>
|
|
5
9
|
import logger from '@/infrastructure/log/logger';
|
|
6
10
|
|
|
7
11
|
export default class CreateUser {
|
|
@@ -12,10 +16,10 @@ export default class CreateUser {
|
|
|
12
16
|
const savedUser = await this.userRepository.save(user);
|
|
13
17
|
|
|
14
18
|
try {
|
|
15
|
-
await
|
|
19
|
+
await cacheService.del('users:all');
|
|
16
20
|
logger.info('Invalidated users:all cache');
|
|
17
21
|
} catch (error) {
|
|
18
|
-
logger.error('
|
|
22
|
+
logger.error('Cache error (del):', error);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
return savedUser;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { UserRepository } from '@/infrastructure/repositories/UserRepository';
|
|
2
|
-
|
|
2
|
+
<%_ if (caching === 'Redis') { -%>
|
|
3
|
+
import cacheService from '@/infrastructure/caching/redisClient';
|
|
4
|
+
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
5
|
+
import cacheService from '@/infrastructure/caching/memoryCache';
|
|
6
|
+
<%_ } -%>
|
|
3
7
|
import logger from '@/infrastructure/log/logger';
|
|
4
8
|
|
|
5
9
|
export default class GetAllUsers {
|
|
@@ -8,21 +12,21 @@ export default class GetAllUsers {
|
|
|
8
12
|
async execute() {
|
|
9
13
|
const cacheKey = 'users:all';
|
|
10
14
|
try {
|
|
11
|
-
const cachedUsers = await
|
|
15
|
+
const cachedUsers = await cacheService.get(cacheKey);
|
|
12
16
|
if (cachedUsers) {
|
|
13
17
|
logger.info('Serving users from cache');
|
|
14
18
|
return cachedUsers;
|
|
15
19
|
}
|
|
16
20
|
} catch (error) {
|
|
17
|
-
logger.error('
|
|
21
|
+
logger.error('Cache error (get):', error);
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
const users = await this.userRepository.getUsers();
|
|
21
25
|
|
|
22
26
|
try {
|
|
23
|
-
await
|
|
27
|
+
await cacheService.set(cacheKey, users, 60);
|
|
24
28
|
} catch (error) {
|
|
25
|
-
logger.error('
|
|
29
|
+
logger.error('Cache error (set):', error);
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
return users;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const NodeCache = require('node-cache');
|
|
2
|
+
const logger = require('<%- loggerPath %>');
|
|
3
|
+
|
|
4
|
+
class MemoryCacheService {
|
|
5
|
+
constructor() {
|
|
6
|
+
// Default TTL of 0 (unlimited), check period of 120s
|
|
7
|
+
this.cache = new NodeCache({ stdTTL: 0, checkperiod: 120 });
|
|
8
|
+
logger.info('Memory Cache initialized');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static getInstance() {
|
|
12
|
+
if (!MemoryCacheService.instance) {
|
|
13
|
+
MemoryCacheService.instance = new MemoryCacheService();
|
|
14
|
+
}
|
|
15
|
+
return MemoryCacheService.instance;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async get(key) {
|
|
19
|
+
try {
|
|
20
|
+
const data = this.cache.get(key);
|
|
21
|
+
if (data === undefined) return null;
|
|
22
|
+
return typeof data === 'string' ? JSON.parse(data) : data;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
logger.error(`Memory Cache get error for key ${key}:`, error);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async set(key, value, ttl) {
|
|
30
|
+
try {
|
|
31
|
+
const data = JSON.stringify(value);
|
|
32
|
+
if (ttl) {
|
|
33
|
+
this.cache.set(key, data, ttl);
|
|
34
|
+
} else {
|
|
35
|
+
this.cache.set(key, data);
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.error(`Memory Cache set error for key ${key}:`, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async del(key) {
|
|
43
|
+
try {
|
|
44
|
+
this.cache.del(key);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.error(`Memory Cache del error for key ${key}:`, error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getOrSet(key, fetcher, ttl = 3600) {
|
|
51
|
+
const cached = await this.get(key);
|
|
52
|
+
if (cached) return cached;
|
|
53
|
+
|
|
54
|
+
const data = await fetcher();
|
|
55
|
+
if (data) await this.set(key, data, ttl);
|
|
56
|
+
return data;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = MemoryCacheService.getInstance();
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import NodeCache from 'node-cache';
|
|
2
|
+
import logger from '<%- loggerPath %>';
|
|
3
|
+
|
|
4
|
+
class MemoryCacheService {
|
|
5
|
+
private cache: NodeCache;
|
|
6
|
+
private static instance: MemoryCacheService;
|
|
7
|
+
|
|
8
|
+
private constructor() {
|
|
9
|
+
// Default TTL of 0 (unlimited), check period of 120s
|
|
10
|
+
this.cache = new NodeCache({ stdTTL: 0, checkperiod: 120 });
|
|
11
|
+
logger.info('Memory Cache initialized');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public static getInstance(): MemoryCacheService {
|
|
15
|
+
if (!MemoryCacheService.instance) {
|
|
16
|
+
MemoryCacheService.instance = new MemoryCacheService();
|
|
17
|
+
}
|
|
18
|
+
return MemoryCacheService.instance;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async get<T>(key: string): Promise<T | null> {
|
|
22
|
+
try {
|
|
23
|
+
const data = this.cache.get<T>(key);
|
|
24
|
+
// Simulating un-parsed data similar to Redis for consistency
|
|
25
|
+
if (data === undefined) return null;
|
|
26
|
+
return typeof data === 'string' ? JSON.parse(data) : data;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
logger.error(`Memory Cache get error for key ${key}:`, error);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async set(key: string, value: unknown, ttl?: number): Promise<void> {
|
|
34
|
+
try {
|
|
35
|
+
const data = JSON.stringify(value);
|
|
36
|
+
if (ttl) {
|
|
37
|
+
this.cache.set(key, data, ttl);
|
|
38
|
+
} else {
|
|
39
|
+
this.cache.set(key, data);
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
logger.error(`Memory Cache set error for key ${key}:`, error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public async del(key: string): Promise<void> {
|
|
47
|
+
try {
|
|
48
|
+
this.cache.del(key);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
logger.error(`Memory Cache del error for key ${key}:`, error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public async getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl: number = 3600): Promise<T> {
|
|
55
|
+
const cached = await this.get<T>(key);
|
|
56
|
+
if (cached) return cached;
|
|
57
|
+
|
|
58
|
+
const data = await fetcher();
|
|
59
|
+
if (data) await this.set(key, data, ttl);
|
|
60
|
+
return data;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default MemoryCacheService.getInstance();
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
<% } -%>
|
|
35
35
|
<% if (caching === 'Redis') { %> "ioredis": "^5.3.2",
|
|
36
36
|
<% } -%>
|
|
37
|
+
<% if (caching === 'Memory Cache') { %> "node-cache": "^5.1.2",
|
|
38
|
+
<% } -%>
|
|
37
39
|
<% if (viewEngine === 'EJS') { %> "ejs": "^3.1.10",
|
|
38
40
|
<% } -%>
|
|
39
41
|
<% if (viewEngine === 'Pug') { %> "pug": "^3.0.2",
|
|
@@ -58,6 +60,8 @@
|
|
|
58
60
|
"@types/hpp": "^0.2.3",
|
|
59
61
|
<% if (caching === 'Redis') { %> "@types/ioredis": "^5.0.0",
|
|
60
62
|
<% } -%>
|
|
63
|
+
<% if (caching === 'Memory Cache') { %> "@types/node-cache": "^4.2.5",
|
|
64
|
+
<% } -%>
|
|
61
65
|
<% if (database === 'PostgreSQL') { %> "@types/pg": "^8.10.9",
|
|
62
66
|
<% } -%>
|
|
63
67
|
<%_ if (database === 'MySQL' || database === 'PostgreSQL') { -%>
|
|
@@ -79,12 +83,12 @@
|
|
|
79
83
|
"jest": "^29.7.0",
|
|
80
84
|
"ts-jest": "^29.2.5",
|
|
81
85
|
"@types/jest": "^29.5.14",
|
|
82
|
-
"supertest": "
|
|
86
|
+
"supertest": "6.3.3",
|
|
83
87
|
"tsconfig-paths": "^4.2.0",
|
|
84
88
|
"tsc-alias": "^1.8.10",
|
|
85
89
|
"@types/supertest": "^6.0.2"<% } else { %>,
|
|
86
90
|
"jest": "^29.7.0",
|
|
87
|
-
"supertest": "
|
|
91
|
+
"supertest": "6.3.3"<% } %>
|
|
88
92
|
},
|
|
89
93
|
"overrides": {
|
|
90
94
|
"minimatch": "^10.2.1"
|
|
@@ -2,13 +2,15 @@ const User = require('../models/User');
|
|
|
2
2
|
const HTTP_STATUS = require('../utils/httpCodes');
|
|
3
3
|
const logger = require('../utils/logger');
|
|
4
4
|
<%_ if (caching === 'Redis') { -%>
|
|
5
|
-
const
|
|
5
|
+
const cacheService = require('../config/redisClient');
|
|
6
|
+
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
7
|
+
const cacheService = require('../config/memoryCache');
|
|
6
8
|
<%_ } -%>
|
|
7
9
|
|
|
8
10
|
const getUsers = async (req, res) => {
|
|
9
11
|
try {
|
|
10
|
-
<%_ if (caching === 'Redis') { -%>
|
|
11
|
-
const users = await
|
|
12
|
+
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
13
|
+
const users = await cacheService.getOrSet('users:all', async () => {
|
|
12
14
|
<%_ if (database === 'MongoDB') { -%>
|
|
13
15
|
return await User.find();
|
|
14
16
|
<%_ } else if (database === 'None') { -%>
|
|
@@ -39,14 +41,14 @@ const createUser = async (req, res) => {
|
|
|
39
41
|
<%_ if (database === 'None') { -%>
|
|
40
42
|
const newUser = { id: String(User.mockData.length + 1), name, email };
|
|
41
43
|
User.mockData.push(newUser);
|
|
42
|
-
<%_ if (caching === 'Redis') { -%>
|
|
43
|
-
await
|
|
44
|
+
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
45
|
+
await cacheService.del('users:all');
|
|
44
46
|
<%_ } -%>
|
|
45
47
|
res.status(HTTP_STATUS.CREATED).json(newUser);
|
|
46
48
|
<%_ } else { -%>
|
|
47
49
|
const user = await User.create({ name, email });
|
|
48
|
-
<%_ if (caching === 'Redis') { -%>
|
|
49
|
-
await
|
|
50
|
+
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
51
|
+
await cacheService.del('users:all');
|
|
50
52
|
<%_ } -%>
|
|
51
53
|
res.status(HTTP_STATUS.CREATED).json(user);
|
|
52
54
|
<%_ } -%>
|
|
@@ -3,14 +3,16 @@ import User from '@/models/User';
|
|
|
3
3
|
import { HTTP_STATUS } from '@/utils/httpCodes';
|
|
4
4
|
import logger from '@/utils/logger';
|
|
5
5
|
<%_ if (caching === 'Redis') { -%>
|
|
6
|
-
import
|
|
6
|
+
import cacheService from '@/config/redisClient';
|
|
7
|
+
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
8
|
+
import cacheService from '@/config/memoryCache';
|
|
7
9
|
<%_ } -%>
|
|
8
10
|
|
|
9
11
|
export class UserController {
|
|
10
12
|
async getUsers(req: Request, res: Response) {
|
|
11
13
|
try {
|
|
12
|
-
<%_ if (caching === 'Redis') { -%>
|
|
13
|
-
const users = await
|
|
14
|
+
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
15
|
+
const users = await cacheService.getOrSet('users:all', async () => {
|
|
14
16
|
<%_ if (database === 'MongoDB') { -%>
|
|
15
17
|
return await User.find();
|
|
16
18
|
<%_ } else if (database === 'None') { -%>
|
|
@@ -45,14 +47,14 @@ export class UserController {
|
|
|
45
47
|
<%_ if (database === 'None') { -%>
|
|
46
48
|
const newUser = { id: String(User.mockData.length + 1), name, email };
|
|
47
49
|
User.mockData.push(newUser);
|
|
48
|
-
<%_ if (caching === 'Redis') { -%>
|
|
49
|
-
await
|
|
50
|
+
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
51
|
+
await cacheService.del('users:all');
|
|
50
52
|
<%_ } -%>
|
|
51
53
|
res.status(HTTP_STATUS.CREATED).json(newUser);
|
|
52
54
|
<%_ } else { -%>
|
|
53
55
|
const user = await User.create({ name, email });
|
|
54
|
-
<%_ if (caching === 'Redis') { -%>
|
|
55
|
-
await
|
|
56
|
+
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
57
|
+
await cacheService.del('users:all');
|
|
56
58
|
<%_ } -%>
|
|
57
59
|
res.status(HTTP_STATUS.CREATED).json(user);
|
|
58
60
|
<%_ } -%>
|