diff --git a/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingAggregate.kt b/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingAggregate.kt index 93ba013..a7dd011 100644 --- a/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingAggregate.kt +++ b/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingAggregate.kt @@ -19,10 +19,12 @@ class BorrowingAggregate() { @AggregateIdentifier lateinit var borrowing: UUID + var copyState = CopyState.AVAILABLE + var borrower: Party? = null @CommandHandler constructor(command: RegisterNewBorrowing): this() { - applyEvent(RegisteredNewBorrowing(command.isbn, UUID.randomUUID())) + applyEvent(RegisteredNewBorrowing(command.isbn, UUID.randomUUID(), command.userId)) } @CommandHandler @@ -51,14 +53,18 @@ class BorrowingAggregate() { this.copyState = CopyState.AVAILABLE this.borrower = null } - var copyState = CopyState.AVAILABLE - var borrower: Party? = null + + @EventSourcingHandler + fun on(evt: RegisteredNewBorrowing) { + this.borrowing = evt.uuid + } + } data class FindBorrowings (val isbn: String) -data class RegisterNewBorrowing (val isbn: String) -data class RegisteredNewBorrowing (val isbn: String, val uuid: UUID) +data class RegisterNewBorrowing (val isbn: String, val userId: UUID) +data class RegisteredNewBorrowing (val isbn: String, val uuid: UUID, val userId: UUID) data class BorrowCopy(@TargetAggregateIdentifier val copyId: UUID, val borrower: Party) data class ReturnCopy(@TargetAggregateIdentifier val copyId: UUID, val borrower: Party) diff --git a/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingController.kt b/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingController.kt index fbb8c91..06d7d9e 100644 --- a/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingController.kt +++ b/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingController.kt @@ -7,11 +7,13 @@ import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.server.ResponseStatusException import java.util.* @RestController +@RequestMapping(path = ["/api"]) class BorrowingController( val commandGateway: CommandGateway ) { diff --git a/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingReadModel.kt b/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingReadModel.kt index dc69071..a32e4ec 100644 --- a/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingReadModel.kt +++ b/backend/src/main/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowingReadModel.kt @@ -1,6 +1,8 @@ package com.ksidelta.libruch.modules.borrowing; +import com.ksidelta.libruch.modules.example.BookState import org.axonframework.eventhandling.EventHandler +import org.axonframework.queryhandling.QueryHandler import org.springframework.data.repository.CrudRepository import org.springframework.stereotype.Repository import org.springframework.stereotype.Service @@ -9,25 +11,58 @@ import javax.persistence.Entity import javax.persistence.Id @Service -class BorrowingEventProcessor(val borrowingReadModelRepository: BorrowingReadModelRepository) { +class BorrowingEventProcessor( + val borrowingReadModelRepository: BorrowingReadModelRepository, + val borrowingCopyReadModelRepository: BorrowingCopyReadModelRepository +) { @EventHandler - fun handle(event: RegisteredNewBorrowing) = + fun handle(event: RegisteredNewBorrowing) { + borrowingReadModelRepository.save( BorrowingOfferModel( - id = event.uuid, + id = event.uuid, isbn = event.isbn ) ) + + borrowingCopyReadModelRepository.save(BorrowingCopyModel( + id = event.uuid, + isbn = event.isbn, + status = BookState.BORROWED, + userId = event.userId + + )) + } + + @QueryHandler + fun queryBorrowedBooks(event: QueryBorrowedBooks): List = + borrowingCopyReadModelRepository.findByUserId(event.userUUID) } +data class QueryBorrowedBooks(val userUUID: UUID) + @Repository interface BorrowingReadModelRepository : CrudRepository { fun findByIsbn(isbn: String): BorrowingOfferModel? } +@Repository +interface BorrowingCopyReadModelRepository : CrudRepository { + fun findByUserId(userUUID: UUID): List +} + @Entity(name = "borrowing_offer_model") data class BorrowingOfferModel( @Id val id: UUID, val isbn: String ) + +@Entity(name = "borrowed_copy_model") +data class BorrowingCopyModel( + @Id + val id: UUID, + val isbn: String, + val status: BookState, + val userId: UUID +) diff --git a/backend/src/test/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowBookUseCase.kt b/backend/src/test/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowBookUseCase.kt new file mode 100644 index 0000000..fa9eef0 --- /dev/null +++ b/backend/src/test/kotlin/com/ksidelta/libruch/modules/borrowing/BorrowBookUseCase.kt @@ -0,0 +1,65 @@ +package com.ksidelta.libruch.modules.borrowing + +import com.ksidelta.libruch.BaseTest +import com.ksidelta.libruch.MockUserArgumentResolver +import com.ksidelta.libruch.modules.example.BookState +import com.ksidelta.libruch.utils.eventuallyConfigured +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.future.await +import kotlinx.coroutines.runBlocking +import org.axonframework.commandhandling.gateway.CommandGateway +import org.axonframework.messaging.responsetypes.ResponseTypes +import org.axonframework.queryhandling.QueryGateway +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.web.client.TestRestTemplate +import java.util.* + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class BorrowBookUseCase : BaseTest() { + + @Autowired + lateinit var testRestTemplate: TestRestTemplate + + @Autowired + lateinit var gateway: CommandGateway + + @Autowired + lateinit var queryGateway: QueryGateway + + @Autowired + lateinit var mockUserArgumentResolver : MockUserArgumentResolver; + + final val isbnConstant = "1234" + @Test + fun test() = runBlocking { + val newBorrowingCompletableFuture = gateway.send(RegisterNewBorrowing(isbnConstant)); + val uuid = newBorrowingCompletableFuture.await() + testRestTemplate.postForEntity("/api/borrow", BorrowCopyDTO(uuid), Void::class.java) + Assertions.assertTrue(true) + + val userUUID = mockUserArgumentResolver.user.id + val query = suspend { + queryGateway.query( + QueryBorrowedBooks(userUUID), + ResponseTypes.multipleInstancesOf(BorrowingCopyModel::class.java) + ).await() + } + + eventuallyConfigured { + query() shouldBe + listOf( + BorrowingCopyModel( + status = BookState.BORROWED, + id = uuid, + isbn = isbnConstant, + userId = userUUID + ) + ) + } + + + } +} \ No newline at end of file