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.
Files changed (235) hide show
  1. package/CHANGELOG.md +309 -294
  2. package/LICENSE +15 -15
  3. package/README.md +2 -1
  4. package/lib/generator.js +139 -139
  5. package/lib/modules/app-setup.js +401 -401
  6. package/lib/modules/caching-setup.js +76 -73
  7. package/lib/modules/config-files.js +151 -151
  8. package/lib/modules/database-setup.js +116 -116
  9. package/lib/modules/kafka-setup.js +249 -191
  10. package/lib/modules/project-setup.js +32 -31
  11. package/lib/prompts.js +100 -100
  12. package/package.json +78 -67
  13. package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
  14. package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
  15. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  16. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  17. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  18. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  19. package/templates/clean-architecture/js/src/index.js.ejs +55 -55
  20. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
  21. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
  22. package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
  23. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  24. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  25. package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
  26. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
  27. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
  28. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  29. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  30. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
  31. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
  32. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
  33. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
  34. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  35. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  36. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
  37. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  38. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  39. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
  40. package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
  41. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
  42. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  43. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  44. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
  45. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
  46. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  47. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  48. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  49. package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
  50. package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
  51. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
  52. package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
  53. package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
  54. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  55. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  56. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  57. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  58. package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
  59. package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
  60. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
  61. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  62. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  63. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  64. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  65. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
  66. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
  67. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
  68. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
  69. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  70. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  71. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
  72. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  73. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
  74. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  75. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
  76. package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
  77. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  78. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  79. package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
  80. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
  81. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  82. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  83. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  84. package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  85. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
  86. package/templates/common/.cursorrules.ejs +60 -60
  87. package/templates/common/.dockerignore +12 -12
  88. package/templates/common/.env.example.ejs +41 -41
  89. package/templates/common/.gitattributes +46 -0
  90. package/templates/common/.gitlab-ci.yml.ejs +86 -86
  91. package/templates/common/.lintstagedrc +6 -6
  92. package/templates/common/.prettierrc +7 -7
  93. package/templates/common/Dockerfile +73 -73
  94. package/templates/common/Jenkinsfile.ejs +87 -87
  95. package/templates/common/README.md.ejs +294 -270
  96. package/templates/common/SECURITY.md +20 -20
  97. package/templates/common/_github/workflows/ci.yml.ejs +46 -46
  98. package/templates/common/_github/workflows/security.yml.ejs +36 -36
  99. package/templates/common/_gitignore +5 -5
  100. package/templates/common/_husky/pre-commit +4 -4
  101. package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
  102. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  103. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
  104. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  105. package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
  106. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  107. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
  108. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  109. package/templates/common/caching/js/memoryCache.js.ejs +60 -60
  110. package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
  111. package/templates/common/caching/js/redisClient.js.ejs +75 -75
  112. package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
  113. package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
  114. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  115. package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
  116. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  117. package/templates/common/database/js/database.js.ejs +19 -19
  118. package/templates/common/database/js/database.spec.js.ejs +56 -56
  119. package/templates/common/database/js/models/User.js.ejs +79 -53
  120. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  121. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  122. package/templates/common/database/js/mongoose.js.ejs +33 -33
  123. package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
  124. package/templates/common/database/ts/database.spec.ts.ejs +56 -56
  125. package/templates/common/database/ts/database.ts.ejs +21 -21
  126. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  127. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  128. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  129. package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
  130. package/templates/common/database/ts/mongoose.ts.ejs +28 -28
  131. package/templates/common/docker-compose.yml.ejs +159 -159
  132. package/templates/common/ecosystem.config.js.ejs +40 -40
  133. package/templates/common/eslint.config.mjs.ejs +77 -77
  134. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  135. package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
  136. package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
  137. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  138. package/templates/common/jest.config.js.ejs +32 -32
  139. package/templates/common/jest.e2e.config.js.ejs +8 -8
  140. package/templates/common/kafka/js/config/kafka.js +9 -9
  141. package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
  142. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  143. package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
  144. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  145. package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
  146. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  147. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  148. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  149. package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
  150. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  151. package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
  152. package/templates/common/kafka/ts/config/kafka.ts +7 -7
  153. package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
  154. package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
  155. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  156. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  157. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  158. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  159. package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
  160. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  161. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  162. package/templates/common/migrate-mongo-config.js.ejs +31 -31
  163. package/templates/common/migrations/init.js.ejs +23 -23
  164. package/templates/common/package.json.ejs +119 -118
  165. package/templates/common/prompts/add-feature.md.ejs +26 -26
  166. package/templates/common/prompts/project-context.md.ejs +43 -43
  167. package/templates/common/prompts/troubleshoot.md.ejs +28 -28
  168. package/templates/common/public/css/style.css +147 -147
  169. package/templates/common/scripts/run-e2e.js.ejs +63 -63
  170. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  171. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  172. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  173. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  174. package/templates/common/sonar-project.properties.ejs +27 -27
  175. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  176. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  177. package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
  178. package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
  179. package/templates/common/swagger.yml.ejs +118 -66
  180. package/templates/common/tsconfig.json +22 -22
  181. package/templates/common/views/ejs/index.ejs +55 -55
  182. package/templates/common/views/pug/index.pug +40 -40
  183. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  184. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  185. package/templates/mvc/js/src/config/env.js.ejs +46 -46
  186. package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
  187. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  188. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  189. package/templates/mvc/js/src/errors/ApiError.js +14 -14
  190. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  191. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  192. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  193. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  194. package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
  195. package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
  196. package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
  197. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
  198. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  199. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  200. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
  201. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  202. package/templates/mvc/js/src/index.js.ejs +136 -136
  203. package/templates/mvc/js/src/routes/api.js +10 -8
  204. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  205. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  206. package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
  207. package/templates/mvc/js/src/utils/httpCodes.js +9 -9
  208. package/templates/mvc/js/src/utils/logger.js +40 -40
  209. package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
  210. package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
  211. package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
  212. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  213. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  214. package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
  215. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  216. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  217. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  218. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  219. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
  220. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
  221. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
  222. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
  223. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  224. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  225. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
  226. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  227. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  228. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  229. package/templates/mvc/ts/src/routes/api.ts +12 -10
  230. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  231. package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  232. package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
  233. package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
  234. package/templates/mvc/ts/src/utils/logger.ts +36 -36
  235. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -1,63 +1,63 @@
1
- jest.mock('winston-daily-rotate-file');
2
- jest.mock('winston', () => {
3
- const mockLogger = {
4
- add: jest.fn(),
5
- info: jest.fn(),
6
- error: jest.fn(),
7
- warn: jest.fn()
8
- };
9
- const format = {
10
- combine: jest.fn(),
11
- timestamp: jest.fn(),
12
- json: jest.fn(),
13
- simple: jest.fn()
14
- };
15
- const transports = {
16
- Console: jest.fn(),
17
- DailyRotateFile: jest.fn()
18
- };
19
- return {
20
- format,
21
- transports,
22
- createLogger: jest.fn().mockReturnValue(mockLogger)
23
- };
24
- });
25
-
26
- <% if (architecture === 'MVC') { -%>
27
- import logger from '@/utils/logger';
28
- <% } else { -%>
29
- import logger from '@/infrastructure/log/logger';
30
- <% } -%>
31
-
32
- describe('Logger', () => {
33
- it('should export a logger instance', () => {
34
- expect(logger).toBeDefined();
35
- });
36
-
37
- it('should have info method', () => {
38
- expect(typeof logger.info).toBe('function');
39
- });
40
-
41
- it('should have error method', () => {
42
- expect(typeof logger.error).toBe('function');
43
- });
44
-
45
- it('should call info', () => {
46
- logger.info('test message');
47
- expect(logger.info).toHaveBeenCalledWith('test message');
48
- });
49
-
50
- it('should call error', () => {
51
- logger.error('test error');
52
- expect(logger.error).toHaveBeenCalledWith('test error');
53
- });
54
-
55
- it('should use JSON format in production environment', () => {
56
- const winston = require('winston');
57
- jest.resetModules();
58
- process.env.NODE_ENV = 'production';
59
- require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
60
- expect(winston.format.json).toHaveBeenCalled();
61
- process.env.NODE_ENV = 'test';
62
- });
63
- });
1
+ jest.mock('winston-daily-rotate-file');
2
+ jest.mock('winston', () => {
3
+ const mockLogger = {
4
+ add: jest.fn(),
5
+ info: jest.fn(),
6
+ error: jest.fn(),
7
+ warn: jest.fn()
8
+ };
9
+ const format = {
10
+ combine: jest.fn(),
11
+ timestamp: jest.fn(),
12
+ json: jest.fn(),
13
+ simple: jest.fn()
14
+ };
15
+ const transports = {
16
+ Console: jest.fn(),
17
+ DailyRotateFile: jest.fn()
18
+ };
19
+ return {
20
+ format,
21
+ transports,
22
+ createLogger: jest.fn().mockReturnValue(mockLogger)
23
+ };
24
+ });
25
+
26
+ <% if (architecture === 'MVC') { -%>
27
+ import logger from '@/utils/logger';
28
+ <% } else { -%>
29
+ import logger from '@/infrastructure/log/logger';
30
+ <% } -%>
31
+
32
+ describe('Logger', () => {
33
+ it('should export a logger instance', () => {
34
+ expect(logger).toBeDefined();
35
+ });
36
+
37
+ it('should have info method', () => {
38
+ expect(typeof logger.info).toBe('function');
39
+ });
40
+
41
+ it('should have error method', () => {
42
+ expect(typeof logger.error).toBe('function');
43
+ });
44
+
45
+ it('should call info', () => {
46
+ logger.info('test message');
47
+ expect(logger.info).toHaveBeenCalledWith('test message');
48
+ });
49
+
50
+ it('should call error', () => {
51
+ logger.error('test error');
52
+ expect(logger.error).toHaveBeenCalledWith('test error');
53
+ });
54
+
55
+ it('should use JSON format in production environment', () => {
56
+ const winston = require('winston');
57
+ jest.resetModules();
58
+ process.env.NODE_ENV = 'production';
59
+ require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
60
+ expect(winston.format.json).toHaveBeenCalled();
61
+ process.env.NODE_ENV = 'test';
62
+ });
63
+ });
@@ -1,36 +1,36 @@
1
- import winston from 'winston';
2
- import 'winston-daily-rotate-file';
3
-
4
- const logger = winston.createLogger({
5
- level: 'info',
6
- format: winston.format.combine(
7
- winston.format.timestamp(),
8
- winston.format.json()
9
- ),
10
- defaultMeta: { service: 'user-service' },
11
- transports: [
12
- new winston.transports.DailyRotateFile({
13
- filename: 'logs/error-%DATE%.log',
14
- datePattern: 'YYYY-MM-DD',
15
- zippedArchive: true,
16
- maxSize: '20m',
17
- maxFiles: '14d',
18
- level: 'error',
19
- }),
20
- new winston.transports.DailyRotateFile({
21
- filename: 'logs/combined-%DATE%.log',
22
- datePattern: 'YYYY-MM-DD',
23
- zippedArchive: true,
24
- maxSize: '20m',
25
- maxFiles: '14d',
26
- }),
27
- ],
28
- });
29
-
30
- logger.add(new winston.transports.Console({
31
- format: process.env.NODE_ENV !== 'production'
32
- ? winston.format.simple()
33
- : winston.format.json(),
34
- }));
35
-
36
- export default logger;
1
+ import winston from 'winston';
2
+ import 'winston-daily-rotate-file';
3
+
4
+ const logger = winston.createLogger({
5
+ level: 'info',
6
+ format: winston.format.combine(
7
+ winston.format.timestamp(),
8
+ winston.format.json()
9
+ ),
10
+ defaultMeta: { service: 'user-service' },
11
+ transports: [
12
+ new winston.transports.DailyRotateFile({
13
+ filename: 'logs/error-%DATE%.log',
14
+ datePattern: 'YYYY-MM-DD',
15
+ zippedArchive: true,
16
+ maxSize: '20m',
17
+ maxFiles: '14d',
18
+ level: 'error',
19
+ }),
20
+ new winston.transports.DailyRotateFile({
21
+ filename: 'logs/combined-%DATE%.log',
22
+ datePattern: 'YYYY-MM-DD',
23
+ zippedArchive: true,
24
+ maxSize: '20m',
25
+ maxFiles: '14d',
26
+ }),
27
+ ],
28
+ });
29
+
30
+ logger.add(new winston.transports.Console({
31
+ format: process.env.NODE_ENV !== 'production'
32
+ ? winston.format.simple()
33
+ : winston.format.json(),
34
+ }));
35
+
36
+ export default logger;
@@ -1,85 +1,175 @@
1
- import { UserRepository } from '@/infrastructure/repositories/UserRepository';
2
- import UserModel from '@/infrastructure/database/models/User';
3
-
4
- // Mock DB Model Database Layer
5
- jest.mock('@/infrastructure/database/models/User');
6
-
7
- describe('UserRepository', () => {
8
- let userRepository: UserRepository;
9
-
10
- beforeEach(() => {
11
- userRepository = new UserRepository();
12
- jest.clearAllMocks();
13
- });
14
-
15
- describe('save', () => {
16
- it('should save and return a newly created user (Happy Path)', async () => {
17
- // Arrange
18
- const payload = { id: '', name: 'TestUser', email: 'test@example.com' };
19
- <%_ if (database === 'MongoDB') { -%>
20
- const mockDbRecord = { _id: { toString: () => '1' }, name: 'TestUser', email: 'test@example.com' };
21
- (UserModel.create as jest.Mock).mockResolvedValue(mockDbRecord);
22
- <%_ } else if (database === 'None') { -%>
23
- (UserModel.create as jest.Mock).mockResolvedValue(payload);
24
- <%_ } else { -%>
25
- const mockDbRecord = { id: '1', name: 'TestUser', email: 'test@example.com' };
26
- (UserModel.create as jest.Mock).mockResolvedValue(mockDbRecord);
27
- <%_ } -%>
28
-
29
- // Act
30
- const result = await userRepository.save(payload);
31
-
32
- // Assert
33
- <%_ if (database === 'None') { -%>
34
- expect(result.name).toEqual(payload.name)
35
- <%_ } else { -%>
36
- expect(result).toEqual({ id: '1', name: 'TestUser', email: 'test@example.com' });
37
- expect(UserModel.create).toHaveBeenCalledWith({ name: payload.name, email: payload.email });
38
- <%_ } -%>
39
- });
40
-
41
- it('should throw an error when DB fails explicitly (Edge Case)', async () => {
42
- <%_ if (database === 'None') { -%>
43
- // Mocks do not naturally fail
44
- <%_ } else { -%>
45
- // Arrange
46
- const payload = { id: '', name: 'FailUser', email: 'fail@example.com' };
47
- const error = new Error('DB Connection Refused');
48
- (UserModel.create as jest.Mock).mockRejectedValue(error);
49
-
50
- // Act & Assert
51
- await expect(userRepository.save(payload)).rejects.toThrow(error);
52
- <%_ } -%>
53
- });
54
- });
55
-
56
- describe('getUsers', () => {
57
- it('should return a list of mapped UserEntities (Happy Path)', async () => {
58
- // Arrange
59
- <%_ if (database === 'MongoDB') { -%>
60
- const mockDbRecords = [{ _id: { toString: () => '1' }, name: 'User1', email: 'user1@example.com' }];
61
- (UserModel.find as jest.Mock).mockResolvedValue(mockDbRecords);
62
- <%_ } else if (database === 'None') { -%>
63
- const mockData = [{ id: '1', name: 'User1', email: 'user1@example.com' }];
64
- (UserModel.find as jest.Mock).mockResolvedValue(mockData);
65
- <%_ } else { -%>
66
- const mockDbRecords = [{ id: '1', name: 'User1', email: 'user1@example.com' }];
67
- (UserModel.findAll as jest.Mock).mockResolvedValue(mockDbRecords);
68
- <%_ } -%>
69
-
70
- // Act
71
- const result = await userRepository.getUsers();
72
-
73
- // Assert
74
- expect(result).toHaveLength(1);
75
- expect(result[0]).toEqual({ id: '1', name: 'User1', email: 'user1@example.com' });
76
- <%_ if (database !== 'None') { -%>
77
- <%_ if (database === 'MongoDB') { -%>
78
- expect(UserModel.find).toHaveBeenCalled();
79
- <%_ } else { -%>
80
- expect(UserModel.findAll).toHaveBeenCalled();
81
- <%_ } -%>
82
- <%_ } -%>
83
- });
84
- });
85
- });
1
+ import { UserRepository } from '@/infrastructure/repositories/UserRepository';
2
+ import UserModel from '@/infrastructure/database/models/User';
3
+
4
+ // Mock DB Model Database Layer
5
+ jest.mock('@/infrastructure/database/models/User');
6
+
7
+ describe('UserRepository', () => {
8
+ let userRepository: UserRepository;
9
+
10
+ beforeEach(() => {
11
+ userRepository = new UserRepository();
12
+ jest.clearAllMocks();
13
+ });
14
+
15
+ describe('save', () => {
16
+ it('should save and return a newly created user (Happy Path)', async () => {
17
+ // Arrange
18
+ const payload = { id: '', name: 'TestUser', email: 'test@example.com' };
19
+ <%_ if (database === 'MongoDB') { -%>
20
+ const mockDbRecord = { _id: { toString: () => '1' }, name: 'TestUser', email: 'test@example.com' };
21
+ (UserModel.create as jest.Mock).mockResolvedValue(mockDbRecord);
22
+ <%_ } else if (database === 'None') { -%>
23
+ (UserModel.create as jest.Mock).mockResolvedValue(payload);
24
+ <%_ } else { -%>
25
+ const mockDbRecord = { id: '1', name: 'TestUser', email: 'test@example.com' };
26
+ (UserModel.create as jest.Mock).mockResolvedValue(mockDbRecord);
27
+ <%_ } -%>
28
+
29
+ // Act
30
+ const result = await userRepository.save(payload);
31
+
32
+ // Assert
33
+ <%_ if (database === 'None') { -%>
34
+ expect(result.name).toEqual(payload.name)
35
+ <%_ } else { -%>
36
+ expect(result).toEqual({ id: '1', name: 'TestUser', email: 'test@example.com' });
37
+ expect(UserModel.create).toHaveBeenCalledWith({ name: payload.name, email: payload.email });
38
+ <%_ } -%>
39
+ });
40
+
41
+ it('should throw an error when DB fails explicitly (Edge Case)', async () => {
42
+ <%_ if (database === 'None') { -%>
43
+ // Mocks do not naturally fail
44
+ <%_ } else { -%>
45
+ // Arrange
46
+ const payload = { id: '', name: 'FailUser', email: 'fail@example.com' };
47
+ const error = new Error('DB Connection Refused');
48
+ (UserModel.create as jest.Mock).mockRejectedValue(error);
49
+
50
+ // Act & Assert
51
+ await expect(userRepository.save(payload)).rejects.toThrow(error);
52
+ <%_ } -%>
53
+ });
54
+ });
55
+
56
+ describe('getUsers', () => {
57
+ it('should return a list of mapped UserEntities (Happy Path)', async () => {
58
+ // Arrange
59
+ <%_ if (database === 'MongoDB') { -%>
60
+ const mockDbRecords = [{ _id: { toString: () => '1' }, name: 'User1', email: 'user1@example.com' }];
61
+ (UserModel.find as jest.Mock).mockResolvedValue(mockDbRecords);
62
+ <%_ } else if (database === 'None') { -%>
63
+ const mockData = [{ id: '1', name: 'User1', email: 'user1@example.com' }];
64
+ (UserModel.find as jest.Mock).mockResolvedValue(mockData);
65
+ <%_ } else { -%>
66
+ const mockDbRecords = [{ id: '1', name: 'User1', email: 'user1@example.com' }];
67
+ (UserModel.findAll as jest.Mock).mockResolvedValue(mockDbRecords);
68
+ <%_ } -%>
69
+
70
+ // Act
71
+ const result = await userRepository.getUsers();
72
+
73
+ // Assert
74
+ expect(result).toHaveLength(1);
75
+ expect(result[0]).toEqual({ id: '1', name: 'User1', email: 'user1@example.com' });
76
+ <%_ if (database !== 'None') { -%>
77
+ <%_ if (database === 'MongoDB') { -%>
78
+ expect(UserModel.find).toHaveBeenCalled();
79
+ <%_ } else { -%>
80
+ expect(UserModel.findAll).toHaveBeenCalled();
81
+ <%_ } -%>
82
+ <%_ } -%>
83
+ });
84
+ });
85
+
86
+ describe('update', () => {
87
+ it('should update and return the user (Happy Path)', async () => {
88
+ // Arrange
89
+ const id = '1';
90
+ const data = { name: 'Updated' };
91
+ const expectedUser = { id: '1', name: 'Updated', email: 'test@example.com' };
92
+
93
+ <%_ if (database === 'MongoDB') { -%>
94
+ const mockDbRecord = { _id: { toString: () => '1' }, name: 'Updated', email: 'test@example.com' };
95
+ (UserModel.findByIdAndUpdate as jest.Mock).mockResolvedValue(mockDbRecord);
96
+ <%_ } else if (database === 'None') { -%>
97
+ (UserModel.update as jest.Mock).mockResolvedValue(expectedUser);
98
+ <%_ } else { -%>
99
+ const mockDbRecord = { id: '1', name: 'Updated', email: 'test@example.com', update: jest.fn().mockResolvedValue(true) };
100
+ (UserModel.findByPk as jest.Mock).mockResolvedValue(mockDbRecord);
101
+ <%_ } -%>
102
+
103
+ // Act
104
+ const result = await userRepository.update(id, data);
105
+
106
+ // Assert
107
+ expect(result?.name).toEqual(data.name);
108
+ <%_ if (database !== 'None') { -%>
109
+ <%_ if (database === 'MongoDB') { -%>
110
+ expect(UserModel.findByIdAndUpdate).toHaveBeenCalled();
111
+ <%_ } else { -%>
112
+ expect(UserModel.findByPk).toHaveBeenCalled();
113
+ <%_ } -%>
114
+ <%_ } -%>
115
+ });
116
+
117
+ it('should return null when user not found (Error Handling)', async () => {
118
+ // Arrange
119
+ const id = '999';
120
+ <%_ if (database === 'MongoDB') { -%>
121
+ (UserModel.findByIdAndUpdate as jest.Mock).mockResolvedValue(null);
122
+ <%_ } else if (database === 'None') { -%>
123
+ (UserModel.update as jest.Mock).mockResolvedValue(null);
124
+ <%_ } else { -%>
125
+ (UserModel.findByPk as jest.Mock).mockResolvedValue(null);
126
+ <%_ } -%>
127
+
128
+ // Act
129
+ const result = await userRepository.update(id, { name: 'Fail' });
130
+
131
+ // Assert
132
+ expect(result).toBeNull();
133
+ });
134
+ });
135
+
136
+ describe('delete', () => {
137
+ it('should successfully delete a user (Happy Path)', async () => {
138
+ // Arrange
139
+ const id = '1';
140
+
141
+ <%_ if (database === 'MongoDB') { -%>
142
+ (UserModel.findByIdAndDelete as jest.Mock).mockResolvedValue(true);
143
+ <%_ } else if (database === 'None') { -%>
144
+ (UserModel.destroy as jest.Mock).mockResolvedValue(true);
145
+ <%_ } else { -%>
146
+ const mockDbRecord = { id: '1', destroy: jest.fn().mockResolvedValue(true) };
147
+ (UserModel.findByPk as jest.Mock).mockResolvedValue(mockDbRecord);
148
+ <%_ } -%>
149
+
150
+ // Act
151
+ const result = await userRepository.delete(id);
152
+
153
+ // Assert
154
+ expect(result).toBe(true);
155
+ });
156
+
157
+ it('should return false when user not found during deletion (Error Handling)', async () => {
158
+ // Arrange
159
+ const id = '999';
160
+ <%_ if (database === 'MongoDB') { -%>
161
+ (UserModel.findByIdAndDelete as jest.Mock).mockResolvedValue(null);
162
+ <%_ } else if (database === 'None') { -%>
163
+ (UserModel.destroy as jest.Mock).mockResolvedValue(false);
164
+ <%_ } else { -%>
165
+ (UserModel.findByPk as jest.Mock).mockResolvedValue(null);
166
+ <%_ } -%>
167
+
168
+ // Act
169
+ const result = await userRepository.delete(id);
170
+
171
+ // Assert
172
+ expect(result).toBe(false);
173
+ });
174
+ });
175
+ });
@@ -0,0 +1,74 @@
1
+ import { User as UserEntity } from '@/domain/user';
2
+ import UserModel from '@/infrastructure/database/models/User';
3
+
4
+ export class UserRepository {
5
+ async save(user: UserEntity): Promise<UserEntity> {
6
+ <%_ if (database === 'MongoDB') { -%>
7
+ const newUser = await UserModel.create({ name: user.name, email: user.email });
8
+ return { id: newUser._id.toString(), name: newUser.name, email: newUser.email };
9
+ <%_ } else if (database === 'None') { -%>
10
+ const newUser = await UserModel.create({ name: user.name, email: user.email });
11
+ return { id: newUser.id, name: newUser.name, email: newUser.email };
12
+ <%_ } else { -%>
13
+ const newUser = await UserModel.create({ name: user.name, email: user.email });
14
+ return { id: newUser.id, name: newUser.name, email: newUser.email };
15
+ <%_ } -%>
16
+ }
17
+
18
+ async getUsers(): Promise<UserEntity[]> {
19
+ <%_ if (database === 'MongoDB') { -%>
20
+ const users = await UserModel.find();
21
+ return users.map(user => ({
22
+ id: user._id.toString(),
23
+ name: user.name,
24
+ email: user.email
25
+ }));
26
+ <%_ } else if (database === 'None') { -%>
27
+ const users = await UserModel.find();
28
+ return users.map(user => ({
29
+ id: user.id,
30
+ name: user.name,
31
+ email: user.email
32
+ }));
33
+ <%_ } else { -%>
34
+ const users = await UserModel.findAll();
35
+ return users.map(user => ({
36
+ id: user.id,
37
+ name: user.name,
38
+ email: user.email
39
+ }));
40
+ <%_ } -%>
41
+ }
42
+
43
+ async update(id: number | string, data: Partial<UserEntity>): Promise<UserEntity | null> {
44
+ <%_ if (database === 'MongoDB') { -%>
45
+ const user = await UserModel.findByIdAndUpdate(id, data, { new: true });
46
+ if (!user) return null;
47
+ return { id: user._id.toString(), name: user.name, email: user.email };
48
+ <%_ } else if (database === 'None') { -%>
49
+ const { id: _, ...updateData } = data;
50
+ const user = await UserModel.update(id, updateData as Parameters<typeof UserModel.update>[1]);
51
+ if (!user) return null;
52
+ return { id: user.id, name: user.name, email: user.email };
53
+ <%_ } else { -%>
54
+ const user = await UserModel.findByPk(id);
55
+ if (!user) return null;
56
+ await user.update(data);
57
+ return { id: user.id || 0, name: user.name, email: user.email };
58
+ <%_ } -%>
59
+ }
60
+
61
+ async delete(id: number | string): Promise<boolean> {
62
+ <%_ if (database === 'MongoDB') { -%>
63
+ const result = await UserModel.findByIdAndDelete(id);
64
+ return !!result;
65
+ <%_ } else if (database === 'None') { -%>
66
+ return await UserModel.destroy(id);
67
+ <%_ } else { -%>
68
+ const user = await UserModel.findByPk(id);
69
+ if (!user) return false;
70
+ await user.destroy();
71
+ return true;
72
+ <%_ } -%>
73
+ }
74
+ }