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,147 +1,147 @@
|
|
|
1
|
-
jest.mock('ioredis', () => {
|
|
2
|
-
const mRedis = jest.fn(() => ({
|
|
3
|
-
on: jest.fn(),
|
|
4
|
-
get: jest.fn(),
|
|
5
|
-
set: jest.fn(),
|
|
6
|
-
del: jest.fn(),
|
|
7
|
-
quit: jest.fn().mockResolvedValue('OK'),
|
|
8
|
-
}));
|
|
9
|
-
return mRedis;
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
jest.mock('dotenv', () => ({
|
|
13
|
-
config: jest.fn()
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
const mockLogger = {
|
|
17
|
-
info: jest.fn(),
|
|
18
|
-
error: jest.fn(),
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
jest.mock('<%- loggerPath %>', () => mockLogger);
|
|
22
|
-
|
|
23
|
-
describe('Redis Service', () => {
|
|
24
|
-
let RedisService;
|
|
25
|
-
let logger;
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
jest.clearAllMocks();
|
|
29
|
-
jest.resetModules();
|
|
30
|
-
|
|
31
|
-
// Clean environment
|
|
32
|
-
const envVars = ['REDIS_HOST', 'REDIS_PORT', 'REDIS_PASSWORD'];
|
|
33
|
-
envVars.forEach(v => delete process.env[v]);
|
|
34
|
-
|
|
35
|
-
logger = require('<%- loggerPath %>');
|
|
36
|
-
RedisService = require('<%= redisClientPath %>');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should handle redis events', () => {
|
|
40
|
-
// Find the event handlers
|
|
41
|
-
const handlers = {};
|
|
42
|
-
RedisService.client.on.mock.calls.forEach(([event, handler]) => {
|
|
43
|
-
handlers[event] = handler;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (handlers['connect']) {
|
|
47
|
-
handlers['connect']();
|
|
48
|
-
expect(logger.info).toHaveBeenCalledWith('Redis connected');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (handlers['error']) {
|
|
52
|
-
handlers['error'](new Error('Test Error'));
|
|
53
|
-
expect(logger.error).toHaveBeenCalledWith('Redis error:', expect.any(Error));
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should get data from redis', async () => {
|
|
58
|
-
const mockData = { test: 'data' };
|
|
59
|
-
RedisService.client.get.mockResolvedValue(JSON.stringify(mockData));
|
|
60
|
-
|
|
61
|
-
const data = await RedisService.get('test-key');
|
|
62
|
-
expect(data).toEqual(mockData);
|
|
63
|
-
expect(RedisService.client.get).toHaveBeenCalledWith('test-key');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should return null when key not found in redis', async () => {
|
|
67
|
-
RedisService.client.get.mockResolvedValue(null);
|
|
68
|
-
const data = await RedisService.get('non-existent');
|
|
69
|
-
expect(data).toBeNull();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should handle errors in get', async () => {
|
|
73
|
-
RedisService.client.get.mockRejectedValue(new Error('Redis Error'));
|
|
74
|
-
const result = await RedisService.get('test-key');
|
|
75
|
-
expect(result).toBeNull();
|
|
76
|
-
expect(logger.error).toHaveBeenCalled();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should set data to redis without TTL', async () => {
|
|
80
|
-
const mockData = { test: 'data' };
|
|
81
|
-
await RedisService.set('test-key', mockData);
|
|
82
|
-
expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData));
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should set data to redis with TTL', async () => {
|
|
86
|
-
const mockData = { test: 'data' };
|
|
87
|
-
await RedisService.set('test-key', mockData, 3600);
|
|
88
|
-
expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData), 'EX', 3600);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle errors in set', async () => {
|
|
92
|
-
RedisService.client.set.mockRejectedValue(new Error('Redis Error'));
|
|
93
|
-
await RedisService.set('test-key', 'value');
|
|
94
|
-
expect(logger.error).toHaveBeenCalled();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should delete data from redis', async () => {
|
|
98
|
-
await RedisService.del('test-key');
|
|
99
|
-
expect(RedisService.client.del).toHaveBeenCalledWith('test-key');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should handle errors in del', async () => {
|
|
103
|
-
RedisService.client.del.mockRejectedValue(new Error('Redis Error'));
|
|
104
|
-
await RedisService.del('test-key');
|
|
105
|
-
expect(logger.error).toHaveBeenCalled();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should use getOrSet and call fetcher if not cached', async () => {
|
|
109
|
-
RedisService.get = jest.fn().mockResolvedValue(null);
|
|
110
|
-
RedisService.set = jest.fn();
|
|
111
|
-
const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
|
|
112
|
-
|
|
113
|
-
const result = await RedisService.getOrSet('new-key', fetcher);
|
|
114
|
-
|
|
115
|
-
expect(result).toEqual({ new: 'data' });
|
|
116
|
-
expect(fetcher).toHaveBeenCalled();
|
|
117
|
-
expect(RedisService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should use getOrSet and return cached data', async () => {
|
|
121
|
-
const cachedData = { cached: 'data' };
|
|
122
|
-
RedisService.get = jest.fn().mockResolvedValue(cachedData);
|
|
123
|
-
const fetcher = jest.fn();
|
|
124
|
-
|
|
125
|
-
const result = await RedisService.getOrSet('cached-key', fetcher);
|
|
126
|
-
|
|
127
|
-
expect(result).toEqual(cachedData);
|
|
128
|
-
expect(fetcher).not.toHaveBeenCalled();
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should handle falsy data from fetcher in getOrSet', async () => {
|
|
132
|
-
RedisService.get = jest.fn().mockResolvedValue(null);
|
|
133
|
-
RedisService.set = jest.fn();
|
|
134
|
-
const fetcher = jest.fn().mockResolvedValue(null);
|
|
135
|
-
|
|
136
|
-
const result = await RedisService.getOrSet('empty-key', fetcher);
|
|
137
|
-
|
|
138
|
-
expect(result).toBeNull();
|
|
139
|
-
expect(RedisService.set).not.toHaveBeenCalled();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should quit the redis client', async () => {
|
|
143
|
-
const result = await RedisService.quit();
|
|
144
|
-
expect(result).toBe('OK');
|
|
145
|
-
expect(RedisService.client.quit).toHaveBeenCalled();
|
|
146
|
-
});
|
|
147
|
-
});
|
|
1
|
+
jest.mock('ioredis', () => {
|
|
2
|
+
const mRedis = jest.fn(() => ({
|
|
3
|
+
on: jest.fn(),
|
|
4
|
+
get: jest.fn(),
|
|
5
|
+
set: jest.fn(),
|
|
6
|
+
del: jest.fn(),
|
|
7
|
+
quit: jest.fn().mockResolvedValue('OK'),
|
|
8
|
+
}));
|
|
9
|
+
return mRedis;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
jest.mock('dotenv', () => ({
|
|
13
|
+
config: jest.fn()
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const mockLogger = {
|
|
17
|
+
info: jest.fn(),
|
|
18
|
+
error: jest.fn(),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
jest.mock('<%- loggerPath %>', () => mockLogger);
|
|
22
|
+
|
|
23
|
+
describe('Redis Service', () => {
|
|
24
|
+
let RedisService;
|
|
25
|
+
let logger;
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
jest.resetModules();
|
|
30
|
+
|
|
31
|
+
// Clean environment
|
|
32
|
+
const envVars = ['REDIS_HOST', 'REDIS_PORT', 'REDIS_PASSWORD'];
|
|
33
|
+
envVars.forEach(v => delete process.env[v]);
|
|
34
|
+
|
|
35
|
+
logger = require('<%- loggerPath %>');
|
|
36
|
+
RedisService = require('<%= redisClientPath %>');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle redis events', () => {
|
|
40
|
+
// Find the event handlers
|
|
41
|
+
const handlers = {};
|
|
42
|
+
RedisService.client.on.mock.calls.forEach(([event, handler]) => {
|
|
43
|
+
handlers[event] = handler;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (handlers['connect']) {
|
|
47
|
+
handlers['connect']();
|
|
48
|
+
expect(logger.info).toHaveBeenCalledWith('Redis connected');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (handlers['error']) {
|
|
52
|
+
handlers['error'](new Error('Test Error'));
|
|
53
|
+
expect(logger.error).toHaveBeenCalledWith('Redis error:', expect.any(Error));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should get data from redis', async () => {
|
|
58
|
+
const mockData = { test: 'data' };
|
|
59
|
+
RedisService.client.get.mockResolvedValue(JSON.stringify(mockData));
|
|
60
|
+
|
|
61
|
+
const data = await RedisService.get('test-key');
|
|
62
|
+
expect(data).toEqual(mockData);
|
|
63
|
+
expect(RedisService.client.get).toHaveBeenCalledWith('test-key');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return null when key not found in redis', async () => {
|
|
67
|
+
RedisService.client.get.mockResolvedValue(null);
|
|
68
|
+
const data = await RedisService.get('non-existent');
|
|
69
|
+
expect(data).toBeNull();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should handle errors in get', async () => {
|
|
73
|
+
RedisService.client.get.mockRejectedValue(new Error('Redis Error'));
|
|
74
|
+
const result = await RedisService.get('test-key');
|
|
75
|
+
expect(result).toBeNull();
|
|
76
|
+
expect(logger.error).toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should set data to redis without TTL', async () => {
|
|
80
|
+
const mockData = { test: 'data' };
|
|
81
|
+
await RedisService.set('test-key', mockData);
|
|
82
|
+
expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should set data to redis with TTL', async () => {
|
|
86
|
+
const mockData = { test: 'data' };
|
|
87
|
+
await RedisService.set('test-key', mockData, 3600);
|
|
88
|
+
expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData), 'EX', 3600);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should handle errors in set', async () => {
|
|
92
|
+
RedisService.client.set.mockRejectedValue(new Error('Redis Error'));
|
|
93
|
+
await RedisService.set('test-key', 'value');
|
|
94
|
+
expect(logger.error).toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should delete data from redis', async () => {
|
|
98
|
+
await RedisService.del('test-key');
|
|
99
|
+
expect(RedisService.client.del).toHaveBeenCalledWith('test-key');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should handle errors in del', async () => {
|
|
103
|
+
RedisService.client.del.mockRejectedValue(new Error('Redis Error'));
|
|
104
|
+
await RedisService.del('test-key');
|
|
105
|
+
expect(logger.error).toHaveBeenCalled();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should use getOrSet and call fetcher if not cached', async () => {
|
|
109
|
+
RedisService.get = jest.fn().mockResolvedValue(null);
|
|
110
|
+
RedisService.set = jest.fn();
|
|
111
|
+
const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
|
|
112
|
+
|
|
113
|
+
const result = await RedisService.getOrSet('new-key', fetcher);
|
|
114
|
+
|
|
115
|
+
expect(result).toEqual({ new: 'data' });
|
|
116
|
+
expect(fetcher).toHaveBeenCalled();
|
|
117
|
+
expect(RedisService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should use getOrSet and return cached data', async () => {
|
|
121
|
+
const cachedData = { cached: 'data' };
|
|
122
|
+
RedisService.get = jest.fn().mockResolvedValue(cachedData);
|
|
123
|
+
const fetcher = jest.fn();
|
|
124
|
+
|
|
125
|
+
const result = await RedisService.getOrSet('cached-key', fetcher);
|
|
126
|
+
|
|
127
|
+
expect(result).toEqual(cachedData);
|
|
128
|
+
expect(fetcher).not.toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should handle falsy data from fetcher in getOrSet', async () => {
|
|
132
|
+
RedisService.get = jest.fn().mockResolvedValue(null);
|
|
133
|
+
RedisService.set = jest.fn();
|
|
134
|
+
const fetcher = jest.fn().mockResolvedValue(null);
|
|
135
|
+
|
|
136
|
+
const result = await RedisService.getOrSet('empty-key', fetcher);
|
|
137
|
+
|
|
138
|
+
expect(result).toBeNull();
|
|
139
|
+
expect(RedisService.set).not.toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should quit the redis client', async () => {
|
|
143
|
+
const result = await RedisService.quit();
|
|
144
|
+
expect(result).toBe('OK');
|
|
145
|
+
expect(RedisService.client.quit).toHaveBeenCalled();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -1,102 +1,102 @@
|
|
|
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: any;
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
jest.clearAllMocks();
|
|
19
|
-
jest.resetModules();
|
|
20
|
-
MemoryCacheService = require('<% if (architecture === "MVC") { %>@/config/memoryCache<% } else { %>@/infrastructure/caching/memoryCache<% } %>').default;
|
|
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
|
-
// Should not throw
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should handle errors in del', async () => {
|
|
64
|
-
MemoryCacheService.cache.del.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
65
|
-
await MemoryCacheService.del('test-key');
|
|
66
|
-
// Should not throw
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should use getOrSet and call fetcher if not cached', async () => {
|
|
70
|
-
MemoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
71
|
-
MemoryCacheService.set = jest.fn();
|
|
72
|
-
const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
|
|
73
|
-
|
|
74
|
-
const result = await MemoryCacheService.getOrSet('new-key', fetcher);
|
|
75
|
-
|
|
76
|
-
expect(result).toEqual({ new: 'data' });
|
|
77
|
-
expect(fetcher).toHaveBeenCalled();
|
|
78
|
-
expect(MemoryCacheService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should return cached data in getOrSet', async () => {
|
|
82
|
-
const cachedData = { cached: 'data' };
|
|
83
|
-
MemoryCacheService.get = jest.fn().mockResolvedValue(cachedData);
|
|
84
|
-
const fetcher = jest.fn();
|
|
85
|
-
|
|
86
|
-
const result = await MemoryCacheService.getOrSet('cached-key', fetcher);
|
|
87
|
-
|
|
88
|
-
expect(result).toEqual(cachedData);
|
|
89
|
-
expect(fetcher).not.toHaveBeenCalled();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should handle falsy data from fetcher in getOrSet', async () => {
|
|
93
|
-
MemoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
94
|
-
MemoryCacheService.set = jest.fn();
|
|
95
|
-
const fetcher = jest.fn().mockResolvedValue(null);
|
|
96
|
-
|
|
97
|
-
const result = await MemoryCacheService.getOrSet('empty-key', fetcher);
|
|
98
|
-
|
|
99
|
-
expect(result).toBeNull();
|
|
100
|
-
expect(MemoryCacheService.set).not.toHaveBeenCalled();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
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: any;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
MemoryCacheService = require('<% if (architecture === "MVC") { %>@/config/memoryCache<% } else { %>@/infrastructure/caching/memoryCache<% } %>').default;
|
|
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
|
+
// Should not throw
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should handle errors in del', async () => {
|
|
64
|
+
MemoryCacheService.cache.del.mockImplementation(() => { throw new Error('Cache Error'); });
|
|
65
|
+
await MemoryCacheService.del('test-key');
|
|
66
|
+
// Should not throw
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should use getOrSet and call fetcher if not cached', async () => {
|
|
70
|
+
MemoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
71
|
+
MemoryCacheService.set = jest.fn();
|
|
72
|
+
const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
|
|
73
|
+
|
|
74
|
+
const result = await MemoryCacheService.getOrSet('new-key', fetcher);
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual({ new: 'data' });
|
|
77
|
+
expect(fetcher).toHaveBeenCalled();
|
|
78
|
+
expect(MemoryCacheService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should return cached data in getOrSet', async () => {
|
|
82
|
+
const cachedData = { cached: 'data' };
|
|
83
|
+
MemoryCacheService.get = jest.fn().mockResolvedValue(cachedData);
|
|
84
|
+
const fetcher = jest.fn();
|
|
85
|
+
|
|
86
|
+
const result = await MemoryCacheService.getOrSet('cached-key', fetcher);
|
|
87
|
+
|
|
88
|
+
expect(result).toEqual(cachedData);
|
|
89
|
+
expect(fetcher).not.toHaveBeenCalled();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle falsy data from fetcher in getOrSet', async () => {
|
|
93
|
+
MemoryCacheService.get = jest.fn().mockResolvedValue(null);
|
|
94
|
+
MemoryCacheService.set = jest.fn();
|
|
95
|
+
const fetcher = jest.fn().mockResolvedValue(null);
|
|
96
|
+
|
|
97
|
+
const result = await MemoryCacheService.getOrSet('empty-key', fetcher);
|
|
98
|
+
|
|
99
|
+
expect(result).toBeNull();
|
|
100
|
+
expect(MemoryCacheService.set).not.toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -1,64 +1,73 @@
|
|
|
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
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
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 flush(): Promise<void> {
|
|
55
|
+
try {
|
|
56
|
+
this.cache.flushAll();
|
|
57
|
+
logger.info('Memory Cache flushed');
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger.error('Memory Cache flush error:', error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public async getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl: number = 3600): Promise<T> {
|
|
64
|
+
const cached = await this.get<T>(key);
|
|
65
|
+
if (cached) return cached;
|
|
66
|
+
|
|
67
|
+
const data = await fetcher();
|
|
68
|
+
if (data) await this.set(key, data, ttl);
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default MemoryCacheService.getInstance();
|