From d0460885ff844431e2f391338c81380b4d3b48cd Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sat, 16 May 2026 19:30:27 -0400 Subject: [PATCH] feat(db): add imported_at column to media_items for accurate "Recently Added" sorting The created_at column stores file modification time (intentional for preserving original metadata), but this makes 'Recently Added' sorting unreliable for imported files. Add imported_at column that records the actual database insert timestamp. Changes: - Add imported_at TIMESTAMPTZ column to media_items (nullable) - Update GetRecentlyAddedItems to sort by imported_at DESC NULLS LAST first - Add ReassignLibraries and ReassignMediaItems queries for admin deletion handover - Add SyncLibraryTypeExtensions query for startup extension sync - Update all media_items SELECT queries to include imported_at column --- database/schema/schema.sql | 1 + internal/database/models.go | 1 + internal/database/querier.go | 6 + internal/database/queries.sql.go | 225 ++++++++++++++++++++++---- internal/database/queries/queries.sql | 34 +++- 5 files changed, 234 insertions(+), 33 deletions(-) diff --git a/database/schema/schema.sql b/database/schema/schema.sql index 2dd96dd..8318fcb 100644 --- a/database/schema/schema.sql +++ b/database/schema/schema.sql @@ -123,6 +123,7 @@ CREATE TABLE IF NOT EXISTS media_items ( google_books_id VARCHAR(100), -- Google Books identifier added_by_admin_id UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + imported_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), -- Universal Sync Format Detection format_group VARCHAR(20) NOT NULL DEFAULT 'reflowable', diff --git a/internal/database/models.go b/internal/database/models.go index 3fb239b..3d8a94b 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -239,6 +239,7 @@ type MediaItems struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` diff --git a/internal/database/querier.go b/internal/database/querier.go index 7e50a2f..a467867 100644 --- a/internal/database/querier.go +++ b/internal/database/querier.go @@ -172,6 +172,8 @@ type Querier interface { GetDistinctSeries(ctx context.Context, arg GetDistinctSeriesParams) ([]GetDistinctSeriesRow, error) GetDistinctSeriesCount(ctx context.Context, libraryID pgtype.UUID) (int32, error) GetFailedSyncQueueItems(ctx context.Context, limit int32) ([]SyncQueue, error) + GetFirstAdmin(ctx context.Context) (pgtype.UUID, error) + GetFirstAdminExclude(ctx context.Context, id pgtype.UUID) (GetFirstAdminExcludeRow, error) GetKoboEntitlementByContentId(ctx context.Context, arg GetKoboEntitlementByContentIdParams) (GetKoboEntitlementByContentIdRow, error) GetKoboEntitlementByEntitlementId(ctx context.Context, arg GetKoboEntitlementByEntitlementIdParams) (GetKoboEntitlementByEntitlementIdRow, error) GetKoboEntitlementsForDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboEntitlementsForDeviceRow, error) @@ -182,6 +184,7 @@ type Querier interface { GetKoboShelvesByCollection(ctx context.Context, arg GetKoboShelvesByCollectionParams) ([]GetKoboShelvesByCollectionRow, error) GetLibrary(ctx context.Context, id pgtype.UUID) (GetLibraryRow, error) GetLibraryByFolder(ctx context.Context, folderPath string) (GetLibraryByFolderRow, error) + GetLibraryByFolderPathPrefix(ctx context.Context, folderPath string) (GetLibraryByFolderPathPrefixRow, error) GetLibraryFolders(ctx context.Context, libraryID pgtype.UUID) ([]LibraryFolders, error) GetLibraryItems(ctx context.Context, libraryID pgtype.UUID) ([]MediaItems, error) GetLibraryType(ctx context.Context, id pgtype.UUID) (LibraryTypes, error) @@ -301,6 +304,8 @@ type Querier interface { ListUsers(ctx context.Context) ([]ListUsersRow, error) // Query media items by multiple identifiers with confidence scoring QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMediaItemsByIdentifiersParams) ([]QueryMediaItemsByIdentifiersRow, error) + ReassignLibraries(ctx context.Context, arg ReassignLibrariesParams) error + ReassignMediaItems(ctx context.Context, arg ReassignMediaItemsParams) error // Remove book from collection RemoveBookFromCollection(ctx context.Context, arg RemoveBookFromCollectionParams) error RemoveBookFromKoboShelf(ctx context.Context, arg RemoveBookFromKoboShelfParams) error @@ -326,6 +331,7 @@ type Querier interface { SetLibraryVisibility(ctx context.Context, arg SetLibraryVisibilityParams) (LibraryVisibility, error) // Set system config SetSystemConfig(ctx context.Context, arg SetSystemConfigParams) (SystemConfig, error) + SyncLibraryTypeExtensions(ctx context.Context, arg SyncLibraryTypeExtensionsParams) error // Update collection UpdateCollection(ctx context.Context, arg UpdateCollectionParams) (Collections, error) UpdateDashboardPreferences(ctx context.Context, arg UpdateDashboardPreferencesParams) (UserDashboardPreferences, error) diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index 9599d30..b65476c 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -651,9 +651,9 @@ func (q *Queries) CreateMediaHighlight(ctx context.Context, arg CreateMediaHighl } 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, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, library_type_name) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43) -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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence +INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, library_type_name) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44) +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence ` type CreateMediaItemParams struct { @@ -685,6 +685,7 @@ type CreateMediaItemParams struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"` MangaType pgtype.Text `db:"manga_type" json:"manga_type"` ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"` SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"` @@ -733,6 +734,7 @@ func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams arg.GoogleBooksID, arg.AddedByAdminID, arg.CreatedAt, + arg.ImportedAt, arg.MangaType, arg.ReadingDirection, arg.SeriesCount, @@ -778,6 +780,7 @@ func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -1938,7 +1941,7 @@ func (q *Queries) GetAnnotationsForBook(ctx context.Context, arg GetAnnotationsF } const GetBooksByTag = `-- name: GetBooksByTag :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE library_id = $1 AND tags @> ARRAY[$2::text] ORDER BY title ASC ` @@ -1985,6 +1988,7 @@ func (q *Queries) GetBooksByTag(ctx context.Context, arg GetBooksByTagParams) ([ &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -2109,7 +2113,7 @@ func (q *Queries) GetCollectionItems(ctx context.Context, collectionID pgtype.UU } const GetCollectionItemsForDashboard = `-- name: GetCollectionItemsForDashboard :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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, ci.excluded FROM media_items mi +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, ci.excluded FROM media_items mi INNER JOIN collection_items ci ON ci.media_item_id = mi.id WHERE ci.collection_id = $1 AND mi.library_id = $2 @@ -2151,6 +2155,7 @@ type GetCollectionItemsForDashboardRow struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` @@ -2224,6 +2229,7 @@ func (q *Queries) GetCollectionItemsForDashboard(ctx context.Context, arg GetCol &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -2401,7 +2407,7 @@ func (q *Queries) GetCollectionsForBook(ctx context.Context, mediaItemID pgtype. } const GetContinueReadingItems = `-- name: GetContinueReadingItems :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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi INNER JOIN ( SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at FROM reading_progress @@ -2459,6 +2465,7 @@ func (q *Queries) GetContinueReadingItems(ctx context.Context, arg GetContinueRe &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -2517,7 +2524,7 @@ WITH user_series_progress AS ( GROUP BY mi.series ), next_books AS ( - SELECT DISTINCT ON (mi.series) 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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, + SELECT DISTINCT ON (mi.series) 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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, usp.last_read_at FROM media_items mi JOIN user_series_progress usp ON mi.series = usp.series @@ -2525,7 +2532,7 @@ next_books AS ( AND (mi.series_number > usp.max_read_number OR usp.max_read_number IS NULL) ORDER BY mi.series, mi.series_number ASC NULLS LAST ) -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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence, last_read_at FROM next_books +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence, last_read_at FROM next_books ORDER BY last_read_at DESC NULLS LAST LIMIT $3 ` @@ -2564,6 +2571,7 @@ type GetContinueSeriesItemsRow struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` @@ -2637,6 +2645,7 @@ func (q *Queries) GetContinueSeriesItems(ctx context.Context, arg GetContinueSer &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -3203,6 +3212,58 @@ func (q *Queries) GetFailedSyncQueueItems(ctx context.Context, limit int32) ([]S return items, nil } +const GetFirstAdmin = `-- name: GetFirstAdmin :one +SELECT id FROM users +WHERE role = 'admin' +ORDER BY created_at ASC +LIMIT 1 +` + +func (q *Queries) GetFirstAdmin(ctx context.Context) (pgtype.UUID, error) { + row := q.db.QueryRow(ctx, GetFirstAdmin) + var id pgtype.UUID + err := row.Scan(&id) + return id, err +} + +const GetFirstAdminExclude = `-- name: GetFirstAdminExclude :one +SELECT id, email, username, theme, first_name, last_name, role, max_devices, created_at, updated_at FROM users +WHERE role = 'admin' AND id != $1 +ORDER BY created_at ASC +LIMIT 1 +` + +type GetFirstAdminExcludeRow struct { + ID pgtype.UUID `db:"id" json:"id"` + Email string `db:"email" json:"email"` + Username string `db:"username" json:"username"` + Theme pgtype.Text `db:"theme" json:"theme"` + FirstName pgtype.Text `db:"first_name" json:"first_name"` + LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` + MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` +} + +func (q *Queries) GetFirstAdminExclude(ctx context.Context, id pgtype.UUID) (GetFirstAdminExcludeRow, error) { + row := q.db.QueryRow(ctx, GetFirstAdminExclude, id) + var i GetFirstAdminExcludeRow + err := row.Scan( + &i.ID, + &i.Email, + &i.Username, + &i.Theme, + &i.FirstName, + &i.LastName, + &i.Role, + &i.MaxDevices, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + const GetKoboEntitlementByContentId = `-- name: GetKoboEntitlementByContentId :one SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path FROM kobo_entitlements ke @@ -3652,6 +3713,43 @@ func (q *Queries) GetLibraryByFolder(ctx context.Context, folderPath string) (Ge return i, err } +const GetLibraryByFolderPathPrefix = `-- name: GetLibraryByFolderPathPrefix :one +SELECT lf.library_id, lf.folder_path, l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at FROM library_folders lf +JOIN libraries l ON lf.library_id = l.id +WHERE $1 LIKE lf.folder_path || '%' +ORDER BY LENGTH(lf.folder_path) DESC +LIMIT 1 +` + +type GetLibraryByFolderPathPrefixRow struct { + LibraryID pgtype.UUID `db:"library_id" json:"library_id"` + FolderPath string `db:"folder_path" json:"folder_path"` + ID pgtype.UUID `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Description pgtype.Text `db:"description" json:"description"` + LibraryTypeID pgtype.UUID `db:"library_type_id" json:"library_type_id"` + CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` +} + +func (q *Queries) GetLibraryByFolderPathPrefix(ctx context.Context, folderPath string) (GetLibraryByFolderPathPrefixRow, error) { + row := q.db.QueryRow(ctx, GetLibraryByFolderPathPrefix, folderPath) + var i GetLibraryByFolderPathPrefixRow + err := row.Scan( + &i.LibraryID, + &i.FolderPath, + &i.ID, + &i.Name, + &i.Description, + &i.LibraryTypeID, + &i.CreatedByAdminID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + const GetLibraryFolders = `-- name: GetLibraryFolders :many SELECT id, library_id, folder_path, created_at FROM library_folders WHERE library_id = $1 ORDER BY created_at ` @@ -3682,7 +3780,7 @@ func (q *Queries) GetLibraryFolders(ctx context.Context, libraryID pgtype.UUID) } const GetLibraryItems = `-- name: GetLibraryItems :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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi WHERE mi.library_id = $1 ORDER BY mi.created_at DESC ` @@ -3724,6 +3822,7 @@ func (q *Queries) GetLibraryItems(ctx context.Context, libraryID pgtype.UUID) ([ &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4029,7 +4128,7 @@ func (q *Queries) GetMediaHighlights(ctx context.Context, arg GetMediaHighlights } 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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence 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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE id = $1 ` func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error) { @@ -4063,6 +4162,7 @@ func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4101,7 +4201,7 @@ func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, } 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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 AND library_id = $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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 AND library_id = $2 ` type GetMediaItemByFilePathParams struct { @@ -4140,6 +4240,7 @@ func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemBy &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4178,7 +4279,7 @@ func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemBy } const GetMediaItemByFilePathAnyLibrary = `-- name: GetMediaItemByFilePathAnyLibrary :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 LIMIT 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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 LIMIT 1 ` func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath string) (MediaItems, error) { @@ -4212,6 +4313,7 @@ func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4251,7 +4353,7 @@ func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath const GetMediaItemByFilePathForSync = `-- name: GetMediaItemByFilePathForSync :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence 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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 ` // ============================================ @@ -4288,6 +4390,7 @@ func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath st &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4326,7 +4429,7 @@ func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath st } const GetMediaItemByKoboContentId = `-- name: GetMediaItemByKoboContentId :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE kobo_content_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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE kobo_content_id = $1 ` func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID pgtype.Text) (MediaItems, error) { @@ -4360,6 +4463,7 @@ func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4398,7 +4502,7 @@ func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID } const GetMediaItemByOPFIdentifier = `-- name: GetMediaItemByOPFIdentifier :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_identifier = $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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_identifier = $1 ` // Get media item by OPF identifier @@ -4433,6 +4537,7 @@ func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4471,7 +4576,7 @@ func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier } const GetMediaItemByOPFUUID = `-- name: GetMediaItemByOPFUUID :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_uuid = $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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_uuid = $1 ` // Get media item by OPF UUID @@ -4506,6 +4611,7 @@ func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4544,7 +4650,7 @@ func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text } const GetMediaItemBySHA256 = `-- name: GetMediaItemBySHA256 :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $1 ` // Get media item by SHA-256 hash @@ -4579,6 +4685,7 @@ func (q *Queries) GetMediaItemBySHA256(ctx context.Context, fileSha256 pgtype.Te &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -4859,7 +4966,7 @@ func (q *Queries) GetNextRetryTime(ctx context.Context) (interface{}, error) { } const GetNotStartedItems = `-- name: GetNotStartedItems :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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi WHERE mi.library_id = $1 AND NOT EXISTS ( SELECT 1 FROM reading_progress rp @@ -4914,6 +5021,7 @@ func (q *Queries) GetNotStartedItems(ctx context.Context, arg GetNotStartedItems &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -5257,9 +5365,9 @@ func (q *Queries) GetReadingSpeed(ctx context.Context, arg GetReadingSpeedParams } const GetRecentlyAddedItems = `-- name: GetRecentlyAddedItems :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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi WHERE mi.library_id = $1 -ORDER BY mi.created_at DESC +ORDER BY mi.imported_at DESC NULLS LAST, mi.created_at DESC LIMIT $2 ` @@ -5305,6 +5413,7 @@ func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAdde &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -5350,7 +5459,7 @@ func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAdde } const GetRecentlyReadItems = `-- name: GetRecentlyReadItems :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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi INNER JOIN ( SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at FROM reading_progress @@ -5406,6 +5515,7 @@ func (q *Queries) GetRecentlyReadItems(ctx context.Context, arg GetRecentlyReadI &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -5551,7 +5661,7 @@ func (q *Queries) GetSavedFilters(ctx context.Context, arg GetSavedFiltersParams } const GetSeriesBooks = `-- name: GetSeriesBooks :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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE library_id = $1 AND series = $2 ORDER BY series_number ASC NULLS LAST ` @@ -5598,6 +5708,7 @@ func (q *Queries) GetSeriesBooks(ctx context.Context, arg GetSeriesBooksParams) &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -7143,7 +7254,7 @@ func (q *Queries) ListLibraries(ctx context.Context) ([]ListLibrariesRow, error) } 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.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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 @@ -7183,6 +7294,7 @@ type ListMediaItemsRow struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` @@ -7257,6 +7369,7 @@ func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams) &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -7304,7 +7417,7 @@ func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams) } 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.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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 @@ -7340,6 +7453,7 @@ type ListMediaItemsByLibraryRow struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` @@ -7414,6 +7528,7 @@ func (q *Queries) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype. &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -7461,7 +7576,7 @@ func (q *Queries) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype. } 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.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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 @@ -7570,6 +7685,7 @@ type ListMediaItemsSortedRow struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` @@ -7649,6 +7765,7 @@ func (q *Queries) ListMediaItemsSorted(ctx context.Context, arg ListMediaItemsSo &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -8145,6 +8262,34 @@ func (q *Queries) QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMed return items, nil } +const ReassignLibraries = `-- name: ReassignLibraries :exec +UPDATE libraries SET created_by_admin_id = $2, updated_at = NOW() WHERE created_by_admin_id = $1 +` + +type ReassignLibrariesParams struct { + CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"` + CreatedByAdminID_2 pgtype.UUID `db:"created_by_admin_id_2" json:"created_by_admin_id_2"` +} + +func (q *Queries) ReassignLibraries(ctx context.Context, arg ReassignLibrariesParams) error { + _, err := q.db.Exec(ctx, ReassignLibraries, arg.CreatedByAdminID, arg.CreatedByAdminID_2) + return err +} + +const ReassignMediaItems = `-- name: ReassignMediaItems :exec +UPDATE media_items SET added_by_admin_id = $2 WHERE added_by_admin_id = $1 +` + +type ReassignMediaItemsParams struct { + AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"` + AddedByAdminID_2 pgtype.UUID `db:"added_by_admin_id_2" json:"added_by_admin_id_2"` +} + +func (q *Queries) ReassignMediaItems(ctx context.Context, arg ReassignMediaItemsParams) error { + _, err := q.db.Exec(ctx, ReassignMediaItems, arg.AddedByAdminID, arg.AddedByAdminID_2) + return err +} + const RemoveBookFromCollection = `-- name: RemoveBookFromCollection :exec DELETE FROM collection_items WHERE collection_id = $1 AND media_item_id = $2 ` @@ -8534,7 +8679,7 @@ func (q *Queries) SearchLanguageValues(ctx context.Context, arg SearchLanguageVa } 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.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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 +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.imported_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.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, 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 @@ -8596,6 +8741,7 @@ type SearchMediaItemsRow struct { 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"` + ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_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"` @@ -8677,6 +8823,7 @@ func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsPara &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -9228,6 +9375,20 @@ func (q *Queries) SetSystemConfig(ctx context.Context, arg SetSystemConfigParams return i, err } +const SyncLibraryTypeExtensions = `-- name: SyncLibraryTypeExtensions :exec +UPDATE library_types SET allowed_extensions = $2 WHERE name = $1 +` + +type SyncLibraryTypeExtensionsParams struct { + Name string `db:"name" json:"name"` + AllowedExtensions []string `db:"allowed_extensions" json:"allowed_extensions"` +} + +func (q *Queries) SyncLibraryTypeExtensions(ctx context.Context, arg SyncLibraryTypeExtensionsParams) error { + _, err := q.db.Exec(ctx, SyncLibraryTypeExtensions, arg.Name, arg.AllowedExtensions) + return err +} + const UpdateCollection = `-- name: UpdateCollection :one UPDATE collections SET @@ -9881,7 +10042,7 @@ UPDATE media_items SET summary = $37, updated_at = NOW() 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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence ` type UpdateMediaItemParams struct { @@ -9993,6 +10154,7 @@ func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -10034,7 +10196,7 @@ const UpdateMediaItemChapterMetadata = `-- name: UpdateMediaItemChapterMetadata UPDATE media_items SET chapter_metadata = $2, updated_at = NOW() 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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence ` type UpdateMediaItemChapterMetadataParams struct { @@ -10073,6 +10235,7 @@ func (q *Queries) UpdateMediaItemChapterMetadata(ctx context.Context, arg Update &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -10205,7 +10368,7 @@ SET hash_confidence = $5, updated_at = NOW() 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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence ` type UpdateMediaItemIdentifiersParams struct { @@ -10258,6 +10421,7 @@ func (q *Queries) UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMedi &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, @@ -10303,7 +10467,7 @@ SET entitlement_id = $2, kobo_metadata = $5, updated_at = NOW() 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, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence +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, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence ` type UpdateMediaItemKoboMetadataParams struct { @@ -10351,6 +10515,7 @@ func (q *Queries) UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMed &i.GoogleBooksID, &i.AddedByAdminID, &i.CreatedAt, + &i.ImportedAt, &i.UpdatedAt, &i.FormatGroup, &i.FormatMimetype, diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index 3fa8efe..4c3372e 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -61,6 +61,9 @@ SELECT * FROM library_types WHERE id = $1; -- name: GetLibraryTypeByName :one SELECT * FROM library_types WHERE name = $1; +-- name: SyncLibraryTypeExtensions :exec +UPDATE library_types SET allowed_extensions = $2 WHERE name = $1; + -- Libraries queries -- name: CreateLibrary :one INSERT INTO libraries (name, description, library_type_id, created_by_admin_id) @@ -105,6 +108,13 @@ SELECT lf.library_id, l.* FROM library_folders lf JOIN libraries l ON lf.library_id = l.id WHERE lf.folder_path = $1; +-- name: GetLibraryByFolderPathPrefix :one +SELECT lf.library_id, lf.folder_path, l.* FROM library_folders lf +JOIN libraries l ON lf.library_id = l.id +WHERE $1 LIKE lf.folder_path || '%' +ORDER BY LENGTH(lf.folder_path) DESC +LIMIT 1; + -- Library Visibility queries -- name: SetLibraryVisibility :one INSERT INTO library_visibility (user_id, library_id, is_visible) @@ -129,8 +139,8 @@ ORDER BY l.created_at ASC; -- Media Items queries -- 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, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, library_type_name) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43) +INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, library_type_name) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44) RETURNING *; -- name: GetMediaItem :one @@ -324,6 +334,24 @@ SELECT setting_value FROM system_settings WHERE setting_key = 'default_timezone' -- name: CountUserDevices :one SELECT COUNT(*) FROM devices WHERE user_id = $1; +-- name: GetFirstAdminExclude :one +SELECT id, email, username, theme, first_name, last_name, role, max_devices, created_at, updated_at FROM users +WHERE role = 'admin' AND id != $1 +ORDER BY created_at ASC +LIMIT 1; + +-- name: GetFirstAdmin :one +SELECT id FROM users +WHERE role = 'admin' +ORDER BY created_at ASC +LIMIT 1; + +-- name: ReassignLibraries :exec +UPDATE libraries SET created_by_admin_id = $2, updated_at = NOW() WHERE created_by_admin_id = $1; + +-- name: ReassignMediaItems :exec +UPDATE media_items SET added_by_admin_id = $2 WHERE added_by_admin_id = $1; + -- name: DeleteUser :exec DELETE FROM users WHERE id = $1; @@ -1878,7 +1906,7 @@ LIMIT $3; -- name: GetRecentlyAddedItems :many SELECT mi.* FROM media_items mi WHERE mi.library_id = $1 -ORDER BY mi.created_at DESC +ORDER BY mi.imported_at DESC NULLS LAST, mi.created_at DESC LIMIT $2; -- name: GetRecentlyReadItems :many