nodejs-quickstart-structure 1.18.1 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +2 -1
- package/lib/modules/caching-setup.js +76 -73
- package/lib/modules/kafka-setup.js +249 -191
- package/lib/modules/project-setup.js +1 -0
- package/package.json +13 -2
- 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/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/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/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/user.types.js.ejs +19 -17
- package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
- 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/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/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/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/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/user.types.ts.ejs +17 -15
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
- 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/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/common/.gitattributes +46 -0
- package/templates/common/README.md.ejs +294 -270
- package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
- package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
- package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
- package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
- package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
- package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
- 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/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/health/js/healthRoute.js.ejs +50 -47
- package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
- package/templates/common/jest.e2e.config.js.ejs +8 -8
- package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
- package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
- 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/utils/kafkaEvents.js.ejs +7 -0
- 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.ts.ejs +95 -95
- package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
- 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/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/swagger.yml.ejs +118 -66
- 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/controllers/userController.js.ejs +246 -105
- package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
- 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/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/user.types.js.ejs +19 -17
- 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/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/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/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/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/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs
CHANGED
|
@@ -1,39 +1,69 @@
|
|
|
1
|
-
const UserModel = require('../database/models/User');
|
|
2
|
-
|
|
3
|
-
class UserRepository {
|
|
4
|
-
async save(user) {
|
|
5
|
-
<%_ if (database === 'None') { -%>
|
|
6
|
-
const newUser = await UserModel.create(user);
|
|
7
|
-
return newUser;
|
|
8
|
-
<%_ } else { -%>
|
|
9
|
-
const newUser = await UserModel.create({ name: user.name, email: user.email });
|
|
10
|
-
<%_ if (database === 'MongoDB') { -%>
|
|
11
|
-
return { ...user, id: newUser._id.toString() };
|
|
12
|
-
<%_ } else { -%>
|
|
13
|
-
return { ...user, id: newUser.id };
|
|
14
|
-
<%_ } -%>
|
|
15
|
-
<%_ } -%>
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async getUsers() {
|
|
19
|
-
<%_ if (database === 'None') { -%>
|
|
20
|
-
return await UserModel.find();
|
|
21
|
-
<%_ } else if (database === 'MongoDB') { -%>
|
|
22
|
-
const users = await UserModel.find();
|
|
23
|
-
return users.map(user => ({
|
|
24
|
-
id: user._id.toString(),
|
|
25
|
-
name: user.name,
|
|
26
|
-
email: user.email
|
|
27
|
-
}));
|
|
28
|
-
<%_ } else { -%>
|
|
29
|
-
const users = await UserModel.findAll();
|
|
30
|
-
return users.map(user => ({
|
|
31
|
-
id: user.id,
|
|
32
|
-
name: user.name,
|
|
33
|
-
email: user.email
|
|
34
|
-
}));
|
|
35
|
-
<%_ } -%>
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
const UserModel = require('../database/models/User');
|
|
2
|
+
|
|
3
|
+
class UserRepository {
|
|
4
|
+
async save(user) {
|
|
5
|
+
<%_ if (database === 'None') { -%>
|
|
6
|
+
const newUser = await UserModel.create(user);
|
|
7
|
+
return newUser;
|
|
8
|
+
<%_ } else { -%>
|
|
9
|
+
const newUser = await UserModel.create({ name: user.name, email: user.email });
|
|
10
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
11
|
+
return { ...user, id: newUser._id.toString() };
|
|
12
|
+
<%_ } else { -%>
|
|
13
|
+
return { ...user, id: newUser.id };
|
|
14
|
+
<%_ } -%>
|
|
15
|
+
<%_ } -%>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async getUsers() {
|
|
19
|
+
<%_ if (database === 'None') { -%>
|
|
20
|
+
return await UserModel.find();
|
|
21
|
+
<%_ } else if (database === 'MongoDB') { -%>
|
|
22
|
+
const users = await UserModel.find();
|
|
23
|
+
return users.map(user => ({
|
|
24
|
+
id: user._id.toString(),
|
|
25
|
+
name: user.name,
|
|
26
|
+
email: user.email
|
|
27
|
+
}));
|
|
28
|
+
<%_ } else { -%>
|
|
29
|
+
const users = await UserModel.findAll();
|
|
30
|
+
return users.map(user => ({
|
|
31
|
+
id: user.id,
|
|
32
|
+
name: user.name,
|
|
33
|
+
email: user.email
|
|
34
|
+
}));
|
|
35
|
+
<%_ } -%>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async update(id, data) {
|
|
39
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
40
|
+
const user = await UserModel.findByIdAndUpdate(id, data, { new: true });
|
|
41
|
+
if (!user) return null;
|
|
42
|
+
return { id: user._id.toString(), name: user.name, email: user.email };
|
|
43
|
+
<%_ } else if (database === 'None') { -%>
|
|
44
|
+
const user = await UserModel.update(id, data);
|
|
45
|
+
return user;
|
|
46
|
+
<%_ } else { -%>
|
|
47
|
+
const user = await UserModel.findByPk(id);
|
|
48
|
+
if (!user) return null;
|
|
49
|
+
await user.update(data);
|
|
50
|
+
return { id: user.id || 0, name: user.name, email: user.email };
|
|
51
|
+
<%_ } -%>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async delete(id) {
|
|
55
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
56
|
+
const result = await UserModel.findByIdAndDelete(id);
|
|
57
|
+
return !!result;
|
|
58
|
+
<%_ } else if (database === 'None') { -%>
|
|
59
|
+
return await UserModel.destroy(id);
|
|
60
|
+
<%_ } else { -%>
|
|
61
|
+
const user = await UserModel.findByPk(id);
|
|
62
|
+
if (!user) return false;
|
|
63
|
+
await user.destroy();
|
|
64
|
+
return true;
|
|
65
|
+
<%_ } -%>
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = UserRepository;
|
package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs
CHANGED
|
@@ -1,81 +1,142 @@
|
|
|
1
|
-
const UserRepository = require('@/infrastructure/repositories/UserRepository');
|
|
2
|
-
const UserModel = require('@/infrastructure/database/models/User');
|
|
3
|
-
|
|
4
|
-
jest.mock('@/infrastructure/database/models/User');
|
|
5
|
-
|
|
6
|
-
describe('UserRepository', () => {
|
|
7
|
-
let userRepository;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
userRepository = new UserRepository();
|
|
11
|
-
jest.clearAllMocks();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
describe('save', () => {
|
|
15
|
-
it('should save and return a newly created user (Happy Path)', async () => {
|
|
16
|
-
const userData = { name: 'New User', email: 'new@example.com' };
|
|
17
|
-
<%_ if (database === 'MongoDB') { -%>
|
|
18
|
-
const savedData = { _id: 'mock-id', ...userData };
|
|
19
|
-
UserModel.create.mockResolvedValue(savedData);
|
|
20
|
-
<%_ } else if (database === 'None') { -%>
|
|
21
|
-
UserModel.create.mockResolvedValue(userData);
|
|
22
|
-
<%_ } else { -%>
|
|
23
|
-
const savedData = { <%= database === "MongoDB" ? "_id" : "id" %>: '<%= database === "MongoDB" ? "mock-id" : "1" %>', ...userData };
|
|
24
|
-
UserModel.create.mockResolvedValue(savedData);
|
|
25
|
-
<%_ } -%>
|
|
26
|
-
|
|
27
|
-
const result = await userRepository.save(userData);
|
|
28
|
-
|
|
29
|
-
<%_ if (database === 'None') { -%>
|
|
30
|
-
expect(result.name).toEqual(userData.name);
|
|
31
|
-
<%_ } else { -%>
|
|
32
|
-
expect(UserModel.create).toHaveBeenCalledWith(userData);
|
|
33
|
-
expect(result).toEqual({ id: '<%= database === "MongoDB" ? "mock-id" : "1" %>', ...userData });
|
|
34
|
-
<%_ } -%>
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should throw an error when DB fails explicitly (Edge Case)', async () => {
|
|
38
|
-
<%_ if (database === 'None') { -%>
|
|
39
|
-
// mock data logic doesn't throw naturally
|
|
40
|
-
<%_ } else { -%>
|
|
41
|
-
const error = new Error('DB Error');
|
|
42
|
-
UserModel.create.mockRejectedValue(error);
|
|
43
|
-
|
|
44
|
-
await expect(userRepository.save({})).rejects.toThrow('DB Error');
|
|
45
|
-
<%_ } -%>
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('getUsers', () => {
|
|
50
|
-
it('should return a list of mapped UserEntities (Happy Path)', async () => {
|
|
51
|
-
<%_ if (database === 'MongoDB') { -%>
|
|
52
|
-
const mockUsers = [
|
|
53
|
-
{ _id: '1', name: 'User 1', email: 'u1@test.com' },
|
|
54
|
-
{ _id: '2', name: 'User 2', email: 'u2@test.com' }
|
|
55
|
-
];
|
|
56
|
-
UserModel.find.mockResolvedValue(mockUsers);
|
|
57
|
-
<%_ } else if (database === 'None') { -%>
|
|
58
|
-
const mockUsers = [{ id: '1', name: 'User 1', email: 'u1@test.com' }];
|
|
59
|
-
UserModel.find.mockResolvedValue(mockUsers);
|
|
60
|
-
<%_ } else { -%>
|
|
61
|
-
const mockUsers = [
|
|
62
|
-
{ <%= database === "MongoDB" ? "_id" : "id" %>: '1', name: 'User 1', email: 'u1@test.com' },
|
|
63
|
-
{ <%= database === "MongoDB" ? "_id" : "id" %>: '2', name: 'User 2', email: 'u2@test.com' }
|
|
64
|
-
];
|
|
65
|
-
UserModel.<%= database === "MongoDB" ? "find" : "findAll" %>.mockResolvedValue(mockUsers);
|
|
66
|
-
<%_ } -%>
|
|
67
|
-
|
|
68
|
-
const result = await userRepository.getUsers();
|
|
69
|
-
|
|
70
|
-
<%_ if (database !== 'None') { -%>
|
|
71
|
-
expect(UserModel.<%= database === 'MongoDB' ? 'find' : 'findAll' %>).toHaveBeenCalled();
|
|
72
|
-
<%_ } -%>
|
|
73
|
-
expect(result).toEqual([
|
|
74
|
-
{ id: '1', name: 'User 1', email: 'u1@test.com' }
|
|
75
|
-
<%_ if (database !== 'None') { -%>
|
|
76
|
-
, { id: '2', name: 'User 2', email: 'u2@test.com' }
|
|
77
|
-
<%_ } -%>
|
|
78
|
-
]);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
1
|
+
const UserRepository = require('@/infrastructure/repositories/UserRepository');
|
|
2
|
+
const UserModel = require('@/infrastructure/database/models/User');
|
|
3
|
+
|
|
4
|
+
jest.mock('@/infrastructure/database/models/User');
|
|
5
|
+
|
|
6
|
+
describe('UserRepository', () => {
|
|
7
|
+
let userRepository;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
userRepository = new UserRepository();
|
|
11
|
+
jest.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('save', () => {
|
|
15
|
+
it('should save and return a newly created user (Happy Path)', async () => {
|
|
16
|
+
const userData = { name: 'New User', email: 'new@example.com' };
|
|
17
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
18
|
+
const savedData = { _id: 'mock-id', ...userData };
|
|
19
|
+
UserModel.create.mockResolvedValue(savedData);
|
|
20
|
+
<%_ } else if (database === 'None') { -%>
|
|
21
|
+
UserModel.create.mockResolvedValue(userData);
|
|
22
|
+
<%_ } else { -%>
|
|
23
|
+
const savedData = { <%= database === "MongoDB" ? "_id" : "id" %>: '<%= database === "MongoDB" ? "mock-id" : "1" %>', ...userData };
|
|
24
|
+
UserModel.create.mockResolvedValue(savedData);
|
|
25
|
+
<%_ } -%>
|
|
26
|
+
|
|
27
|
+
const result = await userRepository.save(userData);
|
|
28
|
+
|
|
29
|
+
<%_ if (database === 'None') { -%>
|
|
30
|
+
expect(result.name).toEqual(userData.name);
|
|
31
|
+
<%_ } else { -%>
|
|
32
|
+
expect(UserModel.create).toHaveBeenCalledWith(userData);
|
|
33
|
+
expect(result).toEqual({ id: '<%= database === "MongoDB" ? "mock-id" : "1" %>', ...userData });
|
|
34
|
+
<%_ } -%>
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should throw an error when DB fails explicitly (Edge Case)', async () => {
|
|
38
|
+
<%_ if (database === 'None') { -%>
|
|
39
|
+
// mock data logic doesn't throw naturally
|
|
40
|
+
<%_ } else { -%>
|
|
41
|
+
const error = new Error('DB Error');
|
|
42
|
+
UserModel.create.mockRejectedValue(error);
|
|
43
|
+
|
|
44
|
+
await expect(userRepository.save({})).rejects.toThrow('DB Error');
|
|
45
|
+
<%_ } -%>
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('getUsers', () => {
|
|
50
|
+
it('should return a list of mapped UserEntities (Happy Path)', async () => {
|
|
51
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
52
|
+
const mockUsers = [
|
|
53
|
+
{ _id: '1', name: 'User 1', email: 'u1@test.com' },
|
|
54
|
+
{ _id: '2', name: 'User 2', email: 'u2@test.com' }
|
|
55
|
+
];
|
|
56
|
+
UserModel.find.mockResolvedValue(mockUsers);
|
|
57
|
+
<%_ } else if (database === 'None') { -%>
|
|
58
|
+
const mockUsers = [{ id: '1', name: 'User 1', email: 'u1@test.com' }];
|
|
59
|
+
UserModel.find.mockResolvedValue(mockUsers);
|
|
60
|
+
<%_ } else { -%>
|
|
61
|
+
const mockUsers = [
|
|
62
|
+
{ <%= database === "MongoDB" ? "_id" : "id" %>: '1', name: 'User 1', email: 'u1@test.com' },
|
|
63
|
+
{ <%= database === "MongoDB" ? "_id" : "id" %>: '2', name: 'User 2', email: 'u2@test.com' }
|
|
64
|
+
];
|
|
65
|
+
UserModel.<%= database === "MongoDB" ? "find" : "findAll" %>.mockResolvedValue(mockUsers);
|
|
66
|
+
<%_ } -%>
|
|
67
|
+
|
|
68
|
+
const result = await userRepository.getUsers();
|
|
69
|
+
|
|
70
|
+
<%_ if (database !== 'None') { -%>
|
|
71
|
+
expect(UserModel.<%= database === 'MongoDB' ? 'find' : 'findAll' %>).toHaveBeenCalled();
|
|
72
|
+
<%_ } -%>
|
|
73
|
+
expect(result).toEqual([
|
|
74
|
+
{ id: '1', name: 'User 1', email: 'u1@test.com' }
|
|
75
|
+
<%_ if (database !== 'None') { -%>
|
|
76
|
+
, { id: '2', name: 'User 2', email: 'u2@test.com' }
|
|
77
|
+
<%_ } -%>
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('update', () => {
|
|
83
|
+
it('should successfully update a user (Happy Path)', async () => {
|
|
84
|
+
const id = '1';
|
|
85
|
+
const updateData = { name: 'Updated name' };
|
|
86
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
87
|
+
const updatedUser = { _id: id, ...updateData, email: 'test@test.com' };
|
|
88
|
+
UserModel.findByIdAndUpdate.mockResolvedValue(updatedUser);
|
|
89
|
+
<%_ } else if (database === 'None') { -%>
|
|
90
|
+
const updatedUser = { id, ...updateData, email: 'test@test.com' };
|
|
91
|
+
UserModel.update.mockResolvedValue(updatedUser);
|
|
92
|
+
<%_ } else { -%>
|
|
93
|
+
const updatedUser = { id: '1', ...updateData, email: 'test@test.com', update: jest.fn().mockResolvedValue(true) };
|
|
94
|
+
UserModel.findByPk.mockResolvedValue(updatedUser);
|
|
95
|
+
<%_ } -%>
|
|
96
|
+
|
|
97
|
+
const result = await userRepository.update(id, updateData);
|
|
98
|
+
expect(result.name).toEqual(updateData.name);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should handle user not found during update (Error Handling)', async () => {
|
|
102
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
103
|
+
UserModel.findByIdAndUpdate.mockResolvedValue(null);
|
|
104
|
+
<%_ } else if (database === 'None') { -%>
|
|
105
|
+
UserModel.update.mockResolvedValue(null);
|
|
106
|
+
<%_ } else { -%>
|
|
107
|
+
UserModel.findByPk.mockResolvedValue(null);
|
|
108
|
+
<%_ } -%>
|
|
109
|
+
const result = await userRepository.update('999', { name: 'fail' });
|
|
110
|
+
expect(result).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('delete', () => {
|
|
115
|
+
it('should successfully delete a user (Happy Path)', async () => {
|
|
116
|
+
const id = '1';
|
|
117
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
118
|
+
UserModel.findByIdAndDelete.mockResolvedValue(true);
|
|
119
|
+
<%_ } else if (database === 'None') { -%>
|
|
120
|
+
UserModel.destroy.mockResolvedValue(true);
|
|
121
|
+
<%_ } else { -%>
|
|
122
|
+
const userMock = { id, destroy: jest.fn().mockResolvedValue(true) };
|
|
123
|
+
UserModel.findByPk.mockResolvedValue(userMock);
|
|
124
|
+
<%_ } -%>
|
|
125
|
+
|
|
126
|
+
const result = await userRepository.delete(id);
|
|
127
|
+
expect(result).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should handle user not found during deletion (Error Handling)', async () => {
|
|
131
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
132
|
+
UserModel.findByIdAndDelete.mockResolvedValue(null);
|
|
133
|
+
<%_ } else if (database === 'None') { -%>
|
|
134
|
+
UserModel.destroy.mockResolvedValue(false);
|
|
135
|
+
<%_ } else { -%>
|
|
136
|
+
UserModel.findByPk.mockResolvedValue(null);
|
|
137
|
+
<%_ } -%>
|
|
138
|
+
const result = await userRepository.delete('999');
|
|
139
|
+
expect(result).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -1,75 +1,156 @@
|
|
|
1
|
-
const CreateUser = require('../../usecases/CreateUser');
|
|
2
|
-
const GetAllUsers = require('../../usecases/GetAllUsers');
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
1
|
+
const CreateUser = require('../../usecases/CreateUser');
|
|
2
|
+
const GetAllUsers = require('../../usecases/GetAllUsers');
|
|
3
|
+
const UpdateUser = require('../../usecases/UpdateUser');
|
|
4
|
+
const DeleteUser = require('../../usecases/DeleteUser');
|
|
5
|
+
const UserRepository = require('../../infrastructure/repositories/UserRepository');
|
|
6
|
+
const ERROR_MESSAGES = require('../../utils/errorMessages');
|
|
7
|
+
<% if (communication !== 'GraphQL') { -%>
|
|
8
|
+
const HTTP_STATUS = require('../../utils/httpCodes');
|
|
9
|
+
<% } -%>
|
|
10
|
+
const logger = require('../../infrastructure/log/logger');
|
|
11
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
12
|
+
const { sendMessage } = require('../../infrastructure/messaging/kafkaClient');
|
|
13
|
+
const { KAFKA_ACTIONS } = require('../../utils/kafkaEvents');
|
|
14
|
+
<%_ } -%>
|
|
15
|
+
|
|
16
|
+
class UserController {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.userRepository = new UserRepository();
|
|
19
|
+
this.createUserUseCase = new CreateUser(this.userRepository);
|
|
20
|
+
this.getAllUsersUseCase = new GetAllUsers(this.userRepository);
|
|
21
|
+
this.updateUserUseCase = new UpdateUser(this.userRepository);
|
|
22
|
+
this.deleteUserUseCase = new DeleteUser(this.userRepository);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
<% if (communication === 'GraphQL') { -%>
|
|
26
|
+
async getUsers() {
|
|
27
|
+
try {
|
|
28
|
+
return await this.getAllUsersUseCase.execute();
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.error(`${ERROR_MESSAGES.FETCH_USERS_ERROR}:`, error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async createUser(data) {
|
|
36
|
+
const { name, email } = data;
|
|
37
|
+
try {
|
|
38
|
+
const user = await this.createUserUseCase.execute(name, email);
|
|
39
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
40
|
+
await sendMessage('user-topic', JSON.stringify({
|
|
41
|
+
action: KAFKA_ACTIONS.USER_CREATED,
|
|
42
|
+
payload: { id: user.id || user._id, email: user.email }
|
|
43
|
+
}), (user.id || user._id).toString());
|
|
44
|
+
<%_ } -%>
|
|
45
|
+
return user;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error(`${ERROR_MESSAGES.CREATE_USER_ERROR}:`, error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async updateUser(id, data) {
|
|
53
|
+
try {
|
|
54
|
+
const user = await this.updateUserUseCase.execute(id, data);
|
|
55
|
+
if (!user) throw new Error(ERROR_MESSAGES.USER_NOT_FOUND);
|
|
56
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
57
|
+
await sendMessage('user-topic', JSON.stringify({
|
|
58
|
+
action: KAFKA_ACTIONS.USER_UPDATED,
|
|
59
|
+
payload: { id, email: user.email }
|
|
60
|
+
}), id);
|
|
61
|
+
<%_ } -%>
|
|
62
|
+
return user;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
logger.error(`${ERROR_MESSAGES.UPDATE_USER_ERROR}:`, error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async deleteUser(id) {
|
|
70
|
+
try {
|
|
71
|
+
const deleted = await this.deleteUserUseCase.execute(id);
|
|
72
|
+
if (!deleted) throw new Error(ERROR_MESSAGES.USER_NOT_FOUND);
|
|
73
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
74
|
+
await sendMessage('user-topic', JSON.stringify({
|
|
75
|
+
action: KAFKA_ACTIONS.USER_DELETED,
|
|
76
|
+
payload: { id }
|
|
77
|
+
}), id);
|
|
78
|
+
<%_ } -%>
|
|
79
|
+
return true;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
logger.error(`${ERROR_MESSAGES.DELETE_USER_ERROR}:`, error);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
<% } else { -%>
|
|
86
|
+
async getUsers(req, res, next) {
|
|
87
|
+
try {
|
|
88
|
+
const users = await this.getAllUsersUseCase.execute();
|
|
89
|
+
res.json(users);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.error(`${ERROR_MESSAGES.FETCH_USERS_ERROR}:`, error);
|
|
92
|
+
next(error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async createUser(req, res, next) {
|
|
97
|
+
const { name, email } = req.body || {};
|
|
98
|
+
try {
|
|
99
|
+
const user = await this.createUserUseCase.execute(name, email);
|
|
100
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
101
|
+
await sendMessage('user-topic', JSON.stringify({
|
|
102
|
+
action: KAFKA_ACTIONS.USER_CREATED,
|
|
103
|
+
payload: { id: user.id || user._id, email: user.email }
|
|
104
|
+
}), (user.id || user._id).toString());
|
|
105
|
+
<%_ } -%>
|
|
106
|
+
res.status(HTTP_STATUS.CREATED).json(user);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
logger.error(`${ERROR_MESSAGES.CREATE_USER_ERROR}:`, error);
|
|
109
|
+
next(error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async updateUser(req, res, next) {
|
|
114
|
+
const { id } = req.params;
|
|
115
|
+
const { name, email } = req.body || {};
|
|
116
|
+
try {
|
|
117
|
+
const user = await this.updateUserUseCase.execute(id, { name, email });
|
|
118
|
+
if (!user) {
|
|
119
|
+
return res.status(HTTP_STATUS.NOT_FOUND).json({ error: ERROR_MESSAGES.USER_NOT_FOUND });
|
|
120
|
+
}
|
|
121
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
122
|
+
await sendMessage('user-topic', JSON.stringify({
|
|
123
|
+
action: KAFKA_ACTIONS.USER_UPDATED,
|
|
124
|
+
payload: { id, email: user.email }
|
|
125
|
+
}), id);
|
|
126
|
+
<%_ } -%>
|
|
127
|
+
res.json(user);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
logger.error(`${ERROR_MESSAGES.UPDATE_USER_ERROR}:`, error);
|
|
130
|
+
next(error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async deleteUser(req, res, next) {
|
|
135
|
+
const { id } = req.params;
|
|
136
|
+
try {
|
|
137
|
+
const deleted = await this.deleteUserUseCase.execute(id);
|
|
138
|
+
if (!deleted) {
|
|
139
|
+
return res.status(HTTP_STATUS.NOT_FOUND).json({ error: ERROR_MESSAGES.USER_NOT_FOUND });
|
|
140
|
+
}
|
|
141
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
142
|
+
await sendMessage('user-topic', JSON.stringify({
|
|
143
|
+
action: KAFKA_ACTIONS.USER_DELETED,
|
|
144
|
+
payload: { id }
|
|
145
|
+
}), id);
|
|
146
|
+
<%_ } -%>
|
|
147
|
+
res.status(HTTP_STATUS.OK).json({ message: 'User deleted successfully' });
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logger.error(`${ERROR_MESSAGES.DELETE_USER_ERROR}:`, error);
|
|
150
|
+
next(error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
<% } -%>
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = UserController;
|