From a0020b30fc149139c811e7010c31a65a54fce979 Mon Sep 17 00:00:00 2001 From: Salsedini Date: Wed, 22 Nov 2023 17:14:36 +0100 Subject: [PATCH] feat: createBook feature --- .../book/application/create-book.use-case.ts | 23 ++++++++++++ .../book/application/find-books.use-case.ts | 4 +- .../book/domain/model/author.value-object.ts | 14 +++++++ src/core/book/domain/model/book.entity.ts | 37 ++++++++++--------- .../model/{book_Id.ts => id.value-object.ts} | 2 +- .../book/domain/model/image.value-object.ts | 8 ++-- .../{book_title.ts => title.value-object.ts} | 2 +- .../book/domain/model/tittle.value-object.ts | 13 ------- .../book/domain/services/book.repository.ts | 9 ----- .../book/domain/services/books.repository.ts | 10 ++++- src/core/book/infraestructure/actions.ts | 13 ------- src/core/book/infrastructure/actions.ts | 14 ++++++- .../services/books-in-memory.retository.ts | 30 +++++++++++---- src/lib/container/container.ts | 2 + 14 files changed, 110 insertions(+), 71 deletions(-) create mode 100644 src/core/book/application/create-book.use-case.ts create mode 100644 src/core/book/domain/model/author.value-object.ts rename src/core/book/domain/model/{book_Id.ts => id.value-object.ts} (82%) rename src/core/book/domain/model/{book_title.ts => title.value-object.ts} (84%) delete mode 100644 src/core/book/domain/model/tittle.value-object.ts delete mode 100644 src/core/book/domain/services/book.repository.ts delete mode 100644 src/core/book/infraestructure/actions.ts diff --git a/src/core/book/application/create-book.use-case.ts b/src/core/book/application/create-book.use-case.ts new file mode 100644 index 0000000..762ddd3 --- /dev/null +++ b/src/core/book/application/create-book.use-case.ts @@ -0,0 +1,23 @@ +import Book from '../domain/model/book.entity' +import BookId from '../domain/model/id.value-object' +import Books from '../domain/services/books.repository' +import { CreateBookCommand } from './types' + +export default class CreateBookUseCase { + constructor(private readonly bookRepository: Books) {} + + async with(command: CreateBookCommand): Promise { + if ( + !(this.bookRepository.findById(BookId.create(command.id)) instanceof Book) + ) { + throw Error('This book already exists') + } + const book: Book = Book.create( + command.id, + command.authors, + command.title, + command.image, + ) + this.bookRepository.save(book) + } +} diff --git a/src/core/book/application/find-books.use-case.ts b/src/core/book/application/find-books.use-case.ts index f609c09..73a796a 100644 --- a/src/core/book/application/find-books.use-case.ts +++ b/src/core/book/application/find-books.use-case.ts @@ -1,4 +1,4 @@ -import Books from '@/core/book/domain/services/book.repository' +import Books from '@/core/book/domain/services/books.repository' import { FindBookResponse } from './types' @@ -12,7 +12,7 @@ export default class FindBooksUseCase { authors: book.authors, id: book.id, image: book.image, - title: book.tittle, + title: book.title, })) } } diff --git a/src/core/book/domain/model/author.value-object.ts b/src/core/book/domain/model/author.value-object.ts new file mode 100644 index 0000000..1da206d --- /dev/null +++ b/src/core/book/domain/model/author.value-object.ts @@ -0,0 +1,14 @@ +export class BookAuthor { + constructor(public readonly value: string) {} + + public static create(author: string): BookAuthor { + if (author === undefined) { + throw Error('Author can not be undefined') + } + if (author.length < 3) { + throw Error('Author is too short') + } + + return new BookAuthor(author) + } +} diff --git a/src/core/book/domain/model/book.entity.ts b/src/core/book/domain/model/book.entity.ts index 53fa60b..30211dd 100644 --- a/src/core/book/domain/model/book.entity.ts +++ b/src/core/book/domain/model/book.entity.ts @@ -1,40 +1,41 @@ -import Image from '@/core/book/domain/model/image.value-object' -import Tittle from '@/core/book/domain/model/tittle.value-object' +import BookImage from '@/core/book/domain/model/image.value-object' + +import { BookAuthor } from './author.value-object' +import BookId from './id.value-object' +import { BookTitle } from './title.value-object' export default class Book { constructor( - private _id: string, - private _tittle: Tittle, - private _authors: string[], - private _image: Image, + private _id: BookId, + private _title: BookTitle, + private _authors: BookAuthor[], + private _image: BookImage, ) {} static create( id: string, authors: string[], - tittle: string, + title: string, image: string, ): Book { - const tittleObj = Tittle.create(tittle) - const imageObj = Image.create(image) + const idObj = BookId.create(id) + const titleObj = BookTitle.create(title) + const imageObj = BookImage.create(image) + const authorObj = authors.map((item) => BookAuthor.create(item)) - return new Book(id, tittleObj, authors, imageObj) + return new Book(idObj, titleObj, authorObj, imageObj) } get id(): string { - return this._id - } - - get tittle(): string { - return this._tittle.value + return this._id.value } - set tittle(tittle: string) { - this._tittle = Tittle.create(tittle) + get title(): string { + return this._title.value } get authors(): string[] { - return this._authors.map((author) => author) + return this._authors.map((author) => author.value) } get image(): string { diff --git a/src/core/book/domain/model/book_Id.ts b/src/core/book/domain/model/id.value-object.ts similarity index 82% rename from src/core/book/domain/model/book_Id.ts rename to src/core/book/domain/model/id.value-object.ts index 9c7a9d5..5bc4268 100644 --- a/src/core/book/domain/model/book_Id.ts +++ b/src/core/book/domain/model/id.value-object.ts @@ -7,7 +7,7 @@ export default class BookId { return new BookId(uuid()) } - public static with(id: string): BookId { + public static create(id: string): BookId { return new BookId(id) } } diff --git a/src/core/book/domain/model/image.value-object.ts b/src/core/book/domain/model/image.value-object.ts index 68303c6..d48a41d 100644 --- a/src/core/book/domain/model/image.value-object.ts +++ b/src/core/book/domain/model/image.value-object.ts @@ -1,9 +1,9 @@ -export default class Image { +export default class BookImage { constructor(public readonly value: string) {} - static create(name: string): Image { + static create(name: string): BookImage { if (!name.trim()) { - return new Image('') + return new BookImage('') } try { @@ -12,6 +12,6 @@ export default class Image { throw new Error('Invalid URL') } - return new Image(name) + return new BookImage(name) } } diff --git a/src/core/book/domain/model/book_title.ts b/src/core/book/domain/model/title.value-object.ts similarity index 84% rename from src/core/book/domain/model/book_title.ts rename to src/core/book/domain/model/title.value-object.ts index 8ac6a14..e598003 100644 --- a/src/core/book/domain/model/book_title.ts +++ b/src/core/book/domain/model/title.value-object.ts @@ -1,7 +1,7 @@ export class BookTitle { constructor(public readonly value: string) {} - public static with(title: string): BookTitle { + public static create(title: string): BookTitle { if (title === undefined) { throw Error('Title can not be undefined') } diff --git a/src/core/book/domain/model/tittle.value-object.ts b/src/core/book/domain/model/tittle.value-object.ts deleted file mode 100644 index 4e86967..0000000 --- a/src/core/book/domain/model/tittle.value-object.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default class Name { - constructor(public readonly value: string) {} - - static create(name: string): Name { - const trimmedName = name.trim() - - if (!trimmedName) { - throw new Error('Name cannot be empty') - } - - return new Name(trimmedName) - } -} diff --git a/src/core/book/domain/services/book.repository.ts b/src/core/book/domain/services/book.repository.ts deleted file mode 100644 index ec5685b..0000000 --- a/src/core/book/domain/services/book.repository.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Book from '@/core/book/domain/model/book.entity' - -export default interface Books { - // Finds a user by email - findAll(): Promise - - // Saves a user - save(user: Book): Promise -} diff --git a/src/core/book/domain/services/books.repository.ts b/src/core/book/domain/services/books.repository.ts index 8d1216a..d54313e 100644 --- a/src/core/book/domain/services/books.repository.ts +++ b/src/core/book/domain/services/books.repository.ts @@ -1,4 +1,10 @@ +import Book from '@/core/book/domain/model/book.entity' + +import BookId from '../model/id.value-object' + export default interface Books { - // Saves a user - //save(book: Book): Promise + // Finds a user by email + findAll(): Promise + findById(id: BookId): Promise + save(book: Book): Promise } diff --git a/src/core/book/infraestructure/actions.ts b/src/core/book/infraestructure/actions.ts deleted file mode 100644 index fe42706..0000000 --- a/src/core/book/infraestructure/actions.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* -export async function createBook( - title:string, - authors:string[], - image:string, - ): -Promise{ - - const id = BookId.generate(); - const result = await container.createBook.with(new CreateBookCommand(id.value,title,authors,image)); - -} -*/ diff --git a/src/core/book/infrastructure/actions.ts b/src/core/book/infrastructure/actions.ts index f01103c..1cca700 100644 --- a/src/core/book/infrastructure/actions.ts +++ b/src/core/book/infrastructure/actions.ts @@ -1,7 +1,19 @@ import container from '@/lib/container' - +import { CreateBookCommand } from '../application/types' +import BookId from '../domain/model/id.value-object' import { FindBookResponse } from '../application/types' export async function findBooks(): Promise { return container.findBooks.with() } + +export async function createBook( + title: string, + authors: string[], + image: string, +): Promise { + const id = BookId.generate() + await container.createBook.with( + new CreateBookCommand(id.value, title, authors, image), + ) +} diff --git a/src/core/book/infrastructure/services/books-in-memory.retository.ts b/src/core/book/infrastructure/services/books-in-memory.retository.ts index 0e01b97..b7baff4 100644 --- a/src/core/book/infrastructure/services/books-in-memory.retository.ts +++ b/src/core/book/infrastructure/services/books-in-memory.retository.ts @@ -1,8 +1,11 @@ import Book from '../../domain/model/book.entity' -import Books from '../../domain/services/book.repository' +import BookId from '../../domain/model/id.value-object' +import Books from '../../domain/services/books.repository' export default class BooksInMemory implements Books { - async findAll(): Promise { + private books: Map = new Map(); + + constructor(){ const booksRaw = [ { authors: ['Donald Knuth'], @@ -76,11 +79,24 @@ export default class BooksInMemory implements Books { }, ] - return await booksRaw.map((book) => - Book.create(book.id, book.authors, book.title, book.image), - ) + booksRaw.map((book) => + this.books.set(book.id, Book.create(book.id, book.authors, book.title, book.image)) + )} + + async findById(id: BookId): Promise { + const book = this.books.get(id.value); + return (book ) ? book : null; } - save(book: Book): Promise { - throw new Error('Method not implemented.' + book.tittle) + + async findAll(): Promise { + return Array.from(this.books.values()) + } + + async save(book: Book): Promise { + this.books.set(book.id, book) + } + + purge(): void { + this.books = new Map() } } diff --git a/src/lib/container/container.ts b/src/lib/container/container.ts index 736d231..988aa61 100644 --- a/src/lib/container/container.ts +++ b/src/lib/container/container.ts @@ -1,3 +1,4 @@ +import CreateBookUseCase from '@/core/book/application/create-book.use-case' import FindBooksUseCase from '@/core/book/application/find-books.use-case' import BooksInMemory from '@/core/book/infrastructure/services/books-in-memory.retository' import FindUserUseCase from '@/core/user/application/find-user.use-case' @@ -11,6 +12,7 @@ const Container = { const books = new BooksInMemory() return { findBooks: new FindBooksUseCase(books), + createBook: new CreateBookUseCase(books), findUser: new FindUserUseCase(users), updateUser: new UpdateUserUseCase(users), }