diff --git a/internal/database/querier.go b/internal/database/querier.go index 643df7b..f02c81e 100644 --- a/internal/database/querier.go +++ b/internal/database/querier.go @@ -288,7 +288,6 @@ type Querier interface { SearchLanguageValues(ctx context.Context, arg SearchLanguageValuesParams) ([]SearchLanguageValuesRow, error) // Search Media Items queries SearchMediaItems(ctx context.Context, arg SearchMediaItemsParams) ([]SearchMediaItemsRow, error) - SearchMediaItemsFuzzy(ctx context.Context, arg SearchMediaItemsFuzzyParams) ([]SearchMediaItemsFuzzyRow, error) SearchMediaItemsUnified(ctx context.Context, arg SearchMediaItemsUnifiedParams) ([]SearchMediaItemsUnifiedRow, error) SearchSeriesValues(ctx context.Context, arg SearchSeriesValuesParams) ([]SearchSeriesValuesRow, error) // Library Visibility queries diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index 939d698..a715c2e 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -6878,7 +6878,7 @@ LIMIT $5 OFFSET $4 ` type SearchAuthorValuesParams struct { - SearchQuery interface{} `db:"search_query" json:"search_query"` + SearchQuery pgtype.Text `db:"search_query" json:"search_query"` UserID pgtype.UUID `db:"user_id" json:"user_id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Offset pgtype.Int4 `db:"offset" json:"offset"` @@ -6936,7 +6936,7 @@ LIMIT $5 OFFSET $4 ` type SearchGenreValuesParams struct { - SearchQuery interface{} `db:"search_query" json:"search_query"` + SearchQuery pgtype.Text `db:"search_query" json:"search_query"` UserID pgtype.UUID `db:"user_id" json:"user_id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Offset pgtype.Int4 `db:"offset" json:"offset"` @@ -6994,7 +6994,7 @@ LIMIT $5 OFFSET $4 ` type SearchLanguageValuesParams struct { - SearchQuery interface{} `db:"search_query" json:"search_query"` + SearchQuery pgtype.Text `db:"search_query" json:"search_query"` UserID pgtype.UUID `db:"user_id" json:"user_id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Offset pgtype.Int4 `db:"offset" json:"offset"` @@ -7191,187 +7191,15 @@ func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsPara return items, nil } -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.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, 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 COALESCE(lv.is_visible, true) = true - AND ($2 IS NULL OR mi.library_id = $2) - AND ( - word_similarity($3, mi.title) > 0.3 OR - word_similarity($3, COALESCE(mi.author, '')) > 0.3 OR - word_similarity($3, COALESCE(mi.series, '')) > 0.3 OR - EXISTS ( - SELECT 1 FROM unnest(mi.tags_search) AS tag - WHERE word_similarity($3, tag) > 0.3 - LIMIT 1 - ) OR - EXISTS ( - SELECT 1 FROM unnest(mi.contributors_search) AS contributor - WHERE word_similarity($3, contributor) > 0.3 - LIMIT 1 - ) - ) - ORDER BY - GREATEST( - word_similarity($3, mi.title), - word_similarity($3, COALESCE(mi.author, '')), - word_similarity($3, COALESCE(mi.series, '')), - COALESCE( - (SELECT MAX(word_similarity($3, tag)) - FROM unnest(mi.tags_search) AS tag), - 0 - ), - COALESCE( - (SELECT MAX(word_similarity($3, contributor)) - FROM unnest(mi.contributors_search) AS contributor), - 0 - ) - ) DESC, - mi.title ASC - LIMIT $5 OFFSET $4 -` - -type SearchMediaItemsFuzzyParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID interface{} `db:"library_id" json:"library_id"` - SearchQuery interface{} `db:"search_query" json:"search_query"` - Offset pgtype.Int4 `db:"offset" json:"offset"` - Limit pgtype.Int4 `db:"limit" json:"limit"` -} - -type SearchMediaItemsFuzzyRow 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 []string `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 []string `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"` - Genre pgtype.Text `db:"genre" json:"genre"` - CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"` - 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"` - 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"` - FormatGroup string `db:"format_group" json:"format_group"` - FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"` - IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"` - HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"` - TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"` - ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"` - EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` - KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"` - KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"` - TagsSearch []string `db:"tags_search" json:"tags_search"` - ContributorsSearch []string `db:"contributors_search" json:"contributors_search"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"` - OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"` - HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"` - LibraryName string `db:"library_name" json:"library_name"` - LibraryTypeName string `db:"library_type_name" json:"library_type_name"` -} - -func (q *Queries) SearchMediaItemsFuzzy(ctx context.Context, arg SearchMediaItemsFuzzyParams) ([]SearchMediaItemsFuzzyRow, error) { - rows, err := q.db.Query(ctx, SearchMediaItemsFuzzy, - arg.UserID, - arg.LibraryID, - arg.SearchQuery, - arg.Offset, - arg.Limit, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SearchMediaItemsFuzzyRow{} - for rows.Next() { - var i SearchMediaItemsFuzzyRow - 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.Genre, - &i.CopyrightYear, - &i.GoodreadsID, - &i.OpenlibraryID, - &i.GoogleBooksID, - &i.AddedByAdminID, - &i.CreatedAt, - &i.UpdatedAt, - &i.FormatGroup, - &i.FormatMimetype, - &i.IsReflowable, - &i.HasFixedLayout, - &i.TotalCharacters, - &i.ChapterCount, - &i.EntitlementID, - &i.RevisionNumber, - &i.KoboContentID, - &i.KoboMetadata, - &i.TagsSearch, - &i.ContributorsSearch, - &i.FileSha256, - &i.OpfIdentifier, - &i.OpfUuid, - &i.HashConfidence, - &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 SearchMediaItemsUnified = `-- name: SearchMediaItemsUnified :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.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, 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 COALESCE(lv.is_visible, true) = true - AND mi.library_id = $2 + WHERE COALESCE(lv.is_visible, true) = true + AND ($2::uuid IS NULL + OR mi.library_id = $2::uuid) -- Fuzzy author filter AND ($3 = '' OR word_similarity($3, COALESCE(mi.author, '')) > 0.3) -- Fuzzy series filter @@ -7636,7 +7464,7 @@ LIMIT $5 OFFSET $4 ` type SearchSeriesValuesParams struct { - SearchQuery interface{} `db:"search_query" json:"search_query"` + SearchQuery pgtype.Text `db:"search_query" json:"search_query"` UserID pgtype.UUID `db:"user_id" json:"user_id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Offset pgtype.Int4 `db:"offset" json:"offset"` diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index f0a228e..08ad311 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -372,56 +372,15 @@ LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = sqlc.na mi.title ASC LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); --- name: SearchMediaItemsFuzzy :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 COALESCE(lv.is_visible, true) = true - AND (sqlc.narg('library_id') IS NULL OR mi.library_id = sqlc.narg('library_id')) - AND ( - word_similarity(sqlc.narg('search_query'), mi.title) > 0.3 OR - word_similarity(sqlc.narg('search_query'), COALESCE(mi.author, '')) > 0.3 OR - word_similarity(sqlc.narg('search_query'), COALESCE(mi.series, '')) > 0.3 OR - EXISTS ( - SELECT 1 FROM unnest(mi.tags_search) AS tag - WHERE word_similarity(sqlc.narg('search_query'), tag) > 0.3 - LIMIT 1 - ) OR - EXISTS ( - SELECT 1 FROM unnest(mi.contributors_search) AS contributor - WHERE word_similarity(sqlc.narg('search_query'), contributor) > 0.3 - LIMIT 1 - ) - ) - ORDER BY - GREATEST( - word_similarity(sqlc.narg('search_query'), mi.title), - word_similarity(sqlc.narg('search_query'), COALESCE(mi.author, '')), - word_similarity(sqlc.narg('search_query'), COALESCE(mi.series, '')), - COALESCE( - (SELECT MAX(word_similarity(sqlc.narg('search_query'), tag)) - FROM unnest(mi.tags_search) AS tag), - 0 - ), - COALESCE( - (SELECT MAX(word_similarity(sqlc.narg('search_query'), contributor)) - FROM unnest(mi.contributors_search) AS contributor), - 0 - ) - ) DESC, - mi.title ASC - LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); - -- name: SearchMediaItemsUnified :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 COALESCE(lv.is_visible, true) = true - AND mi.library_id = sqlc.narg('library_id') + WHERE COALESCE(lv.is_visible, true) = true + AND (sqlc.narg('library_id')::uuid IS NULL + OR mi.library_id = sqlc.narg('library_id')::uuid) -- Fuzzy author filter AND (sqlc.narg('author_filter') = '' OR word_similarity(sqlc.narg('author_filter'), COALESCE(mi.author, '')) > 0.3) -- Fuzzy series filter