author is now on separate table
This commit is contained in:
@@ -11,11 +11,20 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPostBookHandler_Ok(t *testing.T) {
|
||||
func TestPostBookHandler_OkAuthorExist(t *testing.T) {
|
||||
bookJson :=
|
||||
`{
|
||||
"title": "Le château",
|
||||
"author": "Kafka"
|
||||
"title": "Le Procès",
|
||||
"author": "Franz Kafka"
|
||||
}`
|
||||
testPostBookHandler(t, bookJson, 200)
|
||||
}
|
||||
|
||||
func TestPostBookHandler_OkNewAuthor(t *testing.T) {
|
||||
bookJson :=
|
||||
`{
|
||||
"title": "Le joueur d'échecs",
|
||||
"author": "Stefan Zweig"
|
||||
}`
|
||||
testPostBookHandler(t, bookJson, 200)
|
||||
}
|
||||
@@ -23,7 +32,7 @@ func TestPostBookHandler_Ok(t *testing.T) {
|
||||
func TestPostBookHandler_OkOnlyTitle(t *testing.T) {
|
||||
bookJson :=
|
||||
`{
|
||||
"title": "Le château"
|
||||
"title": "Le Procès"
|
||||
}`
|
||||
testPostBookHandler(t, bookJson, 200)
|
||||
}
|
||||
|
||||
@@ -61,6 +61,22 @@ func TestSearchBook_OneBookRead(t *testing.T) {
|
||||
books)
|
||||
}
|
||||
|
||||
func TestSearchBook_ISBN(t *testing.T) {
|
||||
books := testSearchBook(t, "9782070337903", "", "")
|
||||
assert.Equal(t, 1, len(books))
|
||||
assert.Equal(t,
|
||||
[]bookSearchGet{{
|
||||
Title: "Le complot contre l'Amérique",
|
||||
Author: "Philip Roth",
|
||||
Id: 22,
|
||||
Rating: 6,
|
||||
Read: true,
|
||||
WantRead: false,
|
||||
CoverPath: "/bookcover/lecomplotcontrelamerique.jpg",
|
||||
}},
|
||||
books)
|
||||
}
|
||||
|
||||
func TestSearchBook_Limit(t *testing.T) {
|
||||
books := testSearchBook(t, "a", "10", "")
|
||||
assert.Equal(t, 10, len(books))
|
||||
|
||||
9
internal/model/author.go
Normal file
9
internal/model/author.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Author struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
@@ -6,8 +6,9 @@ type Book struct {
|
||||
gorm.Model
|
||||
Title string `json:"title" gorm:"not null"`
|
||||
ISBN string `json:"isbn"`
|
||||
Author string `json:"author"`
|
||||
Summary string `json:"summary"`
|
||||
Author Author
|
||||
AuthorID uint
|
||||
AddedBy User
|
||||
AddedByID uint
|
||||
Cover StaticFile
|
||||
|
||||
@@ -22,14 +22,15 @@ type BookGet struct {
|
||||
func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (BookGet, error) {
|
||||
var book BookGet
|
||||
query := db.Model(&model.Book{})
|
||||
selectQueryString := "books.title, books.author, books.isbn, books.summary, " +
|
||||
selectQueryString := "books.title, authors.name as author, books.isbn, books.summary, " +
|
||||
"user_books.rating, user_books.read, user_books.want_read, " +
|
||||
"DATE(user_books.start_read_date) as start_read_date, " +
|
||||
"DATE(user_books.end_read_date) AS end_read_date, " +
|
||||
selectStaticFilesPath()
|
||||
query = query.Select(selectQueryString)
|
||||
query = joinAuthors(query)
|
||||
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId)
|
||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
query = joinStaticFiles(query)
|
||||
query = query.Where("books.id = ?", bookId)
|
||||
res := query.First(&book)
|
||||
return book, res.Error
|
||||
@@ -113,9 +114,10 @@ func fetchWantReadUserBookQuery(db *gorm.DB, userId uint) *gorm.DB {
|
||||
|
||||
func fetchUserBookGet(db *gorm.DB, userId uint) *gorm.DB {
|
||||
query := db.Model(&model.UserBook{})
|
||||
query = query.Select("books.id, books.title, books.author, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||
query = query.Select("books.id, books.title, authors.name as author, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||
query = query.Joins("left join books on (books.id = user_books.book_id)")
|
||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
query = joinAuthors(query)
|
||||
query = joinStaticFiles(query)
|
||||
query = query.Where("user_id = ?", userId)
|
||||
return query
|
||||
}
|
||||
@@ -123,3 +125,11 @@ func fetchUserBookGet(db *gorm.DB, userId uint) *gorm.DB {
|
||||
func selectStaticFilesPath() string {
|
||||
return "(CASE COALESCE(static_files.path, '') WHEN '' THEN '' ELSE concat('" + fileutils.GetWsLinkPrefix() + "', static_files.path) END) as CoverPath"
|
||||
}
|
||||
|
||||
func joinAuthors(query *gorm.DB) *gorm.DB {
|
||||
return query.Joins("left join authors on (authors.id = books.author_id)")
|
||||
}
|
||||
|
||||
func joinStaticFiles(query *gorm.DB) *gorm.DB {
|
||||
return query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
@@ -34,10 +35,22 @@ func FetchBookSearchGetCount(db *gorm.DB, userId uint, searchterm string) (int64
|
||||
}
|
||||
|
||||
func fetchBookSearchQuery(db *gorm.DB, userId uint, searchterm string) *gorm.DB {
|
||||
query := db.Model(&model.Book{})
|
||||
query = query.Select("books.id, books.title, books.author, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId)
|
||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
query = query.Where("LOWER(books.title) LIKE ?", "%"+strings.ToLower(searchterm)+"%")
|
||||
query := fetchBookSearchQueryBuilder(db, userId)
|
||||
isIsbn, _ := regexp.Match(`\d{10,13}`, []byte(searchterm))
|
||||
if isIsbn {
|
||||
query = query.Where("books.isbn = ?", searchterm)
|
||||
} else {
|
||||
query = query.Where("LOWER(books.title) LIKE ?", "%"+strings.ToLower(searchterm)+"%")
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
func fetchBookSearchQueryBuilder(db *gorm.DB, userId uint) *gorm.DB {
|
||||
query := db.Model(&model.Book{})
|
||||
query = query.Select("books.id, books.title, authors.name as author, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||
query = joinAuthors(query)
|
||||
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId)
|
||||
query = joinStaticFiles(query)
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/myvalidator"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type bookPostCreate struct {
|
||||
@@ -29,8 +32,8 @@ func PostBookHandler(ac appcontext.AppContext) {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
bookDb := bookWsToDb(book, &user)
|
||||
err = ac.Db.Model(&model.Book{}).Save(&bookDb).Error
|
||||
|
||||
err = saveBookToDb(ac, book, &user)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
@@ -38,14 +41,38 @@ func PostBookHandler(ac appcontext.AppContext) {
|
||||
ac.C.String(200, "Success")
|
||||
}
|
||||
|
||||
func bookWsToDb(b bookPostCreate, user *model.User) model.Book {
|
||||
func saveBookToDb(ac appcontext.AppContext, b bookPostCreate, user *model.User) error {
|
||||
author, err := fetchOrCreateAuthor(ac, b.Author)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
book := model.Book{
|
||||
Title: b.Title,
|
||||
Author: b.Author,
|
||||
AddedBy: *user,
|
||||
Title: b.Title,
|
||||
AuthorID: author.ID,
|
||||
AddedBy: *user,
|
||||
}
|
||||
if b.CoverID > 0 {
|
||||
book.CoverID = b.CoverID
|
||||
}
|
||||
return book
|
||||
return ac.Db.Save(&book).Error
|
||||
}
|
||||
|
||||
func fetchOrCreateAuthor(ac appcontext.AppContext, name string) (*model.Author, error) {
|
||||
var author model.Author
|
||||
res := ac.Db.Where("name = ?", name)
|
||||
err := res.Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
author = model.Author{Name: name}
|
||||
err = ac.Db.Save(&author).Error
|
||||
if err != nil {
|
||||
return &author, err
|
||||
}
|
||||
return &author, nil
|
||||
} else {
|
||||
return &author, err
|
||||
}
|
||||
} else {
|
||||
return &author, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func PutReadUserBookHandler(ac appcontext.AppContext) {
|
||||
}
|
||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -71,6 +72,7 @@ func PutWantReadUserBookHandler(ac appcontext.AppContext) {
|
||||
}
|
||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
userbook.WantRead = wantread.WantRead
|
||||
@@ -124,6 +126,7 @@ func PutRateUserBookHandler(ac appcontext.AppContext) {
|
||||
}
|
||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
userbook.Rating = rating.Rating
|
||||
@@ -200,12 +203,10 @@ func fetchOrCreateUserBook(ac appcontext.AppContext, bookId uint, user *model.Us
|
||||
userbook = createUserBook(bookId, user)
|
||||
err = ac.Db.Save(&userbook).Error
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return userbook, err
|
||||
}
|
||||
return userbook, nil
|
||||
} else {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return userbook, err
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user