nodejs-quickstart-structure 1.18.1 → 1.19.1
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 +309 -294
- package/LICENSE +15 -15
- package/README.md +2 -1
- package/lib/generator.js +139 -139
- package/lib/modules/app-setup.js +401 -401
- package/lib/modules/caching-setup.js +76 -73
- package/lib/modules/config-files.js +151 -151
- package/lib/modules/database-setup.js +116 -116
- package/lib/modules/kafka-setup.js +249 -191
- package/lib/modules/project-setup.js +32 -31
- package/lib/prompts.js +100 -100
- package/package.json +78 -67
- package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
- package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
- package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
- package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
- package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
- package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
- package/templates/clean-architecture/js/src/index.js.ejs +55 -55
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
- package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
- package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
- package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
- package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
- package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
- package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
- package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
- package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
- package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
- package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
- package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
- package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
- package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
- package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
- package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
- package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
- package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
- package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
- package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
- package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
- package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
- package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
- package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
- package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
- package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
- package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
- package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
- package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
- package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
- package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
- package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
- package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
- package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
- package/templates/common/.cursorrules.ejs +60 -60
- package/templates/common/.dockerignore +12 -12
- package/templates/common/.env.example.ejs +41 -41
- package/templates/common/.gitattributes +46 -0
- package/templates/common/.gitlab-ci.yml.ejs +86 -86
- package/templates/common/.lintstagedrc +6 -6
- package/templates/common/.prettierrc +7 -7
- package/templates/common/Dockerfile +73 -73
- package/templates/common/Jenkinsfile.ejs +87 -87
- package/templates/common/README.md.ejs +294 -270
- package/templates/common/SECURITY.md +20 -20
- package/templates/common/_github/workflows/ci.yml.ejs +46 -46
- package/templates/common/_github/workflows/security.yml.ejs +36 -36
- package/templates/common/_gitignore +5 -5
- package/templates/common/_husky/pre-commit +4 -4
- package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
- package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
- package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
- package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
- package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
- package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
- package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
- package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
- package/templates/common/caching/js/memoryCache.js.ejs +60 -60
- package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
- package/templates/common/caching/js/redisClient.js.ejs +75 -75
- package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
- package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
- package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
- package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
- package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
- package/templates/common/database/js/database.js.ejs +19 -19
- package/templates/common/database/js/database.spec.js.ejs +56 -56
- package/templates/common/database/js/models/User.js.ejs +79 -53
- package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
- package/templates/common/database/js/models/User.spec.js.ejs +94 -84
- package/templates/common/database/js/mongoose.js.ejs +33 -33
- package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
- package/templates/common/database/ts/database.spec.ts.ejs +56 -56
- package/templates/common/database/ts/database.ts.ejs +21 -21
- package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
- package/templates/common/database/ts/models/User.ts.ejs +87 -61
- package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
- package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
- package/templates/common/database/ts/mongoose.ts.ejs +28 -28
- package/templates/common/docker-compose.yml.ejs +159 -159
- package/templates/common/ecosystem.config.js.ejs +40 -40
- package/templates/common/eslint.config.mjs.ejs +77 -77
- package/templates/common/health/js/healthRoute.js.ejs +50 -47
- package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
- package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
- package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
- package/templates/common/jest.config.js.ejs +32 -32
- package/templates/common/jest.e2e.config.js.ejs +8 -8
- package/templates/common/kafka/js/config/kafka.js +9 -9
- package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
- package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
- package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
- package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
- package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
- package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
- package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
- package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
- package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
- package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
- package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
- package/templates/common/kafka/ts/config/kafka.ts +7 -7
- package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
- package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
- package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
- package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
- package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
- package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
- package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
- package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
- package/templates/common/migrate-mongo-config.js.ejs +31 -31
- package/templates/common/migrations/init.js.ejs +23 -23
- package/templates/common/package.json.ejs +119 -118
- package/templates/common/prompts/add-feature.md.ejs +26 -26
- package/templates/common/prompts/project-context.md.ejs +43 -43
- package/templates/common/prompts/troubleshoot.md.ejs +28 -28
- package/templates/common/public/css/style.css +147 -147
- package/templates/common/scripts/run-e2e.js.ejs +63 -63
- package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
- package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
- package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
- package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
- package/templates/common/sonar-project.properties.ejs +27 -27
- package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
- package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
- package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
- package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
- package/templates/common/swagger.yml.ejs +118 -66
- package/templates/common/tsconfig.json +22 -22
- package/templates/common/views/ejs/index.ejs +55 -55
- package/templates/common/views/pug/index.pug +40 -40
- package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
- package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
- package/templates/mvc/js/src/config/env.js.ejs +46 -46
- package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
- package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
- package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
- package/templates/mvc/js/src/errors/ApiError.js +14 -14
- package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
- package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
- package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
- package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
- package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
- package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
- package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
- package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
- package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
- package/templates/mvc/js/src/index.js.ejs +136 -136
- package/templates/mvc/js/src/routes/api.js +10 -8
- package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
- package/templates/mvc/js/src/utils/errorMessages.js +14 -0
- package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
- package/templates/mvc/js/src/utils/httpCodes.js +9 -9
- package/templates/mvc/js/src/utils/logger.js +40 -40
- package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
- package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
- package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
- package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
- package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
- package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
- package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
- package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
- package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
- package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
- package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
- package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
- package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
- package/templates/mvc/ts/src/index.ts.ejs +156 -153
- package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
- package/templates/mvc/ts/src/routes/api.ts +12 -10
- package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
- package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
- package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
- package/templates/mvc/ts/src/utils/logger.ts +36 -36
- package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
|
@@ -1,60 +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();
|
|
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();
|
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
jest.mock('node-cache', () => {
|
|
2
|
-
return jest.fn().mockImplementation(() => ({
|
|
3
|
-
get: jest.fn(),
|
|
4
|
-
set: jest.fn(),
|
|
5
|
-
del: jest.fn(),
|
|
6
|
-
}));
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
jest.mock('<%- loggerPath %>', () => ({
|
|
10
|
-
info: jest.fn(),
|
|
11
|
-
error: jest.fn(),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
describe('Memory Cache Client', () => {
|
|
15
|
-
let memoryCacheService;
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
jest.clearAllMocks();
|
|
19
|
-
jest.resetModules();
|
|
20
|
-
memoryCacheService = require('<% if (architecture === "MVC") { %>@/config/memoryCache<% } else { %>@/infrastructure/caching/memoryCache<% } %>');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should get data from memory cache', async () => {
|
|
24
|
-
const mockData = { test: 'data' };
|
|
25
|
-
memoryCacheService.cache.get.mockReturnValue(JSON.stringify(mockData));
|
|
26
|
-
|
|
27
|
-
const data = await memoryCacheService.get('test-key');
|
|
28
|
-
expect(data).toEqual(mockData);
|
|
29
|
-
expect(memoryCacheService.cache.get).toHaveBeenCalledWith('test-key');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should return null when key is not found', async () => {
|
|
33
|
-
memoryCacheService.cache.get.mockReturnValue(undefined);
|
|
34
|
-
const data = await memoryCacheService.get('non-existent');
|
|
35
|
-
expect(data).toBeNull();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should return data as is if not a string', async () => {
|
|
39
|
-
const mockData = { test: 'data' };
|
|
40
|
-
memoryCacheService.cache.get.mockReturnValue(mockData);
|
|
41
|
-
const data = await memoryCacheService.get('binary-key');
|
|
42
|
-
expect(data).toEqual(mockData);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should handle errors in get', async () => {
|
|
46
|
-
memoryCacheService.cache.get.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
47
|
-
const data = await memoryCacheService.get('error-key');
|
|
48
|
-
expect(data).toBeNull();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should set data to memory cache without TTL', async () => {
|
|
52
|
-
const mockData = { test: 'data' };
|
|
53
|
-
await memoryCacheService.set('test-key', mockData);
|
|
54
|
-
expect(memoryCacheService.cache.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData));
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should handle errors in set', async () => {
|
|
58
|
-
memoryCacheService.cache.set.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
59
|
-
await memoryCacheService.set('test-key', 'value');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should handle errors in del', async () => {
|
|
63
|
-
memoryCacheService.cache.del.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
64
|
-
await memoryCacheService.del('test-key');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should use getOrSet and call fetcher if not cached', async () => {
|
|
68
|
-
memoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
69
|
-
memoryCacheService.set = jest.fn();
|
|
70
|
-
const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
|
|
71
|
-
|
|
72
|
-
const result = await memoryCacheService.getOrSet('new-key', fetcher);
|
|
73
|
-
|
|
74
|
-
expect(result).toEqual({ new: 'data' });
|
|
75
|
-
expect(fetcher).toHaveBeenCalled();
|
|
76
|
-
// Result should be cached
|
|
77
|
-
expect(memoryCacheService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should return cached data in getOrSet', async () => {
|
|
81
|
-
const cachedData = { cached: 'data' };
|
|
82
|
-
memoryCacheService.get = jest.fn().mockResolvedValue(cachedData);
|
|
83
|
-
const fetcher = jest.fn();
|
|
84
|
-
|
|
85
|
-
const result = await memoryCacheService.getOrSet('cached-key', fetcher);
|
|
86
|
-
|
|
87
|
-
expect(result).toEqual(cachedData);
|
|
88
|
-
expect(fetcher).not.toHaveBeenCalled();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle falsy data from fetcher in getOrSet', async () => {
|
|
92
|
-
memoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
93
|
-
memoryCacheService.set = jest.fn();
|
|
94
|
-
const fetcher = jest.fn().mockResolvedValue(null);
|
|
95
|
-
|
|
96
|
-
const result = await memoryCacheService.getOrSet('empty-key', fetcher);
|
|
97
|
-
|
|
98
|
-
expect(result).toBeNull();
|
|
99
|
-
expect(memoryCacheService.set).not.toHaveBeenCalled();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
1
|
+
jest.mock('node-cache', () => {
|
|
2
|
+
return jest.fn().mockImplementation(() => ({
|
|
3
|
+
get: jest.fn(),
|
|
4
|
+
set: jest.fn(),
|
|
5
|
+
del: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
jest.mock('<%- loggerPath %>', () => ({
|
|
10
|
+
info: jest.fn(),
|
|
11
|
+
error: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
describe('Memory Cache Client', () => {
|
|
15
|
+
let memoryCacheService;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
memoryCacheService = require('<% if (architecture === "MVC") { %>@/config/memoryCache<% } else { %>@/infrastructure/caching/memoryCache<% } %>');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should get data from memory cache', async () => {
|
|
24
|
+
const mockData = { test: 'data' };
|
|
25
|
+
memoryCacheService.cache.get.mockReturnValue(JSON.stringify(mockData));
|
|
26
|
+
|
|
27
|
+
const data = await memoryCacheService.get('test-key');
|
|
28
|
+
expect(data).toEqual(mockData);
|
|
29
|
+
expect(memoryCacheService.cache.get).toHaveBeenCalledWith('test-key');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should return null when key is not found', async () => {
|
|
33
|
+
memoryCacheService.cache.get.mockReturnValue(undefined);
|
|
34
|
+
const data = await memoryCacheService.get('non-existent');
|
|
35
|
+
expect(data).toBeNull();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return data as is if not a string', async () => {
|
|
39
|
+
const mockData = { test: 'data' };
|
|
40
|
+
memoryCacheService.cache.get.mockReturnValue(mockData);
|
|
41
|
+
const data = await memoryCacheService.get('binary-key');
|
|
42
|
+
expect(data).toEqual(mockData);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should handle errors in get', async () => {
|
|
46
|
+
memoryCacheService.cache.get.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
47
|
+
const data = await memoryCacheService.get('error-key');
|
|
48
|
+
expect(data).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should set data to memory cache without TTL', async () => {
|
|
52
|
+
const mockData = { test: 'data' };
|
|
53
|
+
await memoryCacheService.set('test-key', mockData);
|
|
54
|
+
expect(memoryCacheService.cache.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should handle errors in set', async () => {
|
|
58
|
+
memoryCacheService.cache.set.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
59
|
+
await memoryCacheService.set('test-key', 'value');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should handle errors in del', async () => {
|
|
63
|
+
memoryCacheService.cache.del.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
64
|
+
await memoryCacheService.del('test-key');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should use getOrSet and call fetcher if not cached', async () => {
|
|
68
|
+
memoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
69
|
+
memoryCacheService.set = jest.fn();
|
|
70
|
+
const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
|
|
71
|
+
|
|
72
|
+
const result = await memoryCacheService.getOrSet('new-key', fetcher);
|
|
73
|
+
|
|
74
|
+
expect(result).toEqual({ new: 'data' });
|
|
75
|
+
expect(fetcher).toHaveBeenCalled();
|
|
76
|
+
// Result should be cached
|
|
77
|
+
expect(memoryCacheService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should return cached data in getOrSet', async () => {
|
|
81
|
+
const cachedData = { cached: 'data' };
|
|
82
|
+
memoryCacheService.get = jest.fn().mockResolvedValue(cachedData);
|
|
83
|
+
const fetcher = jest.fn();
|
|
84
|
+
|
|
85
|
+
const result = await memoryCacheService.getOrSet('cached-key', fetcher);
|
|
86
|
+
|
|
87
|
+
expect(result).toEqual(cachedData);
|
|
88
|
+
expect(fetcher).not.toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should handle falsy data from fetcher in getOrSet', async () => {
|
|
92
|
+
memoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
93
|
+
memoryCacheService.set = jest.fn();
|
|
94
|
+
const fetcher = jest.fn().mockResolvedValue(null);
|
|
95
|
+
|
|
96
|
+
const result = await memoryCacheService.getOrSet('empty-key', fetcher);
|
|
97
|
+
|
|
98
|
+
expect(result).toBeNull();
|
|
99
|
+
expect(memoryCacheService.set).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
const Redis = require('ioredis');
|
|
2
|
-
require('dotenv').config();
|
|
3
|
-
const logger = require('<%- loggerPath %>');
|
|
4
|
-
|
|
5
|
-
class RedisService {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.client = new Redis({
|
|
8
|
-
host: process.env.REDIS_HOST || 'localhost',
|
|
9
|
-
port: Number(process.env.REDIS_PORT) || 6379,
|
|
10
|
-
password: process.env.REDIS_PASSWORD || undefined,
|
|
11
|
-
retryStrategy: (times) => Math.min(times * 50, 2000),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
this.client.on('connect', () => {
|
|
15
|
-
logger.info('Redis connected');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
this.client.on('error', (err) => {
|
|
19
|
-
logger.error('Redis error:', err);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static getInstance() {
|
|
24
|
-
if (!RedisService.instance) {
|
|
25
|
-
RedisService.instance = new RedisService();
|
|
26
|
-
}
|
|
27
|
-
return RedisService.instance;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async get(key) {
|
|
31
|
-
try {
|
|
32
|
-
const data = await this.client.get(key);
|
|
33
|
-
return data ? JSON.parse(data) : null;
|
|
34
|
-
} catch (error) {
|
|
35
|
-
logger.error(`Redis get error for key ${key}:`, error);
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async set(key, value, ttl) {
|
|
41
|
-
try {
|
|
42
|
-
const data = JSON.stringify(value);
|
|
43
|
-
if (ttl) {
|
|
44
|
-
await this.client.set(key, data, 'EX', ttl);
|
|
45
|
-
} else {
|
|
46
|
-
await this.client.set(key, data);
|
|
47
|
-
}
|
|
48
|
-
} catch (error) {
|
|
49
|
-
logger.error(`Redis set error for key ${key}:`, error);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async del(key) {
|
|
54
|
-
try {
|
|
55
|
-
await this.client.del(key);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
logger.error(`Redis del error for key ${key}:`, error);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async getOrSet(key, fetcher, ttl = 3600) {
|
|
62
|
-
const cached = await this.get(key);
|
|
63
|
-
if (cached) return cached;
|
|
64
|
-
|
|
65
|
-
const data = await fetcher();
|
|
66
|
-
if (data) await this.set(key, data, ttl);
|
|
67
|
-
return data;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async quit() {
|
|
71
|
-
return await this.client.quit();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
module.exports = RedisService.getInstance();
|
|
1
|
+
const Redis = require('ioredis');
|
|
2
|
+
require('dotenv').config();
|
|
3
|
+
const logger = require('<%- loggerPath %>');
|
|
4
|
+
|
|
5
|
+
class RedisService {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.client = new Redis({
|
|
8
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
9
|
+
port: Number(process.env.REDIS_PORT) || 6379,
|
|
10
|
+
password: process.env.REDIS_PASSWORD || undefined,
|
|
11
|
+
retryStrategy: (times) => Math.min(times * 50, 2000),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
this.client.on('connect', () => {
|
|
15
|
+
logger.info('Redis connected');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
this.client.on('error', (err) => {
|
|
19
|
+
logger.error('Redis error:', err);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static getInstance() {
|
|
24
|
+
if (!RedisService.instance) {
|
|
25
|
+
RedisService.instance = new RedisService();
|
|
26
|
+
}
|
|
27
|
+
return RedisService.instance;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async get(key) {
|
|
31
|
+
try {
|
|
32
|
+
const data = await this.client.get(key);
|
|
33
|
+
return data ? JSON.parse(data) : null;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
logger.error(`Redis get error for key ${key}:`, error);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async set(key, value, ttl) {
|
|
41
|
+
try {
|
|
42
|
+
const data = JSON.stringify(value);
|
|
43
|
+
if (ttl) {
|
|
44
|
+
await this.client.set(key, data, 'EX', ttl);
|
|
45
|
+
} else {
|
|
46
|
+
await this.client.set(key, data);
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
logger.error(`Redis set error for key ${key}:`, error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async del(key) {
|
|
54
|
+
try {
|
|
55
|
+
await this.client.del(key);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error(`Redis del error for key ${key}:`, error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async getOrSet(key, fetcher, ttl = 3600) {
|
|
62
|
+
const cached = await this.get(key);
|
|
63
|
+
if (cached) return cached;
|
|
64
|
+
|
|
65
|
+
const data = await fetcher();
|
|
66
|
+
if (data) await this.set(key, data, ttl);
|
|
67
|
+
return data;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async quit() {
|
|
71
|
+
return await this.client.quit();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = RedisService.getInstance();
|