Created
November 6, 2020 16:20
-
-
Save musou1500/596adf81aaa79e65e356eb6ea5e634bc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* domain module | |
* UserAggregate | |
* - (Aggregate Root) User | |
* - (Aggregate Root) UserQuota | |
*/ | |
export class User { | |
#organizationId: number; | |
#name: string; | |
constructor(organizationId: number, name: string) { | |
this.#organizationId = organizationId; | |
this.#name = name; | |
} | |
get organizationId() { | |
return this.#organizationId; | |
} | |
get name() { | |
return this.#name; | |
} | |
} | |
export interface UserRepository { | |
save(user: User): Promise<User>; | |
countUserInOrganization(organizationId: number): Promise<number>; | |
} | |
export interface UserQuotaRepository { | |
lock(organizationId: number): Promise<number>; | |
} | |
export class ReachedToUserQuota extends Error { | |
name = "ReachedToUserQuota"; | |
} | |
// domain service to add user | |
export const addUser = async ( | |
userQuotaRepository: UserQuotaRepository, | |
userRepository: UserRepository, | |
user: User | |
): Promise<User> => { | |
const quota = await userQuotaRepository.lock(user.organizationId); | |
const count = await userRepository.countUserInOrganization( | |
user.organizationId | |
); | |
if (count + 1 > quota) { | |
throw new ReachedToUserQuota(); | |
} | |
return userRepository.save(user); | |
}; | |
/** | |
* application module | |
* - AddUserUseCase | |
*/ | |
export interface AddUserRequest { | |
name: string; | |
organizationId: number; | |
} | |
export interface RepositoryFactory { | |
userRepository(): UserRepository; | |
userQuotaRepository(): UserQuotaRepository; | |
} | |
export interface Transaction { | |
run<T>(fn: (factory: RepositoryFactory) => Promise<T>): Promise<T>; | |
} | |
export class AddUserUseCase { | |
#transaction: Transaction; | |
constructor(transaction: Transaction) { | |
this.#transaction = transaction; | |
} | |
addUser({ name, organizationId }: AddUserRequest): Promise<User> { | |
return this.#transaction.run(({ userRepository, userQuotaRepository }) => | |
addUser( | |
userQuotaRepository(), | |
userRepository(), | |
new User(organizationId, name) | |
) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment