fix: update type handling for schema changes
- Fix pgtype.UUID usage in test files by properly converting string UUIDs to pgtype.UUID - Update numericToFloat to use pgtype.Float8 instead of pgtype.Numeric for DOUBLE PRECISION support - Fix field name from WebURL to WebUrl to match current schema These changes align with the recent community_rating type change to DOUBLE PRECISION and ensure consistent type handling across the codebase.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"bookhoard/internal/database"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -17,12 +18,12 @@ func TestComicMetadataExtraction(t *testing.T) {
|
||||
defer setup.Server.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
libraryID := setup.CreateLibrary(t, "Comic Test Library", "comic")
|
||||
libraryID := setup.CreateLibrary(t, "Comic Test Library", "comics")
|
||||
|
||||
t.Run("CBZ with RTL manga", func(t *testing.T) {
|
||||
// Insert test media item with full comic metadata
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
Title: "Test Manga",
|
||||
FilePath: "/test/manga.cbz",
|
||||
MangaType: pgtype.Text{String: "yes_and_right_to_left", Valid: true},
|
||||
@@ -39,7 +40,7 @@ func TestComicMetadataExtraction(t *testing.T) {
|
||||
|
||||
// Query it back
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, len(items), 0)
|
||||
@@ -59,7 +60,7 @@ func TestComicMetadataExtraction(t *testing.T) {
|
||||
|
||||
t.Run("CBZ with Western comic", func(t *testing.T) {
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
Title: "Test Comic",
|
||||
FilePath: "/test/comic.cbz",
|
||||
MangaType: pgtype.Text{String: "no", Valid: true},
|
||||
@@ -72,7 +73,7 @@ func TestComicMetadataExtraction(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -87,7 +88,7 @@ func TestComicMetadataExtraction(t *testing.T) {
|
||||
|
||||
t.Run("Comic with minimal metadata", func(t *testing.T) {
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
Title: "Minimal Comic",
|
||||
FilePath: "/test/minimal.cbz",
|
||||
// Only required fields - comic metadata should default appropriately
|
||||
@@ -95,7 +96,7 @@ func TestComicMetadataExtraction(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -113,7 +114,7 @@ func TestReadingDirectionAPI(t *testing.T) {
|
||||
defer setup.Server.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
libraryID := setup.CreateLibrary(t, "Reading Direction Test Library", "comic")
|
||||
libraryID := setup.CreateLibrary(t, "Reading Direction Test Library", "comics")
|
||||
|
||||
// Create test items with different reading directions
|
||||
testCases := []struct {
|
||||
@@ -128,7 +129,7 @@ func TestReadingDirectionAPI(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
Title: tc.title,
|
||||
FilePath: "/test/" + tc.title + ".cbz",
|
||||
MangaType: pgtype.Text{String: tc.manga, Valid: true},
|
||||
@@ -139,7 +140,7 @@ func TestReadingDirectionAPI(t *testing.T) {
|
||||
|
||||
t.Run("Search API includes reading_direction", func(t *testing.T) {
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 3)
|
||||
@@ -155,7 +156,7 @@ func TestReadingDirectionAPI(t *testing.T) {
|
||||
t.Run("Filter by reading_direction - RTL only", func(t *testing.T) {
|
||||
// Query all items and filter in-memory
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -171,7 +172,7 @@ func TestReadingDirectionAPI(t *testing.T) {
|
||||
|
||||
t.Run("Verify all reading directions present", func(t *testing.T) {
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -194,25 +195,25 @@ func TestUniversalMetadataFields(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Test with both comic and ebook libraries
|
||||
comicLibraryID := setup.CreateLibrary(t, "Comic Library", "comic")
|
||||
ebookLibraryID := setup.CreateLibrary(t, "Ebook Library", "ebook")
|
||||
comicLibraryID := setup.CreateLibrary(t, "Comic Library", "comics")
|
||||
ebookLibraryID := setup.CreateLibrary(t, "Ebook Library", "ebooks")
|
||||
|
||||
t.Run("Comic with universal fields", func(t *testing.T) {
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: comicLibraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(comicLibraryID)), Valid: true},
|
||||
Title: "Comic with Universal Metadata",
|
||||
FilePath: "/test/comic.cbz",
|
||||
SeriesCount: pgtype.Int4{Int32: 10, Valid: true},
|
||||
Volume: pgtype.Int4{Int32: 2, Valid: true},
|
||||
Imprint: pgtype.Text{String: "DC Black Label", Valid: true},
|
||||
AgeRating: pgtype.Text{String: "Mature", Valid: true},
|
||||
WebURL: pgtype.Text{String: "https://example.com/comic", Valid: true},
|
||||
WebUrl: pgtype.Text{String: "https://example.com/comic", Valid: true},
|
||||
CommunityRating: pgtype.Float8{Float64: 9.2, Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: comicLibraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(comicLibraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -227,20 +228,20 @@ func TestUniversalMetadataFields(t *testing.T) {
|
||||
|
||||
t.Run("Ebook with universal fields", func(t *testing.T) {
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: ebookLibraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(ebookLibraryID)), Valid: true},
|
||||
Title: "Ebook with Universal Metadata",
|
||||
FilePath: "/test/book.epub",
|
||||
SeriesCount: pgtype.Int4{Int32: 7, Valid: true},
|
||||
Volume: pgtype.Int4{Int32: 1, Valid: true},
|
||||
Imprint: pgtype.Text{String: "HarperCollins", Valid: true},
|
||||
AgeRating: pgtype.Text{String: "Everyone", Valid: true},
|
||||
WebURL: pgtype.Text{String: "https://example.com/book", Valid: true},
|
||||
WebUrl: pgtype.Text{String: "https://example.com/book", Valid: true},
|
||||
CommunityRating: pgtype.Float8{Float64: 4.5, Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: ebookLibraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(ebookLibraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -260,13 +261,13 @@ func TestComicSpecificFields(t *testing.T) {
|
||||
defer setup.Server.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
libraryID := setup.CreateLibrary(t, "Comic Library", "comic")
|
||||
libraryID := setup.CreateLibrary(t, "Comic Library", "comics")
|
||||
|
||||
t.Run("Alternate series info as JSONB", func(t *testing.T) {
|
||||
alternateInfo := `{"alternate_series":"Ultimate X-Men","alternate_number":1,"alternate_count":12}`
|
||||
|
||||
_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
Title: "X-Men with Alternate Series",
|
||||
FilePath: "/test/xmen.cbz",
|
||||
AlternateInfo: []byte(alternateInfo),
|
||||
@@ -277,7 +278,7 @@ func TestComicSpecificFields(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
items, err := setup.DB.SearchMediaItems(ctx, database.SearchMediaItemsParams{
|
||||
LibraryID: libraryID,
|
||||
LibraryID: pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -444,7 +445,11 @@ func (h *MediaHandler) HandleBulkDelete(c *echo.Context) error {
|
||||
}
|
||||
|
||||
if media.FilePath != "" {
|
||||
os.Remove(media.FilePath)
|
||||
if err := os.Remove(media.FilePath); err != nil {
|
||||
// Log file removal failure but don't fail the request
|
||||
// DB record is already deleted, which is the primary concern
|
||||
log.Printf("Warning: failed to remove file %s: %v", media.FilePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
results = append(results, map[string]interface{}{
|
||||
@@ -1644,12 +1649,9 @@ func (mh *MediaHandler) ServeFile(c *echo.Context) error {
|
||||
}
|
||||
|
||||
// numericToFloat converts pgtype.Numeric to float64, returning 0 if invalid
|
||||
func numericToFloat(n pgtype.Numeric) float64 {
|
||||
func numericToFloat(n pgtype.Float8) float64 {
|
||||
if n.Valid {
|
||||
f, err := n.Float64Value()
|
||||
if err == nil {
|
||||
return f.Float64
|
||||
}
|
||||
return n.Float64
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user