Skip to content

Commit d771130

Browse files
committed
Add book deleter
1 parent 28ba17c commit d771130

12 files changed

+270
-1
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
## Sample project to validate the [REL lib](https://fs02.github.io/rel/#/) as database layer
22

3-
This project implements a book library with four operations:
3+
This project implements a book library with five operations:
44

55
- POST /books (Insert a new book on the library)
66
- GET /books/{bookID} (Get a book by your ID on the library)
77
- PUT /books/{bookID} (Update a book on the library)
8+
- DELETE /books/{bookID} (Delete a book on the library)
89
- GET /books (Get all books on the library)
910

1011
## How to run

books/bookdeleter/bookdeleter.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//go:generate mockery -name=Finder
2+
//go:generate mockery -name=Deleter
3+
4+
package bookdeleter
5+
6+
import (
7+
"context"
8+
9+
"github.com/rafaelhl/library-rel-lib/books"
10+
)
11+
12+
type (
13+
Finder interface {
14+
FindBookByID(ctx context.Context, bookID int) (books.Book, error)
15+
}
16+
17+
Deleter interface {
18+
DeleteBook(ctx context.Context, book books.Book) error
19+
}
20+
21+
BookDeleter struct {
22+
finder Finder
23+
deleter Deleter
24+
}
25+
)
26+
27+
func New(finder Finder, deleter Deleter) BookDeleter {
28+
return BookDeleter{
29+
finder: finder,
30+
deleter: deleter,
31+
}
32+
}
33+
34+
func (d BookDeleter) DeleteBook(ctx context.Context, id int) error {
35+
book, err := d.finder.FindBookByID(ctx, id)
36+
if err != nil || book.ID == 0 {
37+
return err
38+
}
39+
40+
return d.deleter.DeleteBook(ctx, book)
41+
}

books/bookdeleter/bookdeleter_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package bookdeleter_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/mock"
9+
10+
"github.com/rafaelhl/library-rel-lib/books"
11+
"github.com/rafaelhl/library-rel-lib/books/bookdeleter"
12+
"github.com/rafaelhl/library-rel-lib/books/bookdeleter/mocks"
13+
)
14+
15+
func TestBookDeleter_DeleteBook(t *testing.T) {
16+
finder := new(mocks.Finder)
17+
book := books.Book{
18+
ID: 1,
19+
Title: "Deleting a book",
20+
Author: "Test",
21+
Description: "Book of test delete",
22+
Edition: 1,
23+
ShelfID: 1,
24+
}
25+
finder.On("FindBookByID", mock.Anything, 1).Return(book, nil)
26+
deleter := new(mocks.Deleter)
27+
deleter.On("DeleteBook", mock.Anything, book).Return(nil)
28+
d := bookdeleter.New(finder, deleter)
29+
30+
err := d.DeleteBook(context.Background(), 1)
31+
assert.NoError(t, err)
32+
}

books/bookdeleter/mocks/Deleter.go

+30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

books/bookdeleter/mocks/Finder.go

+37
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

books/entities.go

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type (
1414
ShelfID int `db:"shelf_id" json:"-"`
1515
CreatedAt time.Time `json:"-"`
1616
UpdatedAt time.Time `json:"-"`
17+
DeletedAt time.Time `json:"-"`
1718
BookShelf Shelf `json:"shelf" ref:"shelf_id" fk:"id"`
1819
}
1920

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//go:generate mockery -name=BookDeleter
2+
3+
package bookdelete
4+
5+
import (
6+
"context"
7+
"net/http"
8+
"strconv"
9+
10+
"github.com/go-chi/chi"
11+
)
12+
13+
type (
14+
BookDeleter interface {
15+
DeleteBook(ctx context.Context, id int) error
16+
}
17+
18+
handler struct {
19+
deleter BookDeleter
20+
}
21+
)
22+
23+
func NewHandler(deleter BookDeleter) handler {
24+
return handler{
25+
deleter: deleter,
26+
}
27+
}
28+
29+
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
30+
param := chi.URLParam(r, "bookID")
31+
bookID, err := strconv.Atoi(param)
32+
if err != nil {
33+
w.WriteHeader(http.StatusInternalServerError)
34+
return
35+
}
36+
37+
err = h.deleter.DeleteBook(r.Context(), bookID)
38+
if err != nil {
39+
w.WriteHeader(http.StatusInternalServerError)
40+
return
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package bookdelete_test
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/go-chi/chi"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/mock"
11+
12+
"github.com/rafaelhl/library-rel-lib/books/handler/bookdelete"
13+
"github.com/rafaelhl/library-rel-lib/books/handler/bookdelete/mocks"
14+
)
15+
16+
func TestHandler_ServeHTTP(t *testing.T) {
17+
deleter := new(mocks.BookDeleter)
18+
deleter.On("DeleteBook", mock.Anything, 1).Return(nil)
19+
h := bookdelete.NewHandler(deleter)
20+
21+
mux := chi.NewMux()
22+
mux.Method(http.MethodDelete, "/books/{bookID}", h)
23+
24+
req := httptest.NewRequest(http.MethodDelete, "/books/1", nil)
25+
recorder := httptest.NewRecorder()
26+
mux.ServeHTTP(recorder, req)
27+
28+
deleter.AssertExpectations(t)
29+
assert.Equal(t, http.StatusOK, recorder.Code)
30+
}

books/handler/bookdelete/mocks/BookDeleter.go

+28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

books/repository/repository.go

+4
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ func (r BooksRepository) FindAllBooks(ctx context.Context) ([]books.Book, error)
7676
}
7777
return bookList, err
7878
}
79+
80+
func (r BooksRepository) DeleteBook(ctx context.Context, book books.Book) error {
81+
return r.repo.Delete(ctx, &book)
82+
}

books/repository/repository_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,23 @@ func TestBooksRepository_FindAllBooks(t *testing.T) {
156156
assert.NoError(t, err)
157157
assert.Equal(t, expectedBooks, allBooks)
158158
}
159+
160+
func TestBooksRepository_DeleteBook(t *testing.T) {
161+
repo := reltest.New()
162+
booksRepository := repository.New(repo)
163+
book := books.Book{
164+
ID: 1,
165+
Title: "Livro de Teste",
166+
Description: "Esse livro é de teste",
167+
Author: "Rafael Holanda",
168+
Edition: 1,
169+
BookShelf: books.Shelf{
170+
ID: 1,
171+
},
172+
}
173+
174+
repo.ExpectDelete().For(&book)
175+
err := booksRepository.DeleteBook(context.Background(), book)
176+
177+
assert.NoError(t, err)
178+
}

main.go

+3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
"github.com/go-chi/chi/middleware"
1212
"github.com/go-chi/render"
1313

14+
"github.com/rafaelhl/library-rel-lib/books/bookdeleter"
1415
"github.com/rafaelhl/library-rel-lib/books/bookfinder"
1516
"github.com/rafaelhl/library-rel-lib/books/booklistfinder"
1617
"github.com/rafaelhl/library-rel-lib/books/booksinserter"
1718
"github.com/rafaelhl/library-rel-lib/books/bookupdater"
19+
"github.com/rafaelhl/library-rel-lib/books/handler/bookdelete"
1820
"github.com/rafaelhl/library-rel-lib/books/handler/bookfind"
1921
"github.com/rafaelhl/library-rel-lib/books/handler/bookinsert"
2022
"github.com/rafaelhl/library-rel-lib/books/handler/booklistfind"
@@ -44,6 +46,7 @@ func main() {
4446
router.Method(http.MethodPost, "/books", bookinsert.NewHandler(booksinserter.New(repository, repository)))
4547
router.Method(http.MethodGet, "/books/{bookID}", bookfind.NewHandler(bookfinder.New(repository)))
4648
router.Method(http.MethodPut, "/books/{bookID}", bookupdate.NewHandler(bookupdater.New(repository)))
49+
router.Method(http.MethodDelete, "/books/{bookID}", bookdelete.NewHandler(bookdeleter.New(repository, repository)))
4750
router.Method(http.MethodGet, "/books", booklistfind.NewHandler(booklistfinder.New(repository)))
4851

4952
err = http.ListenAndServe(":8080", router)

0 commit comments

Comments
 (0)