forked from Sairyss/domain-driven-hexagon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
user.entity.ts
98 lines (86 loc) · 2.94 KB
/
user.entity.ts
1
2
3
4
5
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { AggregateRoot, AggregateID } from '@libs/ddd';
import { UserCreatedDomainEvent } from './events/user-created.domain-event';
import { Address, AddressProps } from './value-objects/address.value-object';
import {
CreateUserProps,
UpdateUserAddressProps,
UserProps,
UserRoles,
} from './user.types';
import { UserDeletedDomainEvent } from './events/user-deleted.domain-event';
import { UserRoleChangedDomainEvent } from './events/user-role-changed.domain-event';
import { UserAddressUpdatedDomainEvent } from './events/user-address-updated.domain-event';
import { randomUUID } from 'crypto';
export class UserEntity extends AggregateRoot<UserProps> {
protected readonly _id: AggregateID;
static create(create: CreateUserProps): UserEntity {
const id = randomUUID();
/* Setting a default role since we are not accepting it during creation. */
const props: UserProps = { ...create, role: UserRoles.guest };
const user = new UserEntity({ id, props });
/* adding "UserCreated" Domain Event that will be published
eventually so an event handler somewhere may receive it and do an
appropriate action. Multiple events can be added if needed. */
user.addEvent(
new UserCreatedDomainEvent({
aggregateId: id,
email: props.email,
...props.address.unpack(),
}),
);
return user;
}
/* You can create getters only for the properties that you need to
access and leave the rest of the properties private to keep entity
encapsulated. To get all entity properties (for saving it to a
database or mapping a response) use .getProps() method
defined in a EntityBase parent class */
get role(): UserRoles {
return this.props.role;
}
private changeRole(newRole: UserRoles): void {
this.addEvent(
new UserRoleChangedDomainEvent({
aggregateId: this.id,
oldRole: this.props.role,
newRole,
}),
);
this.props.role = newRole;
}
makeAdmin(): void {
this.changeRole(UserRoles.admin);
}
makeModerator(): void {
this.changeRole(UserRoles.moderator);
}
delete(): void {
this.addEvent(
new UserDeletedDomainEvent({
aggregateId: this.id,
}),
);
}
/* Update method only changes properties that we allow, in this
case only address. This prevents from illegal actions,
for example setting email from outside by doing something
like user.email = otherEmail */
updateAddress(props: UpdateUserAddressProps): void {
const newAddress = new Address({
...this.props.address,
...props,
} as AddressProps);
this.props.address = newAddress;
this.addEvent(
new UserAddressUpdatedDomainEvent({
aggregateId: this.id,
country: newAddress.country,
street: newAddress.street,
postalCode: newAddress.postalCode,
}),
);
}
validate(): void {
// entity business rules validation to protect it's invariant before saving entity to a database
}
}