Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7ba8cde

Browse files
wjanaszekSikora00
authored andcommitted
feat: check out book
1 parentbe8b306 commit7ba8cde

File tree

9 files changed

+202
-0
lines changed

9 files changed

+202
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import{BookId,PatronId}from'@library/lending/domain';
2+
import{Result}from'@library/shared/domain';
3+
import{Command}from'@nestjs-architects/typed-cqrs';
4+
5+
exportclassCheckOutBookCommandextendsCommand<Result>{
6+
constructor(
7+
publicreadonlypatronId:PatronId,
8+
publicreadonlybookId:BookId
9+
){
10+
super();
11+
}
12+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import{BookRepository,PatronRepository}from'@library/lending/application';
2+
import{
3+
Book,
4+
BookCheckedOut,
5+
BookCheckOutFailed,
6+
BookId,
7+
Patron,
8+
PatronId,
9+
}from'@library/lending/domain';
10+
import{InvalidArgumentException,Result}from'@library/shared/domain';
11+
import{IInferredCommandHandler}from'@nestjs-architects/typed-cqrs';
12+
import{CommandHandler}from'@nestjs/cqrs';
13+
import{match}from'fp-ts/Either';
14+
import{pipe}from'fp-ts/function';
15+
import{getOrElseW}from'fp-ts/Option';
16+
import{CheckOutBookCommand}from'./check-out-book.command';
17+
18+
@CommandHandler(CheckOutBookCommand)
19+
exportclassCheckOutBookHandler
20+
implementsIInferredCommandHandler<CheckOutBookCommand>
21+
{
22+
constructor(
23+
privatereadonlybookRepository:BookRepository,
24+
privatereadonlypatronRepository:PatronRepository
25+
){}
26+
27+
asyncexecute(command:CheckOutBookCommand):Promise<Result>{
28+
constbook=awaitthis.findBook(command.bookId);
29+
constpatron=awaitthis.findPatron(command.patronId);
30+
constresult=patron.checkoutBook(book);
31+
returnpipe(
32+
result,
33+
match<BookCheckOutFailed,BookCheckedOut,Promise<Result>>(
34+
this.publishOnFail.bind(this),
35+
this.publishOnSuccess.bind(this)
36+
)
37+
);
38+
}
39+
40+
privatefindBook(id:BookId):Promise<Book>{
41+
returnthis.bookRepository.findById(id).then((result)=>
42+
pipe(
43+
result,
44+
getOrElseW(()=>{
45+
thrownewInvalidArgumentException(
46+
`Cannot find available book with Id:${id}`
47+
);
48+
})
49+
)
50+
);
51+
}
52+
53+
privatefindPatron(patronId:PatronId):Promise<Patron>{
54+
returnthis.patronRepository.findById(patronId).then((result)=>
55+
pipe(
56+
result,
57+
getOrElseW(()=>{
58+
thrownewInvalidArgumentException(
59+
`Patron with given Id does not exists:${patronId}`
60+
);
61+
})
62+
)
63+
);
64+
}
65+
66+
privateasyncpublishOnFail(
67+
bookCheckOutFailed:BookCheckOutFailed
68+
):Promise<Result.Rejection>{
69+
awaitthis.patronRepository.publish(bookCheckOutFailed);
70+
71+
returnResult.Rejection;
72+
}
73+
74+
privateasyncpublishOnSuccess(
75+
bookCheckedOut:BookCheckedOut
76+
):Promise<Result.Success>{
77+
awaitthis.patronRepository.publish(bookCheckedOut);
78+
79+
returnResult.Success;
80+
}
81+
}

‎libs/lending/application/src/lib/lending-application.module.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DynamicModule, Module, ModuleMetadata } from '@nestjs/common';
22
import{CqrsModule}from'@nestjs/cqrs';
33
import{BookPlacedOnHoldEventHandler}from'./book-placed-on-hold.event-handler';
44
import{CancelHoldHandler}from'./cancel-hold/cancel-hold.handler';
5+
import{CheckOutBookHandler}from'./check-out/check-out-book.handler';
56
import{LendingFacade}from'./lending.facade';
67
import{PlaceOnHoldHandler}from'./place-on-hold/place-on-hold.handler';
78
import{DuplicateHoldEventHandler}from'./duplicate-hold.event.handler';
@@ -14,6 +15,7 @@ import { CreateAvailableBookOnInstanceAddedEventHandler } from './create-availab
1415
BookHoldCanceledEventHandler,
1516
BookPlacedOnHoldEventHandler,
1617
CancelHoldHandler,
18+
CheckOutBookHandler,
1719
CreateAvailableBookOnInstanceAddedEventHandler,
1820
DuplicateHoldEventHandler,
1921
LendingFacade,

‎libs/lending/domain/src/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export * from './lib/book/available-book';
22
export*from'./lib/book/book';
33
export*from'./lib/book/book-on-hold';
44
export*from'./lib/book/book-duplicate-hold-found.event';
5+
export*from'./lib/events/book-check-out-failed';
6+
export*from'./lib/events/book-checked-out';
57
export*from'./lib/events/book-hold-canceled';
68
export*from'./lib/events/book-hold-canceling-failed';
79
export*from'./lib/events/book-hold-failed';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import{PatronId}from'../value-objects/patron-id';
2+
import{Rejection}from'../policies/placing-on-hold-policy';
3+
import{PatronEvent}from'./patron-event';
4+
5+
exportclassBookCheckOutFailedimplementsPatronEvent{
6+
privateconstructor(
7+
publicreadonlyreason:string,
8+
publicreadonlypatronId:PatronId
9+
){}
10+
11+
staticbookCheckOutFailedBecause(
12+
rejection:Rejection,
13+
patronId:PatronId
14+
):BookCheckOutFailed{
15+
returnnewBookCheckOutFailed(rejection.reason,patronId);
16+
}
17+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import{PatronId}from'../value-objects/patron-id';
2+
import{PatronEvent}from'./patron-event';
3+
4+
exportclassBookCheckedOutimplementsPatronEvent{
5+
constructor(publicreadonlypatronId:PatronId){}
6+
}

‎libs/lending/domain/src/lib/factories/patron.factory.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import{Patron}from'../patron';
2+
import{allCheckingOutPolicies}from'../policies/checking-out.policy';
23
import{allCurrentPolicies}from'../policies/placing-on-hold-policy';
34
import{BookId}from'../value-objects/book-id';
45
import{Hold}from'../value-objects/hold';
@@ -15,6 +16,7 @@ export class PatronFactory {
1516
patronHolds:Set<[BookId,LibraryBranchId]>
1617
):Patron{
1718
returnnewPatron(
19+
allCheckingOutPolicies,
1820
newPatronHolds(
1921
newSet(
2022
[...patronHolds].map(

‎libs/lending/domain/src/lib/patron.ts‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import{Either,isLeft,left,right}from'fp-ts/lib/Either';
22
import{getLeft,isNone,none,Option}from'fp-ts/lib/Option';
33
import{AvailableBook}from'./book/available-book';
4+
import{Book}from'./book/book';
45
import{BookOnHold}from'./book/book-on-hold';
6+
import{BookCheckOutFailed}from'./events/book-check-out-failed';
7+
import{BookCheckedOut}from'./events/book-checked-out';
58
import{BookHoldCancelingFailed}from'./events/book-hold-canceled';
69
import{BookHoldCanceled}from'./events/book-hold-canceling-failed';
710
import{BookHoldFailed}from'./events/book-hold-failed';
811
import{BookPlacedOnHold}from'./events/book-placed-on-hold';
912
import{BookPlacedOnHoldEvents}from'./events/book-placed-on-hold-events';
1013
import{MaximumNumberOhHoldsReached}from'./events/maximum-number-on-holds-reached';
14+
import{CheckingOutPolicy}from'./policies/checking-out.policy';
1115
import{
1216
PlacingOnHoldPolicy,
1317
Rejection,
@@ -18,6 +22,7 @@ import { PatronInformation } from './value-objects/patron-information';
1822

1923
exportclassPatron{
2024
constructor(
25+
privatereadonlycheckingOutPolicies:Set<CheckingOutPolicy>,
2126
privatereadonlypatronHolds:PatronHolds,
2227
privatereadonlyplacingOnHoldPolicies:Set<PlacingOnHoldPolicy>,
2328
privatereadonlypatronInformation:PatronInformation
@@ -38,6 +43,30 @@ export class Patron {
3843
returnleft(newBookHoldCancelingFailed(this.patronInformation.patronId));
3944
}
4045

46+
checkoutBook(
47+
book:Book
48+
):Either<BookCheckOutFailed,BookCheckedOut>{
49+
constrejection=this.patronCanCheckout(book);
50+
51+
if(!isNone(rejection)){
52+
returnleft(
53+
BookCheckOutFailed.bookCheckOutFailedBecause(
54+
rejection.value,
55+
this.patronInformation.patronId
56+
)
57+
);
58+
}
59+
60+
returnright(newBookCheckedOut(this.patronInformation.patronId));
61+
}
62+
63+
privatepatronCanCheckout(book:Book):Option<Rejection>{
64+
constrejection=[...this.checkingOutPolicies]
65+
.map((policy)=>policy(book,this.patronInformation.patronId))
66+
.find(isLeft);
67+
returnrejection ?getLeft(rejection) :none;
68+
}
69+
4170
isRegular():boolean{
4271
returnthis.patronInformation.isRegular();
4372
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import{Either,left,right}from'fp-ts/Either';
2+
import{Book}from'../book/book';
3+
import{BookOnHold}from'../book/book-on-hold';
4+
import{PatronId}from'../value-objects/patron-id';
5+
6+
exportinterfaceCheckingOutPolicy{
7+
(book:Book,patronId:PatronId):Either<Rejection,Allowance>;
8+
}
9+
10+
exportconstbookIsOnHold:CheckingOutPolicy=(
11+
toCheckout:Book,
12+
_:PatronId
13+
)=>{
14+
if(!(toCheckoutinstanceofBookOnHold)){
15+
returnleft(
16+
Rejection.withReason(
17+
'Cannot checkout book which is not on hold'
18+
)
19+
);
20+
}
21+
returnright(newAllowance());
22+
};
23+
24+
exportconstbookIsOnHoldByThePatron:CheckingOutPolicy=(
25+
toCheckout:Book,
26+
patronId:PatronId
27+
)=>{
28+
if(toCheckoutinstanceofBookOnHold&&!toCheckout.by(patronId)){
29+
returnleft(
30+
Rejection.withReason(
31+
'Cannot checkout book which is on hold by different patron'
32+
)
33+
);
34+
}
35+
returnright(newAllowance());
36+
};
37+
38+
exportconstallCheckingOutPolicies:Set<CheckingOutPolicy>=newSet([
39+
bookIsOnHold,
40+
bookIsOnHoldByThePatron,
41+
]);
42+
43+
exportclassAllowance{}
44+
45+
exportclassRejection{
46+
privateconstructor(publicreadonlyreason:string){}
47+
48+
staticwithReason(reason:string):Rejection{
49+
returnnewRejection(reason);
50+
}
51+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp