Advertisement
Guest User

Untitled

a guest
Jun 20th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.14 KB | None | 0 0
  1. /*
  2. * By designing the Customer as an Aggregate Root and including a reference all of the
  3. * movies that it rented, we can place the validation logic for renting movies
  4. * directly on the customer entity.
  5. *
  6. * Advantages: More declarative-reading code. The operation is a lot closer to the
  7. * entity itself, which improves the discoverability and understanding what a customer
  8. * can do.
  9. *
  10. * Disadvantages: Additional overhead. Having to pull the ids of rented movie everytime we
  11. * retrieve a customer might become cumbersome + slow down performance depending on the use cases.
  12. */
  13.  
  14. interface ICustomerProps {
  15. name: string;
  16. rentedMovies: MovieId[]; // one way reference to movie ids
  17. }
  18.  
  19. class Customer extends AggregateRoot<ICustomerProps> {
  20. private constructor (props: ICustomerProps, id?: UniqueEntityId) {
  21. super(props, id)
  22. }
  23.  
  24. public static create (props: ICustomerProps, id?: UniqueEntityId): Result<Customer> {
  25. // make all invariants are satisfied
  26. }
  27.  
  28. public rentMovie (movie: Movie): Result<Customer> {
  29. // if this.rentedMovies is larger than the max amount of movies, then
  30. // this operation should fail
  31. }
  32. }
  33.  
  34. /*
  35. * Another design: using Domain Services / Use Cases
  36. *
  37. * Advantages: Probably a better design if performance becomes a problem. Domain Services are a good
  38. * place to put domain logic that doesn't belong to one particular entity.
  39. *
  40. * Disadvantages:
  41. */
  42.  
  43. class RentMovieUseCase {
  44. private rentalRepo: IrentalRepo;
  45.  
  46. constructor (rentalRepo: IrentalRepo) {
  47. this.rentalRepo = rentalRepo;
  48. }
  49.  
  50. public async exec (customer: Customer, movie: Movie): Result<Rental> {
  51. const { movieRepo } = this;
  52. const rentedMovies: Rental[] = await rentalRepo.getRentalsByCustomerId(customer.id);
  53. if (rentedMovies.length > MAX_NUM_MOVIES_TO_RENT) {
  54. return Result.fail<Rental>('Customer rented the max amount of movies')
  55. } else {
  56. return Rental.create({ customerId: customer.id, movieId: movie.id });
  57. }
  58. }
  59. }
  60.  
  61. // Using the domain service, the controller might look more like
  62.  
  63. class MovieController extends BaseController {
  64. private movieRepo: IMovieRepo;
  65. private customerRepo: ICustomerRepo;
  66. private rentalRepo: IRentalRepo;
  67.  
  68. constructor (movieRepo: IMovieRepo, customerRepo: ICustomerRepo, rentalRepo: IRentalRepo) {
  69. super();
  70. this.movieRepo = movieRepo;
  71. this.customerRepo = customerRepo;
  72. this.rentalRepo = rentalRepo;
  73. }
  74.  
  75. public async rentMovie () {
  76. const { req, movieRepo, customerRepo, rentalRepo } = this;
  77. const { movieId } = req.params['movie'];
  78. const { customerId } = req.params['customer'];
  79.  
  80. const movie: Movie = await movieRepo.findById(movieId);
  81. const customer: Customer = await customerRepo.findById(customerId);
  82.  
  83. if (!!movie === false) {
  84. return this.fail('Movie not found')
  85. }
  86.  
  87. if (!!customer === false) {
  88. return this.fail('Customer not found')
  89. }
  90.  
  91. const rentMovieResult: Result<Rental> = new RentMovieUseCase(this.rentalRepo).exec(customer, movie)
  92.  
  93. if (rentMovieResult.isFailure) {
  94. return this.fail(rentMovieResult.error)
  95. } else {
  96. const rental = rentMovieResult.getValue();
  97. await rentalRepo.save(rental);
  98. return this.ok();
  99. }
  100. }
  101. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement