Phase 1: Add enhanced database fields and sorting
- Add 9 new fields to media_items table (language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects) - Add indexes for new fields (language, genre, page_count, copyright_year, series_order, date_published) - Add ListMediaItemsSorted SQL query for dynamic sorting - Update ListMediaItems handler to process sort parameter - Support 16 sorting options (title, author, created_at, date_published, copyright_year, page_count, genre, series) - Add /api/media-items/filtered endpoint for advanced filtering - Register new filtered endpoint in routes
This commit is contained in:
@@ -107,6 +107,15 @@ CREATE TABLE media_items (
|
|||||||
date_published DATE,
|
date_published DATE,
|
||||||
publisher VARCHAR(255),
|
publisher VARCHAR(255),
|
||||||
contributors TEXT,
|
contributors TEXT,
|
||||||
|
language VARCHAR(10) DEFAULT 'en',
|
||||||
|
edition VARCHAR(255),
|
||||||
|
page_count INTEGER,
|
||||||
|
goodreads_id VARCHAR(20),
|
||||||
|
openlibrary_id VARCHAR(100),
|
||||||
|
google_books_id VARCHAR(100),
|
||||||
|
copyright_year INTEGER,
|
||||||
|
genre VARCHAR(100),
|
||||||
|
subjects TEXT[],
|
||||||
added_by_admin_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
added_by_admin_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
@@ -246,6 +255,12 @@ CREATE INDEX idx_media_items_title ON media_items(title);
|
|||||||
CREATE INDEX idx_media_items_author ON media_items(author);
|
CREATE INDEX idx_media_items_author ON media_items(author);
|
||||||
CREATE INDEX idx_media_items_library_id ON media_items(library_id);
|
CREATE INDEX idx_media_items_library_id ON media_items(library_id);
|
||||||
CREATE INDEX idx_media_items_added_by_admin_id ON media_items(added_by_admin_id);
|
CREATE INDEX idx_media_items_added_by_admin_id ON media_items(added_by_admin_id);
|
||||||
|
CREATE INDEX idx_media_items_language ON media_items(language);
|
||||||
|
CREATE INDEX idx_media_items_genre ON media_items(genre);
|
||||||
|
CREATE INDEX idx_media_items_page_count ON media_items(page_count);
|
||||||
|
CREATE INDEX idx_media_items_copyright_year ON media_items(copyright_year);
|
||||||
|
CREATE INDEX idx_media_items_series_order ON media_items(series, series_number);
|
||||||
|
CREATE INDEX idx_media_items_date_published ON media_items(date_published);
|
||||||
|
|
||||||
-- GIN indexes for fast fuzzy search using pg_trgm
|
-- GIN indexes for fast fuzzy search using pg_trgm
|
||||||
CREATE INDEX idx_media_items_title_gin ON media_items USING gin (title gin_trgm_ops);
|
CREATE INDEX idx_media_items_title_gin ON media_items USING gin (title gin_trgm_ops);
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ type Querier interface {
|
|||||||
ListLibraries(ctx context.Context) ([]ListLibrariesRow, error)
|
ListLibraries(ctx context.Context) ([]ListLibrariesRow, error)
|
||||||
ListMediaItems(ctx context.Context, arg ListMediaItemsParams) ([]ListMediaItemsRow, error)
|
ListMediaItems(ctx context.Context, arg ListMediaItemsParams) ([]ListMediaItemsRow, error)
|
||||||
ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.UUID) ([]ListMediaItemsByLibraryRow, error)
|
ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.UUID) ([]ListMediaItemsByLibraryRow, error)
|
||||||
|
ListMediaItemsFiltered(ctx context.Context, arg ListMediaItemsFilteredParams) ([]ListMediaItemsFilteredRow, error)
|
||||||
|
ListMediaItemsSorted(ctx context.Context, arg ListMediaItemsSortedParams) ([]ListMediaItemsSortedRow, error)
|
||||||
ListUsers(ctx context.Context) ([]ListUsersRow, error)
|
ListUsers(ctx context.Context) ([]ListUsersRow, error)
|
||||||
RevokeAllUserRefreshTokens(ctx context.Context, userID pgtype.UUID) error
|
RevokeAllUserRefreshTokens(ctx context.Context, userID pgtype.UUID) error
|
||||||
RevokeRefreshToken(ctx context.Context, token string) error
|
RevokeRefreshToken(ctx context.Context, token string) error
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func (q *Queries) CleanupExpiredRefreshTokens(ctx context.Context) error {
|
|||||||
const CreateEbook = `-- name: CreateEbook :one
|
const CreateEbook = `-- name: CreateEbook :one
|
||||||
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id)
|
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id)
|
||||||
VALUES ((SELECT id FROM libraries WHERE library_type_id = (SELECT id FROM library_types WHERE name = 'ebooks') LIMIT 1), $1, $2, normalize_isbn($3), $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
VALUES ((SELECT id FROM libraries WHERE library_type_id = (SELECT id FROM library_types WHERE name = 'ebooks') LIMIT 1), $1, $2, normalize_isbn($3), $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||||
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at
|
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateEbookParams struct {
|
type CreateEbookParams struct {
|
||||||
@@ -105,6 +105,15 @@ func (q *Queries) CreateEbook(ctx context.Context, arg CreateEbookParams) (Media
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -300,7 +309,7 @@ func (q *Queries) CreateMediaHighlight(ctx context.Context, arg CreateMediaHighl
|
|||||||
const CreateMediaItem = `-- name: CreateMediaItem :one
|
const CreateMediaItem = `-- name: CreateMediaItem :one
|
||||||
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id)
|
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id)
|
||||||
VALUES ($1, $2, $3, normalize_isbn($4), $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
VALUES ($1, $2, $3, normalize_isbn($4), $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||||
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at
|
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateMediaItemParams struct {
|
type CreateMediaItemParams struct {
|
||||||
@@ -363,6 +372,15 @@ func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -650,7 +668,7 @@ func (q *Queries) DeleteUser(ctx context.Context, id pgtype.UUID) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GetEbook = `-- name: GetEbook :one
|
const GetEbook = `-- name: GetEbook :one
|
||||||
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM ebooks WHERE id = $1
|
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at FROM ebooks WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
// Backward compatibility - Ebooks queries (using views)
|
// Backward compatibility - Ebooks queries (using views)
|
||||||
@@ -675,6 +693,15 @@ func (q *Queries) GetEbook(ctx context.Context, id pgtype.UUID) (Ebooks, error)
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -684,7 +711,7 @@ func (q *Queries) GetEbook(ctx context.Context, id pgtype.UUID) (Ebooks, error)
|
|||||||
|
|
||||||
const GetEbookByFilePath = `-- name: GetEbookByFilePath :one
|
const GetEbookByFilePath = `-- name: GetEbookByFilePath :one
|
||||||
|
|
||||||
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM ebooks WHERE file_path = $1
|
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at FROM ebooks WHERE file_path = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
// Note: User ebook folders replaced by library folders system
|
// Note: User ebook folders replaced by library folders system
|
||||||
@@ -710,6 +737,15 @@ func (q *Queries) GetEbookByFilePath(ctx context.Context, filePath string) (Eboo
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -1138,7 +1174,7 @@ func (q *Queries) GetMediaHighlights(ctx context.Context, arg GetMediaHighlights
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GetMediaItem = `-- name: GetMediaItem :one
|
const GetMediaItem = `-- name: GetMediaItem :one
|
||||||
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM media_items WHERE id = $1
|
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at FROM media_items WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error) {
|
func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error) {
|
||||||
@@ -1162,6 +1198,15 @@ func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems,
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -1170,7 +1215,7 @@ func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GetMediaItemByFilePath = `-- name: GetMediaItemByFilePath :one
|
const GetMediaItemByFilePath = `-- name: GetMediaItemByFilePath :one
|
||||||
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM media_items WHERE file_path = $1
|
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at FROM media_items WHERE file_path = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetMediaItemByFilePath(ctx context.Context, filePath string) (MediaItems, error) {
|
func (q *Queries) GetMediaItemByFilePath(ctx context.Context, filePath string) (MediaItems, error) {
|
||||||
@@ -1194,6 +1239,15 @@ func (q *Queries) GetMediaItemByFilePath(ctx context.Context, filePath string) (
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -1634,7 +1688,7 @@ func (q *Queries) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ListEbooks = `-- name: ListEbooks :many
|
const ListEbooks = `-- name: ListEbooks :many
|
||||||
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at FROM ebooks ORDER BY created_at DESC LIMIT $1 OFFSET $2
|
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at FROM ebooks ORDER BY created_at DESC LIMIT $1 OFFSET $2
|
||||||
`
|
`
|
||||||
|
|
||||||
type ListEbooksParams struct {
|
type ListEbooksParams struct {
|
||||||
@@ -1669,6 +1723,15 @@ func (q *Queries) ListEbooks(ctx context.Context, arg ListEbooksParams) ([]Ebook
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -1733,7 +1796,7 @@ func (q *Queries) ListLibraries(ctx context.Context) ([]ListLibrariesRow, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ListMediaItems = `-- name: ListMediaItems :many
|
const ListMediaItems = `-- name: ListMediaItems :many
|
||||||
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.copyright_year, mi.genre, mi.subjects, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
||||||
FROM media_items mi
|
FROM media_items mi
|
||||||
JOIN libraries l ON mi.library_id = l.id
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
JOIN library_types lt ON l.library_type_id = lt.id
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
@@ -1763,6 +1826,15 @@ type ListMediaItemsRow struct {
|
|||||||
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
||||||
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
||||||
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
||||||
|
Language pgtype.Text `db:"language" json:"language"`
|
||||||
|
Edition pgtype.Text `db:"edition" json:"edition"`
|
||||||
|
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
|
||||||
|
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
|
||||||
|
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
|
||||||
|
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
|
||||||
|
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
|
||||||
|
Genre pgtype.Text `db:"genre" json:"genre"`
|
||||||
|
Subjects []string `db:"subjects" json:"subjects"`
|
||||||
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
||||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
@@ -1797,6 +1869,15 @@ func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams)
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -1814,7 +1895,7 @@ func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ListMediaItemsByLibrary = `-- name: ListMediaItemsByLibrary :many
|
const ListMediaItemsByLibrary = `-- name: ListMediaItemsByLibrary :many
|
||||||
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.copyright_year, mi.genre, mi.subjects, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
||||||
FROM media_items mi
|
FROM media_items mi
|
||||||
JOIN libraries l ON mi.library_id = l.id
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
JOIN library_types lt ON l.library_type_id = lt.id
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
@@ -1840,6 +1921,15 @@ type ListMediaItemsByLibraryRow struct {
|
|||||||
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
||||||
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
||||||
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
||||||
|
Language pgtype.Text `db:"language" json:"language"`
|
||||||
|
Edition pgtype.Text `db:"edition" json:"edition"`
|
||||||
|
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
|
||||||
|
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
|
||||||
|
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
|
||||||
|
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
|
||||||
|
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
|
||||||
|
Genre pgtype.Text `db:"genre" json:"genre"`
|
||||||
|
Subjects []string `db:"subjects" json:"subjects"`
|
||||||
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
||||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
@@ -1874,6 +1964,346 @@ func (q *Queries) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
|
&i.AddedByAdminID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.LibraryName,
|
||||||
|
&i.LibraryTypeName,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListMediaItemsFiltered = `-- name: ListMediaItemsFiltered :many
|
||||||
|
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.copyright_year, mi.genre, mi.subjects, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
||||||
|
FROM media_items mi
|
||||||
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
|
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
|
||||||
|
WHERE mi.library_id = $2
|
||||||
|
AND COALESCE(lv.is_visible, true) = true
|
||||||
|
AND ($3 = '' OR mi.author ILIKE $3)
|
||||||
|
AND ($4 = '' OR mi.series ILIKE $4)
|
||||||
|
AND ($5 = '' OR mi.genre = $5)
|
||||||
|
AND ($6 = '' OR mi.language = $6)
|
||||||
|
AND ($7 = 0 OR mi.copyright_year >= $7)
|
||||||
|
AND ($8 = 0 OR mi.copyright_year <= $8)
|
||||||
|
AND ($9 = false OR mi.cover_image_path IS NOT NULL)
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN $10 = 'title ASC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $10 = 'title DESC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $10 = 'author ASC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $10 = 'author DESC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $10 = 'created_at ASC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $10 = 'created_at DESC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END DESC,
|
||||||
|
mi.created_at DESC
|
||||||
|
LIMIT $12 OFFSET $11
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListMediaItemsFilteredParams struct {
|
||||||
|
UserID pgtype.UUID `db:"user_id" json:"user_id"`
|
||||||
|
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
|
||||||
|
AuthorFilter interface{} `db:"author_filter" json:"author_filter"`
|
||||||
|
SeriesFilter interface{} `db:"series_filter" json:"series_filter"`
|
||||||
|
GenreFilter interface{} `db:"genre_filter" json:"genre_filter"`
|
||||||
|
LanguageFilter interface{} `db:"language_filter" json:"language_filter"`
|
||||||
|
YearMin interface{} `db:"year_min" json:"year_min"`
|
||||||
|
YearMax interface{} `db:"year_max" json:"year_max"`
|
||||||
|
HasCover interface{} `db:"has_cover" json:"has_cover"`
|
||||||
|
Sort interface{} `db:"sort" json:"sort"`
|
||||||
|
Offset pgtype.Int4 `db:"offset" json:"offset"`
|
||||||
|
Limit pgtype.Int4 `db:"limit" json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListMediaItemsFilteredRow struct {
|
||||||
|
ID pgtype.UUID `db:"id" json:"id"`
|
||||||
|
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
|
||||||
|
Title string `db:"title" json:"title"`
|
||||||
|
Author pgtype.Text `db:"author" json:"author"`
|
||||||
|
Isbn pgtype.Text `db:"isbn" json:"isbn"`
|
||||||
|
Description pgtype.Text `db:"description" json:"description"`
|
||||||
|
FilePath string `db:"file_path" json:"file_path"`
|
||||||
|
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
|
||||||
|
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
|
||||||
|
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
|
||||||
|
Series pgtype.Text `db:"series" json:"series"`
|
||||||
|
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
|
||||||
|
Tags pgtype.Text `db:"tags" json:"tags"`
|
||||||
|
Asin pgtype.Text `db:"asin" json:"asin"`
|
||||||
|
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
||||||
|
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
||||||
|
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
||||||
|
Language pgtype.Text `db:"language" json:"language"`
|
||||||
|
Edition pgtype.Text `db:"edition" json:"edition"`
|
||||||
|
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
|
||||||
|
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
|
||||||
|
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
|
||||||
|
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
|
||||||
|
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
|
||||||
|
Genre pgtype.Text `db:"genre" json:"genre"`
|
||||||
|
Subjects []string `db:"subjects" json:"subjects"`
|
||||||
|
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
||||||
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
|
LibraryName string `db:"library_name" json:"library_name"`
|
||||||
|
LibraryTypeName string `db:"library_type_name" json:"library_type_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListMediaItemsFiltered(ctx context.Context, arg ListMediaItemsFilteredParams) ([]ListMediaItemsFilteredRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, ListMediaItemsFiltered,
|
||||||
|
arg.UserID,
|
||||||
|
arg.LibraryID,
|
||||||
|
arg.AuthorFilter,
|
||||||
|
arg.SeriesFilter,
|
||||||
|
arg.GenreFilter,
|
||||||
|
arg.LanguageFilter,
|
||||||
|
arg.YearMin,
|
||||||
|
arg.YearMax,
|
||||||
|
arg.HasCover,
|
||||||
|
arg.Sort,
|
||||||
|
arg.Offset,
|
||||||
|
arg.Limit,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
items := []ListMediaItemsFilteredRow{}
|
||||||
|
for rows.Next() {
|
||||||
|
var i ListMediaItemsFilteredRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.LibraryID,
|
||||||
|
&i.Title,
|
||||||
|
&i.Author,
|
||||||
|
&i.Isbn,
|
||||||
|
&i.Description,
|
||||||
|
&i.FilePath,
|
||||||
|
&i.FileSize,
|
||||||
|
&i.MimeType,
|
||||||
|
&i.CoverImagePath,
|
||||||
|
&i.Series,
|
||||||
|
&i.SeriesNumber,
|
||||||
|
&i.Tags,
|
||||||
|
&i.Asin,
|
||||||
|
&i.DatePublished,
|
||||||
|
&i.Publisher,
|
||||||
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
|
&i.AddedByAdminID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.LibraryName,
|
||||||
|
&i.LibraryTypeName,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListMediaItemsSorted = `-- name: ListMediaItemsSorted :many
|
||||||
|
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.copyright_year, mi.genre, mi.subjects, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
||||||
|
FROM media_items mi
|
||||||
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
|
WHERE mi.library_id = $1
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'title ASC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'title DESC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'author ASC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'author DESC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'created_at ASC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'created_at DESC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'series ASC' THEN COALESCE(mi.series, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'series DESC' THEN COALESCE(mi.series, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'date_published ASC' THEN COALESCE(mi.date_published::text, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'date_published DESC' THEN COALESCE(mi.date_published::text, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'copyright_year ASC' THEN COALESCE(mi.copyright_year::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'copyright_year DESC' THEN COALESCE(mi.copyright_year::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'genre ASC' THEN COALESCE(mi.genre, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $2 = 'genre DESC' THEN COALESCE(mi.genre, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
mi.created_at DESC
|
||||||
|
LIMIT $4 OFFSET $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListMediaItemsSortedParams struct {
|
||||||
|
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
|
||||||
|
Sort interface{} `db:"sort" json:"sort"`
|
||||||
|
Offset pgtype.Int4 `db:"offset" json:"offset"`
|
||||||
|
Limit pgtype.Int4 `db:"limit" json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListMediaItemsSortedRow struct {
|
||||||
|
ID pgtype.UUID `db:"id" json:"id"`
|
||||||
|
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
|
||||||
|
Title string `db:"title" json:"title"`
|
||||||
|
Author pgtype.Text `db:"author" json:"author"`
|
||||||
|
Isbn pgtype.Text `db:"isbn" json:"isbn"`
|
||||||
|
Description pgtype.Text `db:"description" json:"description"`
|
||||||
|
FilePath string `db:"file_path" json:"file_path"`
|
||||||
|
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
|
||||||
|
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
|
||||||
|
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
|
||||||
|
Series pgtype.Text `db:"series" json:"series"`
|
||||||
|
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
|
||||||
|
Tags pgtype.Text `db:"tags" json:"tags"`
|
||||||
|
Asin pgtype.Text `db:"asin" json:"asin"`
|
||||||
|
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
||||||
|
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
||||||
|
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
||||||
|
Language pgtype.Text `db:"language" json:"language"`
|
||||||
|
Edition pgtype.Text `db:"edition" json:"edition"`
|
||||||
|
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
|
||||||
|
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
|
||||||
|
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
|
||||||
|
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
|
||||||
|
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
|
||||||
|
Genre pgtype.Text `db:"genre" json:"genre"`
|
||||||
|
Subjects []string `db:"subjects" json:"subjects"`
|
||||||
|
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
||||||
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
|
LibraryName string `db:"library_name" json:"library_name"`
|
||||||
|
LibraryTypeName string `db:"library_type_name" json:"library_type_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListMediaItemsSorted(ctx context.Context, arg ListMediaItemsSortedParams) ([]ListMediaItemsSortedRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, ListMediaItemsSorted,
|
||||||
|
arg.LibraryID,
|
||||||
|
arg.Sort,
|
||||||
|
arg.Offset,
|
||||||
|
arg.Limit,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
items := []ListMediaItemsSortedRow{}
|
||||||
|
for rows.Next() {
|
||||||
|
var i ListMediaItemsSortedRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.LibraryID,
|
||||||
|
&i.Title,
|
||||||
|
&i.Author,
|
||||||
|
&i.Isbn,
|
||||||
|
&i.Description,
|
||||||
|
&i.FilePath,
|
||||||
|
&i.FileSize,
|
||||||
|
&i.MimeType,
|
||||||
|
&i.CoverImagePath,
|
||||||
|
&i.Series,
|
||||||
|
&i.SeriesNumber,
|
||||||
|
&i.Tags,
|
||||||
|
&i.Asin,
|
||||||
|
&i.DatePublished,
|
||||||
|
&i.Publisher,
|
||||||
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -1955,7 +2385,7 @@ func (q *Queries) RevokeRefreshToken(ctx context.Context, token string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SearchMediaItems = `-- name: SearchMediaItems :many
|
const SearchMediaItems = `-- name: SearchMediaItems :many
|
||||||
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.copyright_year, mi.genre, mi.subjects, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
||||||
FROM media_items mi
|
FROM media_items mi
|
||||||
JOIN libraries l ON mi.library_id = l.id
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
JOIN library_types lt ON l.library_type_id = lt.id
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
@@ -2005,6 +2435,15 @@ type SearchMediaItemsRow struct {
|
|||||||
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
||||||
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
||||||
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
||||||
|
Language pgtype.Text `db:"language" json:"language"`
|
||||||
|
Edition pgtype.Text `db:"edition" json:"edition"`
|
||||||
|
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
|
||||||
|
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
|
||||||
|
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
|
||||||
|
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
|
||||||
|
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
|
||||||
|
Genre pgtype.Text `db:"genre" json:"genre"`
|
||||||
|
Subjects []string `db:"subjects" json:"subjects"`
|
||||||
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
||||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
@@ -2045,6 +2484,15 @@ func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsPara
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -2062,7 +2510,7 @@ func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsPara
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SearchMediaItemsFuzzy = `-- name: SearchMediaItemsFuzzy :many
|
const SearchMediaItemsFuzzy = `-- name: SearchMediaItemsFuzzy :many
|
||||||
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.copyright_year, mi.genre, mi.subjects, mi.added_by_admin_id, mi.created_at, mi.updated_at, l.name as library_name, lt.name as library_type_name
|
||||||
FROM media_items mi
|
FROM media_items mi
|
||||||
JOIN libraries l ON mi.library_id = l.id
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
JOIN library_types lt ON l.library_type_id = lt.id
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
@@ -2112,6 +2560,15 @@ type SearchMediaItemsFuzzyRow struct {
|
|||||||
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
|
||||||
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
Publisher pgtype.Text `db:"publisher" json:"publisher"`
|
||||||
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
Contributors pgtype.Text `db:"contributors" json:"contributors"`
|
||||||
|
Language pgtype.Text `db:"language" json:"language"`
|
||||||
|
Edition pgtype.Text `db:"edition" json:"edition"`
|
||||||
|
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
|
||||||
|
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
|
||||||
|
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
|
||||||
|
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
|
||||||
|
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
|
||||||
|
Genre pgtype.Text `db:"genre" json:"genre"`
|
||||||
|
Subjects []string `db:"subjects" json:"subjects"`
|
||||||
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
|
||||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
@@ -2151,6 +2608,15 @@ func (q *Queries) SearchMediaItemsFuzzy(ctx context.Context, arg SearchMediaItem
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -2214,7 +2680,7 @@ UPDATE media_items SET
|
|||||||
contributors = $13,
|
contributors = $13,
|
||||||
updated_at = NOW()
|
updated_at = NOW()
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at
|
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateEbookParams struct {
|
type UpdateEbookParams struct {
|
||||||
@@ -2268,6 +2734,15 @@ func (q *Queries) UpdateEbook(ctx context.Context, arg UpdateEbookParams) (Media
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
@@ -2485,7 +2960,7 @@ UPDATE media_items SET
|
|||||||
contributors = $13,
|
contributors = $13,
|
||||||
updated_at = NOW()
|
updated_at = NOW()
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id, created_at, updated_at
|
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, goodreads_id, openlibrary_id, google_books_id, copyright_year, genre, subjects, added_by_admin_id, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateMediaItemParams struct {
|
type UpdateMediaItemParams struct {
|
||||||
@@ -2539,6 +3014,15 @@ func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams
|
|||||||
&i.DatePublished,
|
&i.DatePublished,
|
||||||
&i.Publisher,
|
&i.Publisher,
|
||||||
&i.Contributors,
|
&i.Contributors,
|
||||||
|
&i.Language,
|
||||||
|
&i.Edition,
|
||||||
|
&i.PageCount,
|
||||||
|
&i.GoodreadsID,
|
||||||
|
&i.OpenlibraryID,
|
||||||
|
&i.GoogleBooksID,
|
||||||
|
&i.CopyrightYear,
|
||||||
|
&i.Genre,
|
||||||
|
&i.Subjects,
|
||||||
&i.AddedByAdminID,
|
&i.AddedByAdminID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
|||||||
@@ -119,6 +119,124 @@ JOIN library_types lt ON l.library_type_id = lt.id
|
|||||||
WHERE mi.library_id = $1
|
WHERE mi.library_id = $1
|
||||||
ORDER BY mi.created_at DESC;
|
ORDER BY mi.created_at DESC;
|
||||||
|
|
||||||
|
-- name: ListMediaItemsSorted :many
|
||||||
|
SELECT mi.*, l.name as library_name, lt.name as library_type_name
|
||||||
|
FROM media_items mi
|
||||||
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
|
WHERE mi.library_id = sqlc.narg('library_id')
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'title ASC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'title DESC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'author ASC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'author DESC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'created_at ASC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'created_at DESC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'series ASC' THEN COALESCE(mi.series, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'series DESC' THEN COALESCE(mi.series, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'date_published ASC' THEN COALESCE(mi.date_published::text, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'date_published DESC' THEN COALESCE(mi.date_published::text, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'copyright_year ASC' THEN COALESCE(mi.copyright_year::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'copyright_year DESC' THEN COALESCE(mi.copyright_year::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'genre ASC' THEN COALESCE(mi.genre, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'genre DESC' THEN COALESCE(mi.genre, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
mi.created_at DESC
|
||||||
|
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||||
|
|
||||||
|
-- name: ListMediaItemsFiltered :many
|
||||||
|
SELECT mi.*, l.name as library_name, lt.name as library_type_name
|
||||||
|
FROM media_items mi
|
||||||
|
JOIN libraries l ON mi.library_id = l.id
|
||||||
|
JOIN library_types lt ON l.library_type_id = lt.id
|
||||||
|
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = sqlc.narg('user_id')
|
||||||
|
WHERE mi.library_id = sqlc.narg('library_id')
|
||||||
|
AND COALESCE(lv.is_visible, true) = true
|
||||||
|
AND (sqlc.narg('author_filter') = '' OR mi.author ILIKE sqlc.narg('author_filter'))
|
||||||
|
AND (sqlc.narg('series_filter') = '' OR mi.series ILIKE sqlc.narg('series_filter'))
|
||||||
|
AND (sqlc.narg('genre_filter') = '' OR mi.genre = sqlc.narg('genre_filter'))
|
||||||
|
AND (sqlc.narg('language_filter') = '' OR mi.language = sqlc.narg('language_filter'))
|
||||||
|
AND (sqlc.narg('year_min') = 0 OR mi.copyright_year >= sqlc.narg('year_min'))
|
||||||
|
AND (sqlc.narg('year_max') = 0 OR mi.copyright_year <= sqlc.narg('year_max'))
|
||||||
|
AND (sqlc.narg('has_cover') = false OR mi.cover_image_path IS NOT NULL)
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'title ASC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'title DESC' THEN mi.title
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'author ASC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'author DESC' THEN COALESCE(mi.author, '')
|
||||||
|
ELSE ''
|
||||||
|
END DESC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'created_at ASC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('sort') = 'created_at DESC' THEN mi.created_at
|
||||||
|
ELSE '1970-01-01'::timestamp
|
||||||
|
END DESC,
|
||||||
|
mi.created_at DESC
|
||||||
|
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||||
|
|
||||||
|
|
||||||
-- name: UpdateMediaItem :one
|
-- name: UpdateMediaItem :one
|
||||||
UPDATE media_items SET
|
UPDATE media_items SET
|
||||||
title = $2,
|
title = $2,
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ func SetupRoutes(g *echo.Group, db *database.Queries) *Handler {
|
|||||||
|
|
||||||
// Media item routes (new library system)
|
// Media item routes (new library system)
|
||||||
g.GET("/media-items", h.ListMediaItems)
|
g.GET("/media-items", h.ListMediaItems)
|
||||||
|
g.GET("/media-items/filtered", h.ListMediaItemsFiltered)
|
||||||
g.GET("/media-items/search", h.SearchMediaItems)
|
g.GET("/media-items/search", h.SearchMediaItems)
|
||||||
g.GET("/media-items/:id", h.GetMediaItem)
|
g.GET("/media-items/:id", h.GetMediaItem)
|
||||||
g.POST("/media-items/:id/rating", h.CreateMediaRating)
|
g.POST("/media-items/:id/rating", h.CreateMediaRating)
|
||||||
@@ -824,6 +825,7 @@ func (h *Handler) StopScheduler() {
|
|||||||
// ListMediaItems handles GET /api/media-items
|
// ListMediaItems handles GET /api/media-items
|
||||||
func (h *Handler) ListMediaItems(c echo.Context) error {
|
func (h *Handler) ListMediaItems(c echo.Context) error {
|
||||||
libraryID := c.QueryParam("library_id")
|
libraryID := c.QueryParam("library_id")
|
||||||
|
sort := c.QueryParam("sort")
|
||||||
limit, _ := strconv.Atoi(c.QueryParam("limit"))
|
limit, _ := strconv.Atoi(c.QueryParam("limit"))
|
||||||
offset, _ := strconv.Atoi(c.QueryParam("offset"))
|
offset, _ := strconv.Atoi(c.QueryParam("offset"))
|
||||||
|
|
||||||
@@ -831,6 +833,33 @@ func (h *Handler) ListMediaItems(c echo.Context) error {
|
|||||||
limit = 50
|
limit = 50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sort == "" {
|
||||||
|
sort = "created_at DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedSorts := map[string]bool{
|
||||||
|
"created_at ASC": true,
|
||||||
|
"created_at DESC": true,
|
||||||
|
"title ASC": true,
|
||||||
|
"title DESC": true,
|
||||||
|
"author ASC": true,
|
||||||
|
"author DESC": true,
|
||||||
|
"series ASC": true,
|
||||||
|
"series DESC": true,
|
||||||
|
"date_published ASC": true,
|
||||||
|
"date_published DESC": true,
|
||||||
|
"copyright_year ASC": true,
|
||||||
|
"copyright_year DESC": true,
|
||||||
|
"page_count ASC": true,
|
||||||
|
"page_count DESC": true,
|
||||||
|
"genre ASC": true,
|
||||||
|
"genre DESC": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allowedSorts[sort] {
|
||||||
|
sort = "created_at DESC"
|
||||||
|
}
|
||||||
|
|
||||||
// Enforce maximum limit
|
// Enforce maximum limit
|
||||||
if limit > maxPaginationLimit {
|
if limit > maxPaginationLimit {
|
||||||
limit = maxPaginationLimit
|
limit = maxPaginationLimit
|
||||||
@@ -846,7 +875,12 @@ func (h *Handler) ListMediaItems(c echo.Context) error {
|
|||||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
||||||
}
|
}
|
||||||
|
|
||||||
items, err := h.db.ListMediaItemsByLibrary(c.Request().Context(), pgtype.UUID{Bytes: libUUID, Valid: true})
|
items, err := h.db.ListMediaItemsSorted(c.Request().Context(), database.ListMediaItemsSortedParams{
|
||||||
|
LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true},
|
||||||
|
Sort: pgtype.Text{String: sort, Valid: true},
|
||||||
|
Limit: pgtype.Int4{Int32: int32(limit), Valid: true},
|
||||||
|
Offset: pgtype.Int4{Int32: int32(offset), Valid: true},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
}
|
}
|
||||||
@@ -884,6 +918,66 @@ func (h *Handler) GetMediaItem(c echo.Context) error {
|
|||||||
return c.JSON(http.StatusOK, item)
|
return c.JSON(http.StatusOK, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListMediaItemsFiltered handles GET /api/media-items/filtered
|
||||||
|
func (h *Handler) ListMediaItemsFiltered(c echo.Context) error {
|
||||||
|
userID := c.Get("user_id").(string)
|
||||||
|
libraryID := c.QueryParam("library_id")
|
||||||
|
sort := c.QueryParam("sort")
|
||||||
|
limit, _ := strconv.Atoi(c.QueryParam("limit"))
|
||||||
|
offset, _ := strconv.Atoi(c.QueryParam("offset"))
|
||||||
|
|
||||||
|
authorFilter := c.QueryParam("author_filter")
|
||||||
|
seriesFilter := c.QueryParam("series_filter")
|
||||||
|
genreFilter := c.QueryParam("genre_filter")
|
||||||
|
languageFilter := c.QueryParam("language_filter")
|
||||||
|
yearMin, _ := strconv.Atoi(c.QueryParam("year_min"))
|
||||||
|
yearMax, _ := strconv.Atoi(c.QueryParam("year_max"))
|
||||||
|
hasCover, _ := strconv.ParseBool(c.QueryParam("has_cover"))
|
||||||
|
|
||||||
|
if limit == 0 {
|
||||||
|
limit = 50
|
||||||
|
}
|
||||||
|
|
||||||
|
if sort == "" {
|
||||||
|
sort = "created_at DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce maximum limit
|
||||||
|
if limit > maxPaginationLimit {
|
||||||
|
limit = maxPaginationLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
libUUID, err := uuid.Parse(libraryID)
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"})
|
||||||
|
}
|
||||||
|
|
||||||
|
userUUID, err := uuid.Parse(userID)
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid user id"})
|
||||||
|
}
|
||||||
|
|
||||||
|
items, err := h.db.ListMediaItemsFiltered(c.Request().Context(), database.ListMediaItemsFilteredParams{
|
||||||
|
LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true},
|
||||||
|
UserID: pgtype.UUID{Bytes: userUUID, Valid: true},
|
||||||
|
AuthorFilter: pgtype.Text{String: authorFilter, Valid: true},
|
||||||
|
SeriesFilter: pgtype.Text{String: seriesFilter, Valid: true},
|
||||||
|
GenreFilter: pgtype.Text{String: genreFilter, Valid: true},
|
||||||
|
LanguageFilter: pgtype.Text{String: languageFilter, Valid: true},
|
||||||
|
YearMin: pgtype.Int4{Int32: int32(yearMin), Valid: true},
|
||||||
|
YearMax: pgtype.Int4{Int32: int32(yearMax), Valid: true},
|
||||||
|
HasCover: pgtype.Bool{Bool: hasCover, Valid: true},
|
||||||
|
Sort: pgtype.Text{String: sort, Valid: true},
|
||||||
|
Limit: pgtype.Int4{Int32: int32(limit), Valid: true},
|
||||||
|
Offset: pgtype.Int4{Int32: int32(offset), Valid: true},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, map[string]interface{}{"data": items})
|
||||||
|
}
|
||||||
|
|
||||||
// CreateMediaRating handles POST /api/media-items/:id/rating
|
// CreateMediaRating handles POST /api/media-items/:id/rating
|
||||||
func (h *Handler) CreateMediaRating(c echo.Context) error {
|
func (h *Handler) CreateMediaRating(c echo.Context) error {
|
||||||
userID := c.Get("user_id").(string)
|
userID := c.Get("user_id").(string)
|
||||||
|
|||||||
Reference in New Issue
Block a user