Add position for book in collection

This commit is contained in:
2026-04-11 17:26:21 +02:00
parent 36a21c8891
commit d2fe3bf34f
14 changed files with 200 additions and 58 deletions

View File

@@ -10,12 +10,37 @@ import (
"gorm.io/gorm"
)
func CollectionQueryToCollectionItemDto(collectionsQueryResult []query.CollectionsQueryResult) []dto.CollectionItemGet {
var collections []dto.CollectionItemGet
func CollectionItemsQueryToDto(itemsQueryResult []query.CollectionItemQueryResult) []dto.CollectionItemGet {
var dtoItems []dto.CollectionItemGet
for _, queryResult := range itemsQueryResult {
bookItem := dto.BookItemGet{
ID: queryResult.ID,
Title: queryResult.Title,
Author: queryResult.Author,
Description: queryResult.Description,
InventaireID: queryResult.InventaireID,
IsInventaireEdition: queryResult.IsInventaireEdition,
Rating: queryResult.Rating,
Read: queryResult.Read,
StartReadDate: queryResult.StartReadDate,
WantRead: queryResult.WantRead,
CoverPath: queryResult.CoverPath,
}
dtoItems = append(dtoItems,
dto.CollectionItemGet{
Position: queryResult.Position,
Book: bookItem,
})
}
return dtoItems
}
func CollectionQueryToCollectionItemDto(collectionsQueryResult []query.CollectionsQueryResult) []dto.CollectionListItemGet {
var collections []dto.CollectionListItemGet
for _, collectionDb := range collectionsQueryResult {
i := findIdInCollection(collections, collectionDb.ID)
if i == -1 {
collections = append(collections, dto.CollectionItemGet{
collections = append(collections, dto.CollectionListItemGet{
ID: collectionDb.ID,
Name: collectionDb.Name,
})
@@ -30,9 +55,9 @@ func CollectionQueryToCollectionItemDto(collectionsQueryResult []query.Collectio
return collections
}
func collectionDbToCollectionBookItem(collectionDb *query.CollectionsQueryResult) *dto.CollectionBookItemGet {
func collectionDbToCollectionBookItem(collectionDb *query.CollectionsQueryResult) *dto.CollectionListBookItemGet {
if collectionDb.BookId > 0 {
bookItem := dto.CollectionBookItemGet{
bookItem := dto.CollectionListBookItemGet{
ID: collectionDb.BookId,
Title: collectionDb.BookTitle,
CoverPath: collectionDb.CoverPath,
@@ -44,7 +69,7 @@ func collectionDbToCollectionBookItem(collectionDb *query.CollectionsQueryResult
}
// returns the position in collections, -1 if not found
func findIdInCollection(collections []dto.CollectionItemGet, collectionId uint) int {
func findIdInCollection(collections []dto.CollectionListItemGet, collectionId uint) int {
for i, collection := range collections {
if collection.ID == collectionId {
return i

View File

@@ -13,14 +13,14 @@ func TestGetCollection_Ok(t *testing.T) {
status, collection := testGetCollection(t, "1", "10", "0")
assert.Equal(t, http.StatusOK, status)
assert.Equal(t, "Littérature française", collection.Name)
assert.Equal(t, 6, len(collection.Books))
assert.Equal(t, 6, len(collection.Items))
}
func TestGetCollection_Limit(t *testing.T) {
status, collection := testGetCollection(t, "2", "3", "0")
assert.Equal(t, http.StatusOK, status)
assert.Equal(t, "Nouvelles", collection.Name)
assert.Equal(t, 3, len(collection.Books))
assert.Equal(t, 3, len(collection.Items))
assert.Equal(t, int64(4), collection.Count)
}
@@ -33,10 +33,17 @@ func TestGetCollection_Empty(t *testing.T) {
status, collection := testGetCollection(t, "4", "10", "0")
assert.Equal(t, http.StatusOK, status)
assert.Equal(t, "Empty", collection.Name)
assert.Equal(t, 0, len(collection.Books))
assert.Equal(t, 0, len(collection.Items))
assert.Equal(t, int64(0), collection.Count)
}
func TestGetCollection_Position(t *testing.T) {
status, collection := testGetCollection(t, "2", "3", "0")
assert.Equal(t, http.StatusOK, status)
assert.Equal(t, "Nouvelles", collection.Name)
assert.Equal(t, uint(3), collection.Items[2].Position)
}
func testGetCollection(t *testing.T, id string, limit string, offset string) (int, dto.CollectionGet) {
return testutils.TestFetchModel[dto.CollectionGet](t, "/ws/collection/"+id, limit, offset)
}

View File

@@ -11,24 +11,36 @@ import (
"github.com/stretchr/testify/assert"
)
func TestPostCollectionBookHandler_Ok(t *testing.T) {
func TestPostCollectionBookHandler_AddOk(t *testing.T) {
payload :=
`{
"bookId": 9
}`
collectionId := "1"
status := testPostCollectionBookHandler(t, collectionId, payload)
status := testPostCollectionBookHandler(collectionId, payload)
assert.Equal(t, http.StatusOK, status)
_, collection := testGetCollection(t, collectionId, "10", "0")
assert.Equal(t, int64(7), collection.Count)
}
func TestPostCollectionBookHandler_BookOK(t *testing.T) {
payload :=
`{
"bookId": 7
}`
collectionId := "2"
status := testPostCollectionBookHandler(collectionId, payload)
assert.Equal(t, http.StatusOK, status)
_, collection := testGetCollection(t, collectionId, "10", "0")
assert.Equal(t, uint(7), collection.Items[0].Book.ID)
}
func TestPostCollectionBookHandler_CollectionNotFound(t *testing.T) {
payload :=
`{
"bookId": 9
}`
status := testPostCollectionBookHandler(t, "12", payload)
status := testPostCollectionBookHandler("12", payload)
assert.Equal(t, http.StatusNotFound, status)
}
@@ -37,7 +49,7 @@ func TestPostCollectionBookHandler_BookNotFound(t *testing.T) {
`{
"bookId": 14654
}`
status := testPostCollectionBookHandler(t, "1", payload)
status := testPostCollectionBookHandler("1", payload)
assert.Equal(t, http.StatusNotFound, status)
}
@@ -46,11 +58,11 @@ func TestPostCollectionBookHandler_Unauthorized(t *testing.T) {
`{
"bookId": 9
}`
status := testPostCollectionBookHandler(t, "3", payload)
status := testPostCollectionBookHandler("3", payload)
assert.Equal(t, http.StatusUnauthorized, status)
}
func testPostCollectionBookHandler(t *testing.T, collectionId string, payload string) int {
func testPostCollectionBookHandler(collectionId string, payload string) int {
router := testutils.TestSetup()
w := httptest.NewRecorder()

View File

@@ -23,6 +23,7 @@ func Initdb(databasePath string, demoDataPath string) *gorm.DB {
db.AutoMigrate(&model.UserBook{})
db.AutoMigrate(&model.StaticFile{})
db.AutoMigrate(&model.Collection{})
db.AutoMigrate(&model.CollectionItem{})
var book model.Book
queryResult := db.Limit(1).Find(&book)
if queryResult.RowsAffected == 0 && demoDataPath != "" {

View File

@@ -45,23 +45,28 @@ type BookItemGet struct {
}
type CollectionGet struct {
Name string `json:"name"`
Count int64 `json:"count"`
Books []BookItemGet `json:"books"`
}
type CollectionItemsGet struct {
Count int64 `json:"count"`
Collections []CollectionItemGet `json:"collections"`
Name string `json:"name"`
Count int64 `json:"count"`
Items []CollectionItemGet `json:"items"`
}
type CollectionItemGet struct {
ID uint `json:"id"`
Name string `json:"name"`
Books []CollectionBookItemGet `json:"books"`
Position uint `json:"position"`
Book BookItemGet `json:"book"`
}
type CollectionBookItemGet struct {
type CollectionItemsGet struct {
Count int64 `json:"count"`
Collections []CollectionListItemGet `json:"collections"`
}
type CollectionListItemGet struct {
ID uint `json:"id"`
Name string `json:"name"`
Books []CollectionListBookItemGet `json:"books"`
}
type CollectionListBookItemGet struct {
ID uint `json:"id"`
Title string `json:"title"`
CoverPath string `json:"coverPath"`

View File

@@ -7,5 +7,5 @@ type Collection struct {
Name string
User User
UserID uint
Books []Book `gorm:"many2many:collection_books;"`
Items []CollectionItem
}

View File

@@ -0,0 +1,11 @@
package model
import "gorm.io/gorm"
type CollectionItem struct {
gorm.Model
CollectionID uint
Position uint
Book Book
BookID uint
}

View File

@@ -1,7 +1,6 @@
package query
import (
"git.artlef.fr/bibliomane/internal/dto"
"git.artlef.fr/bibliomane/internal/model"
"gorm.io/gorm"
)
@@ -64,8 +63,8 @@ func fetchCollectionItemBook(db *gorm.DB, collectionId uint, limit int, offset i
func fetchCollectionItemBooksQuery(db *gorm.DB, collectionId uint) *gorm.DB {
query := db.Model(&model.Collection{})
query = query.Select("collections.id, collections.user_id, collections.name, books.id as book_id, books.title as book_title, " + selectStaticFilesPath())
query = query.Joins("left join collection_books on (collection_books.collection_id = collections.id)")
query = query.Joins("left join books on (books.id = collection_books.book_id)")
query = query.Joins("left join collection_items on (collection_items.collection_id = collections.id)")
query = query.Joins("left join books on (books.id = collection_items.book_id)")
query = joinStaticFiles(query)
query = query.Where("collections.id = ?", collectionId)
return query
@@ -81,14 +80,29 @@ func fetchCollections(db *gorm.DB, userId uint) *gorm.DB {
return db.Model(&model.Collection{}).Where("collections.user_id = ?", userId)
}
func FetchCollectionBooks(db *gorm.DB, userId uint, collectionId uint, limit int, offset int) ([]dto.BookItemGet, error) {
var books []dto.BookItemGet
type CollectionItemQueryResult struct {
Position uint
ID uint
Title string
Author string
Description string
InventaireID string
IsInventaireEdition bool
Rating int
Read bool
StartReadDate string
WantRead bool
CoverPath string
}
func FetchCollectionItems(db *gorm.DB, userId uint, collectionId uint, limit int, offset int) ([]CollectionItemQueryResult, error) {
var collectionitems []CollectionItemQueryResult
query := fetchCollectionBooksQuery(db, userId, collectionId)
query = query.Limit(limit)
query = query.Offset(offset)
query = query.Order("books.id DESC")
res := query.Find(&books)
return books, res.Error
query = query.Order("collection_items.position")
res := query.Find(&collectionitems)
return collectionitems, res.Error
}
func FetchCollectionBooksCount(db *gorm.DB, userId uint, collectionId uint) (int64, error) {
@@ -98,8 +112,14 @@ func FetchCollectionBooksCount(db *gorm.DB, userId uint, collectionId uint) (int
}
func fetchCollectionBooksQuery(db *gorm.DB, userId uint, collectionId uint) *gorm.DB {
query := fetchBookQueryBuilder(db, userId)
query = query.Joins("left join collection_books on (collection_books.book_id = books.id)")
query = query.Where("collection_books.collection_id = ?", collectionId)
query := db.Model(&model.CollectionItem{})
query = query.Select("collection_items.position, " + selectBookItem())
query = query.Joins("left join collections on (collection_items.collection_id = collections.id)")
query = query.Joins("left join books on (books.id = collection_items.book_id)")
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)
query = query.Order("collection_items.position")
query = query.Where("collections.id = ?", collectionId)
return query
}

View File

@@ -56,7 +56,7 @@ func PostCollectionBookHandler(ac appcontext.AppContext) {
return
}
collection.Books = append(collection.Books, book)
ac.Db.Save(&collection)
item := model.CollectionItem{Position: 0, BookID: book.ID, CollectionID: collection.ID}
ac.Db.Save(&item)
ac.C.String(http.StatusOK, "Success")
}

View File

@@ -5,6 +5,7 @@ import (
"net/http"
"strconv"
"git.artlef.fr/bibliomane/internal/adapter"
"git.artlef.fr/bibliomane/internal/appcontext"
"git.artlef.fr/bibliomane/internal/dto"
"git.artlef.fr/bibliomane/internal/i18nresource"
@@ -50,12 +51,13 @@ func GetCollectionHandler(ac appcontext.AppContext) {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
books, err := query.FetchCollectionBooks(ac.Db, user.ID, uint(collectionId), limit, offset)
itemsQueryResult, err := query.FetchCollectionItems(ac.Db, user.ID, uint(collectionId), limit, offset)
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
return
}
collection.Books = books
items := adapter.CollectionItemsQueryToDto(itemsQueryResult)
collection.Items = items
count, err := query.FetchCollectionBooksCount(ac.Db, user.ID, uint(collectionId))
if err != nil {
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)