diff --git a/internal/database/queries.sql.go.backup b/internal/database/queries.sql.go.backup deleted file mode 100644 index fc01487..0000000 --- a/internal/database/queries.sql.go.backup +++ /dev/null @@ -1,8689 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.30.0 -// source: queries.sql - -package database - -import ( - "context" - - "github.com/jackc/pgx/v5/pgtype" -) - -const AddBookToCollection = `-- name: AddBookToCollection :one - -INSERT INTO collection_items (collection_id, media_item_id, added_by_user_id) -VALUES ($1, $2, $3) -ON CONFLICT (collection_id, media_item_id) DO NOTHING -RETURNING id, collection_id, media_item_id, added_at, added_by_user_id, excluded -` - -type AddBookToCollectionParams struct { - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - AddedByUserID pgtype.UUID `db:"added_by_user_id" json:"added_by_user_id"` -} - -// COLLECTION ITEMS QUERIES -// Add book to collection -func (q *Queries) AddBookToCollection(ctx context.Context, arg AddBookToCollectionParams) (CollectionItems, error) { - row := q.db.QueryRow(ctx, AddBookToCollection, arg.CollectionID, arg.MediaItemID, arg.AddedByUserID) - var i CollectionItems - err := row.Scan( - &i.ID, - &i.CollectionID, - &i.MediaItemID, - &i.AddedAt, - &i.AddedByUserID, - &i.Excluded, - ) - return i, err -} - -const AddBookToKoboShelf = `-- name: AddBookToKoboShelf :one - -INSERT INTO kobo_shelves (device_id, media_item_id, shelf_name, shelf_position) -VALUES ($1, $2, $3, $4) -ON CONFLICT (device_id, media_item_id) -DO UPDATE SET - shelf_name = EXCLUDED.shelf_name, - shelf_position = EXCLUDED.shelf_position, - last_synced_at = NOW() -RETURNING id, device_id, media_item_id, shelf_name, shelf_position, added_at, last_synced_at, collection_id, position_in_collection -` - -type AddBookToKoboShelfParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"` - ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"` -} - -// ============================================ -// KOBO SHELF MANAGEMENT QUERIES -// ============================================ -func (q *Queries) AddBookToKoboShelf(ctx context.Context, arg AddBookToKoboShelfParams) (KoboShelves, error) { - row := q.db.QueryRow(ctx, AddBookToKoboShelf, - arg.DeviceID, - arg.MediaItemID, - arg.ShelfName, - arg.ShelfPosition, - ) - var i KoboShelves - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.ShelfName, - &i.ShelfPosition, - &i.AddedAt, - &i.LastSyncedAt, - &i.CollectionID, - &i.PositionInCollection, - ) - return i, err -} - -const AddLibraryFolder = `-- name: AddLibraryFolder :one -INSERT INTO library_folders (library_id, folder_path) VALUES ($1, $2) RETURNING id, library_id, folder_path, created_at -` - -type AddLibraryFolderParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - FolderPath string `db:"folder_path" json:"folder_path"` -} - -// Library Folders queries -func (q *Queries) AddLibraryFolder(ctx context.Context, arg AddLibraryFolderParams) (LibraryFolders, error) { - row := q.db.QueryRow(ctx, AddLibraryFolder, arg.LibraryID, arg.FolderPath) - var i LibraryFolders - err := row.Scan( - &i.ID, - &i.LibraryID, - &i.FolderPath, - &i.CreatedAt, - ) - return i, err -} - -const BulkUpdateFormatGroups = `-- name: BulkUpdateFormatGroups :exec -UPDATE media_items m -SET - format_group = detect_format_group(m.mime_type, m.file_path), - format_mimetype = m.mime_type, - is_reflowable = (detect_format_group(m.mime_type, m.file_path) = 'reflowable'), - has_fixed_layout = (detect_format_group(m.mime_type, m.file_path) IN ('fixed_layout', 'comic_archive')), - updated_at = NOW() -WHERE m.format_group IS NULL OR m.format_group = 'unknown' -` - -// Bulk update format group for all media items -func (q *Queries) BulkUpdateFormatGroups(ctx context.Context) error { - _, err := q.db.Exec(ctx, BulkUpdateFormatGroups) - return err -} - -const BulkUpdateProgressFromSync = `-- name: BulkUpdateProgressFromSync :many -SELECT bulk_update_progress_from_koreader FROM bulk_update_progress_from_koreader($1::uuid, $2::jsonb) -` - -type BulkUpdateProgressFromSyncParams struct { - Column1 pgtype.UUID `db:"column_1" json:"column_1"` - Column2 []byte `db:"column_2" json:"column_2"` -} - -func (q *Queries) BulkUpdateProgressFromSync(ctx context.Context, arg BulkUpdateProgressFromSyncParams) ([]interface{}, error) { - rows, err := q.db.Query(ctx, BulkUpdateProgressFromSync, arg.Column1, arg.Column2) - if err != nil { - return nil, err - } - defer rows.Close() - items := []interface{}{} - for rows.Next() { - var bulk_update_progress_from_koreader interface{} - if err := rows.Scan(&bulk_update_progress_from_koreader); err != nil { - return nil, err - } - items = append(items, bulk_update_progress_from_koreader) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const CleanupExpiredOpdsTokens = `-- name: CleanupExpiredOpdsTokens :exec -DELETE FROM opds_tokens WHERE expires_at < NOW() -` - -// Cleanup expired OPDS tokens -func (q *Queries) CleanupExpiredOpdsTokens(ctx context.Context) error { - _, err := q.db.Exec(ctx, CleanupExpiredOpdsTokens) - return err -} - -const CleanupExpiredRefreshTokens = `-- name: CleanupExpiredRefreshTokens :exec -DELETE FROM refresh_tokens WHERE expires_at < NOW() OR (revoked_at IS NOT NULL AND revoked_at < NOW() - INTERVAL '7 days') -` - -func (q *Queries) CleanupExpiredRefreshTokens(ctx context.Context) error { - _, err := q.db.Exec(ctx, CleanupExpiredRefreshTokens) - return err -} - -const ClearDeviceSyncQueue = `-- name: ClearDeviceSyncQueue :exec -DELETE FROM sync_queue WHERE device_id = $1 -` - -func (q *Queries) ClearDeviceSyncQueue(ctx context.Context, deviceID pgtype.UUID) error { - _, err := q.db.Exec(ctx, ClearDeviceSyncQueue, deviceID) - return err -} - -const ClearKoboShelf = `-- name: ClearKoboShelf :exec -DELETE FROM kobo_shelves WHERE device_id = $1 -` - -func (q *Queries) ClearKoboShelf(ctx context.Context, deviceID pgtype.UUID) error { - _, err := q.db.Exec(ctx, ClearKoboShelf, deviceID) - return err -} - -const ClearKoboShelfByName = `-- name: ClearKoboShelfByName :exec -DELETE FROM kobo_shelves WHERE device_id = $1 AND shelf_name = $2 -` - -type ClearKoboShelfByNameParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"` -} - -func (q *Queries) ClearKoboShelfByName(ctx context.Context, arg ClearKoboShelfByNameParams) error { - _, err := q.db.Exec(ctx, ClearKoboShelfByName, arg.DeviceID, arg.ShelfName) - return err -} - -const CountUnlinkedBooks = `-- name: CountUnlinkedBooks :one -SELECT COUNT(*) as count -FROM unlinked_books -WHERE device_id = $1 AND resolved = false -` - -// Count unlinked books for a device -func (q *Queries) CountUnlinkedBooks(ctx context.Context, deviceID pgtype.UUID) (int64, error) { - row := q.db.QueryRow(ctx, CountUnlinkedBooks, deviceID) - var count int64 - err := row.Scan(&count) - return count, err -} - -const CountUserDevices = `-- name: CountUserDevices :one -SELECT COUNT(*) FROM devices WHERE user_id = $1 -` - -func (q *Queries) CountUserDevices(ctx context.Context, userID pgtype.UUID) (int64, error) { - row := q.db.QueryRow(ctx, CountUserDevices, userID) - var count int64 - err := row.Scan(&count) - return count, err -} - -const CreateCollection = `-- name: CreateCollection :one - -INSERT INTO collections (user_id, name, description, color, icon, auto_assign_rules, view_settings) -VALUES ($1, $2, $3, $4, $5, $6, $7) -RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at -` - -type CreateCollectionParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` - Description pgtype.Text `db:"description" json:"description"` - Color pgtype.Text `db:"color" json:"color"` - Icon pgtype.Text `db:"icon" json:"icon"` - AutoAssignRules []byte `db:"auto_assign_rules" json:"auto_assign_rules"` - ViewSettings []byte `db:"view_settings" json:"view_settings"` -} - -// COLLECTIONS QUERIES -// Create collection -func (q *Queries) CreateCollection(ctx context.Context, arg CreateCollectionParams) (Collections, error) { - row := q.db.QueryRow(ctx, CreateCollection, - arg.UserID, - arg.Name, - arg.Description, - arg.Color, - arg.Icon, - arg.AutoAssignRules, - arg.ViewSettings, - ) - var i Collections - err := row.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ) - return i, err -} - -const CreateDevice = `-- name: CreateDevice :one - -INSERT INTO devices (user_id, device_name, device_type, device_identifier, auth_token, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) -RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at -` - -type CreateDeviceParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - DeviceName string `db:"device_name" json:"device_name"` - DeviceType string `db:"device_type" json:"device_type"` - DeviceIdentifier string `db:"device_identifier" json:"device_identifier"` - AuthToken string `db:"auth_token" json:"auth_token"` - SyncEnabled pgtype.Bool `db:"sync_enabled" json:"sync_enabled"` - AutoSync pgtype.Bool `db:"auto_sync" json:"auto_sync"` - SyncFrequencyMinutes pgtype.Int4 `db:"sync_frequency_minutes" json:"sync_frequency_minutes"` - DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"` -} - -// ============================================ -// DEVICE MANAGEMENT & AUTH -// ============================================ -// Device Registration & Management -func (q *Queries) CreateDevice(ctx context.Context, arg CreateDeviceParams) (Devices, error) { - row := q.db.QueryRow(ctx, CreateDevice, - arg.UserID, - arg.DeviceName, - arg.DeviceType, - arg.DeviceIdentifier, - arg.AuthToken, - arg.SyncEnabled, - arg.AutoSync, - arg.SyncFrequencyMinutes, - arg.DeviceMetadata, - ) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const CreateDeviceCatalog = `-- name: CreateDeviceCatalog :one - -INSERT INTO device_catalogs (device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8) -ON CONFLICT (device_id, kobo_content_id) -DO UPDATE SET - available = EXCLUDED.available, - delivery_date = COALESCE(EXCLUDED.delivery_date, device_catalogs.delivery_date), - delivery_method = EXCLUDED.delivery_method -RETURNING id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method -` - -type CreateDeviceCatalogParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"` - KoboContentID string `db:"kobo_content_id" json:"kobo_content_id"` - ContentIDType pgtype.Text `db:"content_id_type" json:"content_id_type"` - Available pgtype.Bool `db:"available" json:"available"` - DeliveryDate pgtype.Timestamptz `db:"delivery_date" json:"delivery_date"` - DeliveryMethod pgtype.Text `db:"delivery_method" json:"delivery_method"` -} - -// DEVICE CATALOGS QUERIES -// Create device catalog entry -func (q *Queries) CreateDeviceCatalog(ctx context.Context, arg CreateDeviceCatalogParams) (DeviceCatalogs, error) { - row := q.db.QueryRow(ctx, CreateDeviceCatalog, - arg.DeviceID, - arg.MediaItemID, - arg.BookhoardUuid, - arg.KoboContentID, - arg.ContentIDType, - arg.Available, - arg.DeliveryDate, - arg.DeliveryMethod, - ) - var i DeviceCatalogs - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.BookhoardUuid, - &i.KoboContentID, - &i.ContentIDType, - &i.Available, - &i.DeliveryDate, - &i.DeliveryMethod, - ) - return i, err -} - -const CreateDeviceFileAlias = `-- name: CreateDeviceFileAlias :one - -INSERT INTO device_file_aliases (media_item_id, device_id, file_path, file_sha256, confidence_score) -VALUES ($1, $2, $3, $4, $5) -RETURNING id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at -` - -type CreateDeviceFileAliasParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - FilePath string `db:"file_path" json:"file_path"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` -} - -// DEVICE FILE ALIASES QUERIES -// Create device file alias -func (q *Queries) CreateDeviceFileAlias(ctx context.Context, arg CreateDeviceFileAliasParams) (DeviceFileAliases, error) { - row := q.db.QueryRow(ctx, CreateDeviceFileAlias, - arg.MediaItemID, - arg.DeviceID, - arg.FilePath, - arg.FileSha256, - arg.ConfidenceScore, - ) - var i DeviceFileAliases - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.DeviceID, - &i.FilePath, - &i.FileSha256, - &i.ConfidenceScore, - &i.LastSeenAt, - ) - return i, err -} - -const CreateDeviceShelfMapping = `-- name: CreateDeviceShelfMapping :one - -INSERT INTO device_shelf_mappings (collection_id, device_id, device_shelf_name, sync_direction) -VALUES ($1, $2, $3, $4) -ON CONFLICT (collection_id, device_id) -DO UPDATE SET - device_shelf_name = EXCLUDED.device_shelf_name, - sync_direction = EXCLUDED.sync_direction -RETURNING id, collection_id, device_id, device_shelf_name, sync_direction, created_at -` - -type CreateDeviceShelfMappingParams struct { - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"` - SyncDirection pgtype.Text `db:"sync_direction" json:"sync_direction"` -} - -// DEVICE SHELF MAPPINGS QUERIES -// Create device shelf mapping -func (q *Queries) CreateDeviceShelfMapping(ctx context.Context, arg CreateDeviceShelfMappingParams) (DeviceShelfMappings, error) { - row := q.db.QueryRow(ctx, CreateDeviceShelfMapping, - arg.CollectionID, - arg.DeviceID, - arg.DeviceShelfName, - arg.SyncDirection, - ) - var i DeviceShelfMappings - err := row.Scan( - &i.ID, - &i.CollectionID, - &i.DeviceID, - &i.DeviceShelfName, - &i.SyncDirection, - &i.CreatedAt, - ) - return i, err -} - -const CreateLibrary = `-- name: CreateLibrary :one -INSERT INTO libraries (name, description, library_type_id, created_by_admin_id) -VALUES ($1, $2, $3, $4) -RETURNING id, name, description, library_type_id, created_by_admin_id, created_at, updated_at -` - -type CreateLibraryParams struct { - 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"` -} - -// Libraries queries -func (q *Queries) CreateLibrary(ctx context.Context, arg CreateLibraryParams) (Libraries, error) { - row := q.db.QueryRow(ctx, CreateLibrary, - arg.Name, - arg.Description, - arg.LibraryTypeID, - arg.CreatedByAdminID, - ) - var i Libraries - err := row.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.LibraryTypeID, - &i.CreatedByAdminID, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const CreateMediaHighlight = `-- name: CreateMediaHighlight :one -INSERT INTO media_highlights (media_item_id, user_id, selection_text, start_position, end_position, color, note_id) -VALUES ($1, $2, $3, $4, $5, $6, $7) -RETURNING id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data -` - -type CreateMediaHighlightParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - SelectionText string `db:"selection_text" json:"selection_text"` - StartPosition pgtype.Text `db:"start_position" json:"start_position"` - EndPosition pgtype.Text `db:"end_position" json:"end_position"` - Color pgtype.Text `db:"color" json:"color"` - NoteID pgtype.UUID `db:"note_id" json:"note_id"` -} - -// Media Highlights queries -func (q *Queries) CreateMediaHighlight(ctx context.Context, arg CreateMediaHighlightParams) (MediaHighlights, error) { - row := q.db.QueryRow(ctx, CreateMediaHighlight, - arg.MediaItemID, - arg.UserID, - arg.SelectionText, - arg.StartPosition, - arg.EndPosition, - arg.Color, - arg.NoteID, - ) - var i MediaHighlights - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.SelectionText, - &i.StartPosition, - &i.EndPosition, - &i.Color, - &i.NoteID, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageStart, - &i.PercentageEnd, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiStart, - &i.EpubcfiEnd, - &i.ChapterReference, - &i.ParagraphStart, - &i.ParagraphEnd, - &i.PanelNumber, - &i.DeviceSyncData, - ) - return i, err -} - -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) -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) -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, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence -` - -type CreateMediaItemParams struct { - 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"` - TagsSearch []string `db:"tags_search" json:"tags_search"` - 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"` - ContributorsSearch []string `db:"contributors_search" json:"contributors_search"` - 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"` -} - -// Media Items queries -func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams) (MediaItems, error) { - row := q.db.QueryRow(ctx, CreateMediaItem, - arg.LibraryID, - arg.Title, - arg.Author, - arg.Isbn, - arg.Description, - arg.FilePath, - arg.FileSize, - arg.MimeType, - arg.CoverImagePath, - arg.Series, - arg.SeriesNumber, - arg.Tags, - arg.TagsSearch, - arg.Asin, - arg.DatePublished, - arg.Publisher, - arg.Contributors, - arg.ContributorsSearch, - arg.Language, - arg.Edition, - arg.PageCount, - arg.Genre, - arg.CopyrightYear, - arg.GoodreadsID, - arg.OpenlibraryID, - arg.GoogleBooksID, - arg.AddedByAdminID, - arg.CreatedAt, - ) - var i MediaItems - err := row.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, - ) - return i, err -} - -const CreateMediaItemFormat = `-- name: CreateMediaItemFormat :one - -INSERT INTO media_item_formats (media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, converted_from_format_id) -VALUES ($1, $2, $3, $4, $5, $6, $7) -RETURNING id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id -` - -type CreateMediaItemFormatParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - FormatType string `db:"format_type" json:"format_type"` - FilePath pgtype.Text `db:"file_path" json:"file_path"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - FileSizeBytes pgtype.Int8 `db:"file_size_bytes" json:"file_size_bytes"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` - ConvertedFromFormatID pgtype.UUID `db:"converted_from_format_id" json:"converted_from_format_id"` -} - -// MEDIA ITEM FORMATS QUERIES -// Create media item format -func (q *Queries) CreateMediaItemFormat(ctx context.Context, arg CreateMediaItemFormatParams) (MediaItemFormats, error) { - row := q.db.QueryRow(ctx, CreateMediaItemFormat, - arg.MediaItemID, - arg.FormatType, - arg.FilePath, - arg.FileSha256, - arg.FileSizeBytes, - arg.MimeType, - arg.ConvertedFromFormatID, - ) - var i MediaItemFormats - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.FormatType, - &i.FilePath, - &i.FileSha256, - &i.FileSizeBytes, - &i.MimeType, - &i.CreatedAt, - &i.ConvertedFromFormatID, - ) - return i, err -} - -const CreateMediaNote = `-- name: CreateMediaNote :one -INSERT INTO media_notes (media_item_id, user_id, content, position) -VALUES ($1, $2, $3, $4) -RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data -` - -type CreateMediaNoteParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Content string `db:"content" json:"content"` - Position pgtype.Text `db:"position" json:"position"` -} - -// Media Notes queries -func (q *Queries) CreateMediaNote(ctx context.Context, arg CreateMediaNoteParams) (MediaNotes, error) { - row := q.db.QueryRow(ctx, CreateMediaNote, - arg.MediaItemID, - arg.UserID, - arg.Content, - arg.Position, - ) - var i MediaNotes - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Content, - &i.Position, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageLocation, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiLocation, - &i.ChapterReference, - &i.ParagraphReference, - &i.DeviceSyncData, - ) - return i, err -} - -const CreateMediaRating = `-- name: CreateMediaRating :one -INSERT INTO media_ratings (media_item_id, user_id, rating) -VALUES ($1, $2, $3) -ON CONFLICT (media_item_id, user_id) -DO UPDATE SET - rating = EXCLUDED.rating, - updated_at = NOW() -RETURNING id, media_item_id, user_id, rating, created_at, updated_at -` - -type CreateMediaRatingParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Rating int32 `db:"rating" json:"rating"` -} - -func (q *Queries) CreateMediaRating(ctx context.Context, arg CreateMediaRatingParams) (MediaRatings, error) { - row := q.db.QueryRow(ctx, CreateMediaRating, arg.MediaItemID, arg.UserID, arg.Rating) - var i MediaRatings - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Rating, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const CreateOpdsToken = `-- name: CreateOpdsToken :one - -INSERT INTO opds_tokens (device_id, token, token_type, expires_at) -VALUES ($1, $2, $3, $4) -RETURNING id, device_id, token, token_type, expires_at, created_at -` - -type CreateOpdsTokenParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - Token string `db:"token" json:"token"` - TokenType pgtype.Text `db:"token_type" json:"token_type"` - ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` -} - -// OPDS TOKENS QUERIES -// Create OPDS token -func (q *Queries) CreateOpdsToken(ctx context.Context, arg CreateOpdsTokenParams) (OpdsTokens, error) { - row := q.db.QueryRow(ctx, CreateOpdsToken, - arg.DeviceID, - arg.Token, - arg.TokenType, - arg.ExpiresAt, - ) - var i OpdsTokens - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.Token, - &i.TokenType, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} - -const CreateOrUpdateKoboEntitlement = `-- name: CreateOrUpdateKoboEntitlement :one - -INSERT INTO kobo_entitlements (device_id, media_item_id, entitlement_id, content_id, revision_number, purchase_date, kobo_metadata) -VALUES ($1, $2, $3, $4, $5, $6, $7) -ON CONFLICT (device_id, entitlement_id) -DO UPDATE SET - content_id = EXCLUDED.content_id, - revision_number = EXCLUDED.revision_number, - purchase_date = COALESCE(EXCLUDED.purchase_date, kobo_entitlements.purchase_date), - book_status = 'installed', - sync_status = 'synced', - kobo_metadata = EXCLUDED.kobo_metadata, - updated_at = NOW() -RETURNING id, device_id, media_item_id, entitlement_id, content_id, revision_number, purchase_date, accession_date, book_status, sync_status, kobo_metadata, created_at, updated_at -` - -type CreateOrUpdateKoboEntitlementParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` - ContentID string `db:"content_id" json:"content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` - PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"` - KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"` -} - -// ============================================ -// KOBO ENTITLEMENT QUERIES -// ============================================ -func (q *Queries) CreateOrUpdateKoboEntitlement(ctx context.Context, arg CreateOrUpdateKoboEntitlementParams) (KoboEntitlements, error) { - row := q.db.QueryRow(ctx, CreateOrUpdateKoboEntitlement, - arg.DeviceID, - arg.MediaItemID, - arg.EntitlementID, - arg.ContentID, - arg.RevisionNumber, - arg.PurchaseDate, - arg.KoboMetadata, - ) - var i KoboEntitlements - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.EntitlementID, - &i.ContentID, - &i.RevisionNumber, - &i.PurchaseDate, - &i.AccessionDate, - &i.BookStatus, - &i.SyncStatus, - &i.KoboMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const CreateReadingHistory = `-- name: CreateReadingHistory :one -INSERT INTO reading_history ( - user_id, - media_item_id, - device_id, - progress_percentage, - reading_session_start, - reading_session_end, - pages_read, - time_spent_seconds, - device_metadata -) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) -RETURNING id, user_id, media_item_id, device_id, progress_percentage, reading_session_start, reading_session_end, pages_read, time_spent_seconds, device_metadata, created_at -` - -type CreateReadingHistoryParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ProgressPercentage pgtype.Float8 `db:"progress_percentage" json:"progress_percentage"` - ReadingSessionStart pgtype.Timestamptz `db:"reading_session_start" json:"reading_session_start"` - ReadingSessionEnd pgtype.Timestamptz `db:"reading_session_end" json:"reading_session_end"` - PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"` - TimeSpentSeconds pgtype.Int4 `db:"time_spent_seconds" json:"time_spent_seconds"` - DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"` -} - -// Create reading history entry -func (q *Queries) CreateReadingHistory(ctx context.Context, arg CreateReadingHistoryParams) (ReadingHistory, error) { - row := q.db.QueryRow(ctx, CreateReadingHistory, - arg.UserID, - arg.MediaItemID, - arg.DeviceID, - arg.ProgressPercentage, - arg.ReadingSessionStart, - arg.ReadingSessionEnd, - arg.PagesRead, - arg.TimeSpentSeconds, - arg.DeviceMetadata, - ) - var i ReadingHistory - err := row.Scan( - &i.ID, - &i.UserID, - &i.MediaItemID, - &i.DeviceID, - &i.ProgressPercentage, - &i.ReadingSessionStart, - &i.ReadingSessionEnd, - &i.PagesRead, - &i.TimeSpentSeconds, - &i.DeviceMetadata, - &i.CreatedAt, - ) - return i, err -} - -const CreateRefreshToken = `-- name: CreateRefreshToken :one -INSERT INTO refresh_tokens (user_id, token, expires_at) -VALUES ($1, $2, $3) -RETURNING id, user_id, token, expires_at, created_at, revoked_at -` - -type CreateRefreshTokenParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Token pgtype.UUID `db:"token" json:"token"` - ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` -} - -// Refresh Tokens queries -func (q *Queries) CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshTokens, error) { - row := q.db.QueryRow(ctx, CreateRefreshToken, arg.UserID, arg.Token, arg.ExpiresAt) - var i RefreshTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.Token, - &i.ExpiresAt, - &i.CreatedAt, - &i.RevokedAt, - ) - return i, err -} - -const CreateSyncConflict = `-- name: CreateSyncConflict :one -INSERT INTO sync_conflicts (media_item_id, user_id, conflict_type, conflict_data) -VALUES ($1, $2, $3, $4) -RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at -` - -type CreateSyncConflictParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - ConflictType string `db:"conflict_type" json:"conflict_type"` - ConflictData []byte `db:"conflict_data" json:"conflict_data"` -} - -// Conflict Resolution -func (q *Queries) CreateSyncConflict(ctx context.Context, arg CreateSyncConflictParams) (SyncConflicts, error) { - row := q.db.QueryRow(ctx, CreateSyncConflict, - arg.MediaItemID, - arg.UserID, - arg.ConflictType, - arg.ConflictData, - ) - var i SyncConflicts - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.ConflictType, - &i.ConflictData, - &i.ResolutionStatus, - &i.ResolutionData, - &i.ResolvedBy, - &i.ResolvedAt, - &i.CreatedAt, - ) - return i, err -} - -const CreateSyncHistoryEntry = `-- name: CreateSyncHistoryEntry :one -INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, status) -VALUES ($1, $2, 'koreader_progress', $3, 5, 'completed') -RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at -` - -type CreateSyncHistoryEntryParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - SyncData []byte `db:"sync_data" json:"sync_data"` -} - -func (q *Queries) CreateSyncHistoryEntry(ctx context.Context, arg CreateSyncHistoryEntryParams) (SyncQueue, error) { - row := q.db.QueryRow(ctx, CreateSyncHistoryEntry, arg.DeviceID, arg.MediaItemID, arg.SyncData) - var i SyncQueue - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ) - return i, err -} - -const CreateSyncQueueItem = `-- name: CreateSyncQueueItem :one -INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, max_attempts, status) -VALUES ($1, $2, $3, $4, $5, $6, $7) -RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at -` - -type CreateSyncQueueItemParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - SyncType string `db:"sync_type" json:"sync_type"` - SyncData []byte `db:"sync_data" json:"sync_data"` - Priority pgtype.Int4 `db:"priority" json:"priority"` - MaxAttempts pgtype.Int4 `db:"max_attempts" json:"max_attempts"` - Status pgtype.Text `db:"status" json:"status"` -} - -// Sync Queue Management -func (q *Queries) CreateSyncQueueItem(ctx context.Context, arg CreateSyncQueueItemParams) (SyncQueue, error) { - row := q.db.QueryRow(ctx, CreateSyncQueueItem, - arg.DeviceID, - arg.MediaItemID, - arg.SyncType, - arg.SyncData, - arg.Priority, - arg.MaxAttempts, - arg.Status, - ) - var i SyncQueue - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ) - return i, err -} - -const CreateSystemCollection = `-- name: CreateSystemCollection :one -INSERT INTO collections (user_id, name, description, icon, color, show_on_dashboard, query_type, priority, is_system_collection, auto_assign_rules) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true, 'null'::jsonb) -RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at -` - -type CreateSystemCollectionParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` - Description pgtype.Text `db:"description" json:"description"` - Icon pgtype.Text `db:"icon" json:"icon"` - Color pgtype.Text `db:"color" json:"color"` - ShowOnDashboard pgtype.Bool `db:"show_on_dashboard" json:"show_on_dashboard"` - QueryType pgtype.Text `db:"query_type" json:"query_type"` - Priority pgtype.Int4 `db:"priority" json:"priority"` -} - -func (q *Queries) CreateSystemCollection(ctx context.Context, arg CreateSystemCollectionParams) (Collections, error) { - row := q.db.QueryRow(ctx, CreateSystemCollection, - arg.UserID, - arg.Name, - arg.Description, - arg.Icon, - arg.Color, - arg.ShowOnDashboard, - arg.QueryType, - arg.Priority, - ) - var i Collections - err := row.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ) - return i, err -} - -const CreateUnlinkedBook = `-- name: CreateUnlinkedBook :one - -INSERT INTO unlinked_books (device_id, content_id, file_path, title, author, confidence_score) -VALUES ($1, $2, $3, $4, $5, $6) -RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at -` - -type CreateUnlinkedBookParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ContentID string `db:"content_id" json:"content_id"` - FilePath pgtype.Text `db:"file_path" json:"file_path"` - Title pgtype.Text `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` -} - -// ============================================ -// ENHANCED KOBO SYNC -// ============================================ -// Create unlinked book entry -func (q *Queries) CreateUnlinkedBook(ctx context.Context, arg CreateUnlinkedBookParams) (UnlinkedBooks, error) { - row := q.db.QueryRow(ctx, CreateUnlinkedBook, - arg.DeviceID, - arg.ContentID, - arg.FilePath, - arg.Title, - arg.Author, - arg.ConfidenceScore, - ) - var i UnlinkedBooks - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - ) - return i, err -} - -const CreateUser = `-- name: CreateUser :one -INSERT INTO users (email, username, password_hash, first_name, last_name, theme, role) -VALUES ($1, $2, $3, $4, $5, $6, $7) -RETURNING id, email, username, theme, first_name, last_name, role, created_at, updated_at -` - -type CreateUserParams struct { - Email string `db:"email" json:"email"` - Username string `db:"username" json:"username"` - PasswordHash string `db:"password_hash" json:"password_hash"` - FirstName pgtype.Text `db:"first_name" json:"first_name"` - LastName pgtype.Text `db:"last_name" json:"last_name"` - Theme pgtype.Text `db:"theme" json:"theme"` - Role string `db:"role" json:"role"` -} - -type CreateUserRow 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"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` -} - -func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) { - row := q.db.QueryRow(ctx, CreateUser, - arg.Email, - arg.Username, - arg.PasswordHash, - arg.FirstName, - arg.LastName, - arg.Theme, - arg.Role, - ) - var i CreateUserRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const DeleteCollection = `-- name: DeleteCollection :exec -DELETE FROM collections WHERE id = $1 -` - -// Delete collection -func (q *Queries) DeleteCollection(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteCollection, id) - return err -} - -const DeleteDevice = `-- name: DeleteDevice :exec -DELETE FROM devices WHERE id = $1 -` - -func (q *Queries) DeleteDevice(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteDevice, id) - return err -} - -const DeleteDeviceByToken = `-- name: DeleteDeviceByToken :exec -DELETE FROM devices WHERE auth_token = $1 -` - -func (q *Queries) DeleteDeviceByToken(ctx context.Context, authToken string) error { - _, err := q.db.Exec(ctx, DeleteDeviceByToken, authToken) - return err -} - -const DeleteDeviceCatalog = `-- name: DeleteDeviceCatalog :exec -DELETE FROM device_catalogs WHERE id = $1 -` - -// Delete device catalog entry -func (q *Queries) DeleteDeviceCatalog(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteDeviceCatalog, id) - return err -} - -const DeleteDeviceFileAlias = `-- name: DeleteDeviceFileAlias :exec -DELETE FROM device_file_aliases WHERE id = $1 -` - -// Delete device file alias -func (q *Queries) DeleteDeviceFileAlias(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteDeviceFileAlias, id) - return err -} - -const DeleteDeviceShelfMapping = `-- name: DeleteDeviceShelfMapping :exec -DELETE FROM device_shelf_mappings WHERE id = $1 -` - -// Delete device shelf mapping -func (q *Queries) DeleteDeviceShelfMapping(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteDeviceShelfMapping, id) - return err -} - -const DeleteKoboEntitlement = `-- name: DeleteKoboEntitlement :exec -DELETE FROM kobo_entitlements WHERE device_id = $1 AND entitlement_id = $2 -` - -type DeleteKoboEntitlementParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` -} - -func (q *Queries) DeleteKoboEntitlement(ctx context.Context, arg DeleteKoboEntitlementParams) error { - _, err := q.db.Exec(ctx, DeleteKoboEntitlement, arg.DeviceID, arg.EntitlementID) - return err -} - -const DeleteLibrary = `-- name: DeleteLibrary :exec -DELETE FROM libraries WHERE id = $1 -` - -func (q *Queries) DeleteLibrary(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteLibrary, id) - return err -} - -const DeleteLibraryFolder = `-- name: DeleteLibraryFolder :one -DELETE FROM library_folders WHERE library_id = $1 AND folder_path = $2 RETURNING id, library_id, folder_path, created_at -` - -type DeleteLibraryFolderParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - FolderPath string `db:"folder_path" json:"folder_path"` -} - -func (q *Queries) DeleteLibraryFolder(ctx context.Context, arg DeleteLibraryFolderParams) (LibraryFolders, error) { - row := q.db.QueryRow(ctx, DeleteLibraryFolder, arg.LibraryID, arg.FolderPath) - var i LibraryFolders - err := row.Scan( - &i.ID, - &i.LibraryID, - &i.FolderPath, - &i.CreatedAt, - ) - return i, err -} - -const DeleteMediaHighlight = `-- name: DeleteMediaHighlight :exec -DELETE FROM media_highlights WHERE id = $1 -` - -func (q *Queries) DeleteMediaHighlight(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteMediaHighlight, id) - return err -} - -const DeleteMediaItem = `-- name: DeleteMediaItem :exec -DELETE FROM media_items WHERE id = $1 -` - -func (q *Queries) DeleteMediaItem(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteMediaItem, id) - return err -} - -const DeleteMediaItemFormat = `-- name: DeleteMediaItemFormat :exec -DELETE FROM media_item_formats WHERE id = $1 -` - -// Delete media item format -func (q *Queries) DeleteMediaItemFormat(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteMediaItemFormat, id) - return err -} - -const DeleteMediaNote = `-- name: DeleteMediaNote :exec -DELETE FROM media_notes WHERE id = $1 -` - -func (q *Queries) DeleteMediaNote(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteMediaNote, id) - return err -} - -const DeleteMediaRating = `-- name: DeleteMediaRating :exec -DELETE FROM media_ratings WHERE media_item_id = $1 AND user_id = $2 -` - -type DeleteMediaRatingParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) DeleteMediaRating(ctx context.Context, arg DeleteMediaRatingParams) error { - _, err := q.db.Exec(ctx, DeleteMediaRating, arg.MediaItemID, arg.UserID) - return err -} - -const DeleteReadingProgress = `-- name: DeleteReadingProgress :exec -DELETE FROM reading_progress WHERE media_item_id = $1 AND user_id = $2 -` - -type DeleteReadingProgressParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) DeleteReadingProgress(ctx context.Context, arg DeleteReadingProgressParams) error { - _, err := q.db.Exec(ctx, DeleteReadingProgress, arg.MediaItemID, arg.UserID) - return err -} - -const DeleteSyncConflict = `-- name: DeleteSyncConflict :exec -DELETE FROM sync_conflicts WHERE id = $1 -` - -func (q *Queries) DeleteSyncConflict(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteSyncConflict, id) - return err -} - -const DeleteSyncQueueItem = `-- name: DeleteSyncQueueItem :exec -DELETE FROM sync_queue WHERE id = $1 -` - -func (q *Queries) DeleteSyncQueueItem(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteSyncQueueItem, id) - return err -} - -const DeleteSystemConfig = `-- name: DeleteSystemConfig :exec -DELETE FROM system_config WHERE key = $1 -` - -// Delete system config -func (q *Queries) DeleteSystemConfig(ctx context.Context, key string) error { - _, err := q.db.Exec(ctx, DeleteSystemConfig, key) - return err -} - -const DeleteUnlinkedBook = `-- name: DeleteUnlinkedBook :exec -DELETE FROM unlinked_books WHERE id = $1 -` - -// Delete unlinked book -func (q *Queries) DeleteUnlinkedBook(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteUnlinkedBook, id) - return err -} - -const DeleteUser = `-- name: DeleteUser :exec -DELETE FROM users WHERE id = $1 -` - -func (q *Queries) DeleteUser(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, DeleteUser, id) - return err -} - -const DeleteUserSystemCollection = `-- name: DeleteUserSystemCollection :exec -DELETE FROM collections -WHERE user_id = $1 - AND name = $2 - AND is_system_collection = true -` - -type DeleteUserSystemCollectionParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` -} - -func (q *Queries) DeleteUserSystemCollection(ctx context.Context, arg DeleteUserSystemCollectionParams) error { - _, err := q.db.Exec(ctx, DeleteUserSystemCollection, arg.UserID, arg.Name) - return err -} - -const GenerateKoboEntitlementId = `-- name: GenerateKoboEntitlementId :one -SELECT 'kobo_' || uuid_generate_v4()::TEXT as entitlement_id -` - -func (q *Queries) GenerateKoboEntitlementId(ctx context.Context) (interface{}, error) { - row := q.db.QueryRow(ctx, GenerateKoboEntitlementId) - var entitlement_id interface{} - err := row.Scan(&entitlement_id) - return entitlement_id, err -} - -const GetAllSystemConfig = `-- name: GetAllSystemConfig :many -SELECT key, value, updated_at, updated_by FROM system_config ORDER BY key -` - -// Get all system config -func (q *Queries) GetAllSystemConfig(ctx context.Context) ([]SystemConfig, error) { - rows, err := q.db.Query(ctx, GetAllSystemConfig) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SystemConfig{} - for rows.Next() { - var i SystemConfig - if err := rows.Scan( - &i.Key, - &i.Value, - &i.UpdatedAt, - &i.UpdatedBy, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetAllSystemSettings = `-- name: GetAllSystemSettings :many -SELECT setting_key, setting_value, description FROM system_settings ORDER BY setting_key -` - -type GetAllSystemSettingsRow struct { - SettingKey string `db:"setting_key" json:"setting_key"` - SettingValue string `db:"setting_value" json:"setting_value"` - Description pgtype.Text `db:"description" json:"description"` -} - -func (q *Queries) GetAllSystemSettings(ctx context.Context) ([]GetAllSystemSettingsRow, error) { - rows, err := q.db.Query(ctx, GetAllSystemSettings) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetAllSystemSettingsRow{} - for rows.Next() { - var i GetAllSystemSettingsRow - if err := rows.Scan(&i.SettingKey, &i.SettingValue, &i.Description); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetAnnotationsForBook = `-- name: GetAnnotationsForBook :many -SELECT - mh.id, - mh.selection_text, - mh.start_position, - mh.end_position, - mh.color, - mh.created_at, - mh.updated_at, - 'highlight' as annotation_type, - mh.percentage_start, - mh.percentage_end, - mh.epubcfi_start, - mh.epubcfi_end -FROM media_highlights mh -WHERE mh.media_item_id = $1 AND mh.user_id = $2 -UNION ALL -SELECT - mn.id, - mn.content, - mn.position, - NULL as end_position, - NULL as color, - mn.created_at, - mn.updated_at, - 'note' as annotation_type, - mn.percentage_location as percentage_start, - NULL as percentage_end, - mn.epubcfi_location as epubcfi_start, - NULL as epubcfi_end -FROM media_notes mn -WHERE mn.media_item_id = $1 AND mn.user_id = $2 -ORDER BY created_at DESC -` - -type GetAnnotationsForBookParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -type GetAnnotationsForBookRow struct { - ID pgtype.UUID `db:"id" json:"id"` - SelectionText string `db:"selection_text" json:"selection_text"` - StartPosition pgtype.Text `db:"start_position" json:"start_position"` - EndPosition pgtype.Text `db:"end_position" json:"end_position"` - Color pgtype.Text `db:"color" json:"color"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - AnnotationType string `db:"annotation_type" json:"annotation_type"` - PercentageStart pgtype.Float8 `db:"percentage_start" json:"percentage_start"` - PercentageEnd pgtype.Float8 `db:"percentage_end" json:"percentage_end"` - EpubcfiStart pgtype.Text `db:"epubcfi_start" json:"epubcfi_start"` - EpubcfiEnd pgtype.Text `db:"epubcfi_end" json:"epubcfi_end"` -} - -func (q *Queries) GetAnnotationsForBook(ctx context.Context, arg GetAnnotationsForBookParams) ([]GetAnnotationsForBookRow, error) { - rows, err := q.db.Query(ctx, GetAnnotationsForBook, arg.MediaItemID, arg.UserID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetAnnotationsForBookRow{} - for rows.Next() { - var i GetAnnotationsForBookRow - if err := rows.Scan( - &i.ID, - &i.SelectionText, - &i.StartPosition, - &i.EndPosition, - &i.Color, - &i.CreatedAt, - &i.UpdatedAt, - &i.AnnotationType, - &i.PercentageStart, - &i.PercentageEnd, - &i.EpubcfiStart, - &i.EpubcfiEnd, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetCollection = `-- name: GetCollection :one -SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections WHERE id = $1 -` - -// Get collection -func (q *Queries) GetCollection(ctx context.Context, id pgtype.UUID) (Collections, error) { - row := q.db.QueryRow(ctx, GetCollection, id) - var i Collections - err := row.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ) - return i, err -} - -const GetCollectionItems = `-- name: GetCollectionItems :many -SELECT ci.id, ci.collection_id, ci.media_item_id, ci.added_at, ci.added_by_user_id, ci.excluded, mi.title, mi.author, mi.cover_image_path, mi.library_id -FROM collection_items ci -JOIN media_items mi ON ci.media_item_id = mi.id -WHERE ci.collection_id = $1 -ORDER BY ci.added_at DESC -` - -type GetCollectionItemsRow struct { - ID pgtype.UUID `db:"id" json:"id"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"` - AddedByUserID pgtype.UUID `db:"added_by_user_id" json:"added_by_user_id"` - Excluded pgtype.Bool `db:"excluded" json:"excluded"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` -} - -// Get collection items -func (q *Queries) GetCollectionItems(ctx context.Context, collectionID pgtype.UUID) ([]GetCollectionItemsRow, error) { - rows, err := q.db.Query(ctx, GetCollectionItems, collectionID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetCollectionItemsRow{} - for rows.Next() { - var i GetCollectionItemsRow - if err := rows.Scan( - &i.ID, - &i.CollectionID, - &i.MediaItemID, - &i.AddedAt, - &i.AddedByUserID, - &i.Excluded, - &i.Title, - &i.Author, - &i.CoverImagePath, - &i.LibraryID, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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.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 -ORDER BY ci.added_at DESC -LIMIT $3 -` - -type GetCollectionItemsForDashboardParams struct { - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - Limit int32 `db:"limit" json:"limit"` -} - -type GetCollectionItemsForDashboardRow 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"` - Excluded pgtype.Bool `db:"excluded" json:"excluded"` -} - -func (q *Queries) GetCollectionItemsForDashboard(ctx context.Context, arg GetCollectionItemsForDashboardParams) ([]GetCollectionItemsForDashboardRow, error) { - rows, err := q.db.Query(ctx, GetCollectionItemsForDashboard, arg.CollectionID, arg.LibraryID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetCollectionItemsForDashboardRow{} - for rows.Next() { - var i GetCollectionItemsForDashboardRow - 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.Excluded, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetCollectionWithBookCount = `-- name: GetCollectionWithBookCount :one -SELECT - c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at, - COUNT(ci.id) as book_count -FROM collections c -LEFT JOIN collection_items ci ON c.id = ci.collection_id -WHERE c.id = $1 -GROUP BY c.id -` - -type GetCollectionWithBookCountRow struct { - ID pgtype.UUID `db:"id" json:"id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` - Description pgtype.Text `db:"description" json:"description"` - Color pgtype.Text `db:"color" json:"color"` - Icon pgtype.Text `db:"icon" json:"icon"` - AutoAssignRules []byte `db:"auto_assign_rules" json:"auto_assign_rules"` - ViewSettings []byte `db:"view_settings" json:"view_settings"` - ShowOnDashboard pgtype.Bool `db:"show_on_dashboard" json:"show_on_dashboard"` - QueryType pgtype.Text `db:"query_type" json:"query_type"` - Priority pgtype.Int4 `db:"priority" json:"priority"` - IsSystemCollection pgtype.Bool `db:"is_system_collection" json:"is_system_collection"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - BookCount int64 `db:"book_count" json:"book_count"` -} - -// Get collection with book count -func (q *Queries) GetCollectionWithBookCount(ctx context.Context, id pgtype.UUID) (GetCollectionWithBookCountRow, error) { - row := q.db.QueryRow(ctx, GetCollectionWithBookCount, id) - var i GetCollectionWithBookCountRow - err := row.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - &i.BookCount, - ) - return i, err -} - -const GetCollectionsByUser = `-- name: GetCollectionsByUser :many -SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections WHERE user_id = $1 ORDER BY created_at DESC -` - -// Get collections by user -func (q *Queries) GetCollectionsByUser(ctx context.Context, userID pgtype.UUID) ([]Collections, error) { - rows, err := q.db.Query(ctx, GetCollectionsByUser, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Collections{} - for rows.Next() { - var i Collections - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetCollectionsForBook = `-- name: GetCollectionsForBook :many -SELECT c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at -FROM collections c -JOIN collection_items ci ON c.id = ci.collection_id -WHERE ci.media_item_id = $1 -` - -// Get collections for book -func (q *Queries) GetCollectionsForBook(ctx context.Context, mediaItemID pgtype.UUID) ([]Collections, error) { - rows, err := q.db.Query(ctx, GetCollectionsForBook, mediaItemID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Collections{} - for rows.Next() { - var i Collections - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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.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 - WHERE user_id = $2 - AND percentage > 0 - AND percentage < 1 - ORDER BY media_item_id, last_read_at DESC -) rp ON rp.media_item_id = mi.id -WHERE mi.library_id = $1 -ORDER BY rp.last_read_at DESC -LIMIT $3 -` - -type GetContinueReadingItemsParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Limit int32 `db:"limit" json:"limit"` -} - -// Smart section queries (for system collections) -func (q *Queries) GetContinueReadingItems(ctx context.Context, arg GetContinueReadingItemsParams) ([]MediaItems, error) { - rows, err := q.db.Query(ctx, GetContinueReadingItems, arg.LibraryID, arg.UserID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaItems{} - for rows.Next() { - var i MediaItems - 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, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetDashboardPreferences = `-- name: GetDashboardPreferences :one - -SELECT id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at FROM user_dashboard_preferences -WHERE user_id = $1 AND library_id = $2 -` - -type GetDashboardPreferencesParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` -} - -// ============================================ -// CAROUSEL-STYLE DASHBOARD -// ============================================ -// Dashboard preferences queries -func (q *Queries) GetDashboardPreferences(ctx context.Context, arg GetDashboardPreferencesParams) (UserDashboardPreferences, error) { - row := q.db.QueryRow(ctx, GetDashboardPreferences, arg.UserID, arg.LibraryID) - var i UserDashboardPreferences - err := row.Scan( - &i.ID, - &i.UserID, - &i.LibraryID, - &i.HiddenCollections, - &i.CollectionOrder, - &i.ItemsPerSection, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetDevice = `-- name: GetDevice :one -SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE id = $1 -` - -func (q *Queries) GetDevice(ctx context.Context, id pgtype.UUID) (Devices, error) { - row := q.db.QueryRow(ctx, GetDevice, id) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetDeviceByAuthToken = `-- name: GetDeviceByAuthToken :one -SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE auth_token = $1 -` - -func (q *Queries) GetDeviceByAuthToken(ctx context.Context, authToken string) (Devices, error) { - row := q.db.QueryRow(ctx, GetDeviceByAuthToken, authToken) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetDeviceByIdentifier = `-- name: GetDeviceByIdentifier :one -SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_identifier = $1 -` - -func (q *Queries) GetDeviceByIdentifier(ctx context.Context, deviceIdentifier string) (Devices, error) { - row := q.db.QueryRow(ctx, GetDeviceByIdentifier, deviceIdentifier) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetDeviceCatalogByBookhoardUUID = `-- name: GetDeviceCatalogByBookhoardUUID :one -SELECT id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method FROM device_catalogs WHERE device_id = $1 AND bookhoard_uuid = $2 -` - -type GetDeviceCatalogByBookhoardUUIDParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"` -} - -// Get device catalog by Bookhoard UUID -func (q *Queries) GetDeviceCatalogByBookhoardUUID(ctx context.Context, arg GetDeviceCatalogByBookhoardUUIDParams) (DeviceCatalogs, error) { - row := q.db.QueryRow(ctx, GetDeviceCatalogByBookhoardUUID, arg.DeviceID, arg.BookhoardUuid) - var i DeviceCatalogs - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.BookhoardUuid, - &i.KoboContentID, - &i.ContentIDType, - &i.Available, - &i.DeliveryDate, - &i.DeliveryMethod, - ) - return i, err -} - -const GetDeviceCatalogByKoboContentId = `-- name: GetDeviceCatalogByKoboContentId :one -SELECT id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method FROM device_catalogs WHERE kobo_content_id = $1 -` - -// Get device catalog by Kobo ContentId -func (q *Queries) GetDeviceCatalogByKoboContentId(ctx context.Context, koboContentID string) (DeviceCatalogs, error) { - row := q.db.QueryRow(ctx, GetDeviceCatalogByKoboContentId, koboContentID) - var i DeviceCatalogs - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.BookhoardUuid, - &i.KoboContentID, - &i.ContentIDType, - &i.Available, - &i.DeliveryDate, - &i.DeliveryMethod, - ) - return i, err -} - -const GetDeviceCatalogEntries = `-- name: GetDeviceCatalogEntries :many -SELECT dc.id, dc.device_id, dc.media_item_id, dc.bookhoard_uuid, dc.kobo_content_id, dc.content_id_type, dc.available, dc.delivery_date, dc.delivery_method, mi.title, mi.author -FROM device_catalogs dc -JOIN media_items mi ON dc.media_item_id = mi.id -WHERE dc.device_id = $1 AND dc.available = true -ORDER BY dc.delivery_date DESC -` - -type GetDeviceCatalogEntriesRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"` - KoboContentID string `db:"kobo_content_id" json:"kobo_content_id"` - ContentIDType pgtype.Text `db:"content_id_type" json:"content_id_type"` - Available pgtype.Bool `db:"available" json:"available"` - DeliveryDate pgtype.Timestamptz `db:"delivery_date" json:"delivery_date"` - DeliveryMethod pgtype.Text `db:"delivery_method" json:"delivery_method"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` -} - -// Get device catalog entries -func (q *Queries) GetDeviceCatalogEntries(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceCatalogEntriesRow, error) { - rows, err := q.db.Query(ctx, GetDeviceCatalogEntries, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetDeviceCatalogEntriesRow{} - for rows.Next() { - var i GetDeviceCatalogEntriesRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.BookhoardUuid, - &i.KoboContentID, - &i.ContentIDType, - &i.Available, - &i.DeliveryDate, - &i.DeliveryMethod, - &i.Title, - &i.Author, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetDeviceFileAlias = `-- name: GetDeviceFileAlias :one -SELECT id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at FROM device_file_aliases WHERE device_id = $1 AND file_path = $2 -` - -type GetDeviceFileAliasParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - FilePath string `db:"file_path" json:"file_path"` -} - -// Get device file alias -func (q *Queries) GetDeviceFileAlias(ctx context.Context, arg GetDeviceFileAliasParams) (DeviceFileAliases, error) { - row := q.db.QueryRow(ctx, GetDeviceFileAlias, arg.DeviceID, arg.FilePath) - var i DeviceFileAliases - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.DeviceID, - &i.FilePath, - &i.FileSha256, - &i.ConfidenceScore, - &i.LastSeenAt, - ) - return i, err -} - -const GetDeviceFileAliasBySHA256 = `-- name: GetDeviceFileAliasBySHA256 :one -SELECT dfa.id, dfa.media_item_id, dfa.device_id, dfa.file_path, dfa.file_sha256, dfa.confidence_score, dfa.last_seen_at, mi.title, mi.author -FROM device_file_aliases dfa -JOIN media_items mi ON dfa.media_item_id = mi.id -WHERE dfa.file_sha256 = $1 -` - -type GetDeviceFileAliasBySHA256Row struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - FilePath string `db:"file_path" json:"file_path"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` - LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` -} - -// Get device file alias by SHA-256 -func (q *Queries) GetDeviceFileAliasBySHA256(ctx context.Context, fileSha256 pgtype.Text) (GetDeviceFileAliasBySHA256Row, error) { - row := q.db.QueryRow(ctx, GetDeviceFileAliasBySHA256, fileSha256) - var i GetDeviceFileAliasBySHA256Row - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.DeviceID, - &i.FilePath, - &i.FileSha256, - &i.ConfidenceScore, - &i.LastSeenAt, - &i.Title, - &i.Author, - ) - return i, err -} - -const GetDeviceFileAliasesByDevice = `-- name: GetDeviceFileAliasesByDevice :many -SELECT dfa.id, dfa.media_item_id, dfa.device_id, dfa.file_path, dfa.file_sha256, dfa.confidence_score, dfa.last_seen_at, mi.title, mi.author -FROM device_file_aliases dfa -JOIN media_items mi ON dfa.media_item_id = mi.id -WHERE dfa.device_id = $1 -ORDER BY dfa.last_seen_at DESC -` - -type GetDeviceFileAliasesByDeviceRow struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - FilePath string `db:"file_path" json:"file_path"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` - LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` -} - -// Get device file aliases by device -func (q *Queries) GetDeviceFileAliasesByDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceFileAliasesByDeviceRow, error) { - rows, err := q.db.Query(ctx, GetDeviceFileAliasesByDevice, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetDeviceFileAliasesByDeviceRow{} - for rows.Next() { - var i GetDeviceFileAliasesByDeviceRow - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.DeviceID, - &i.FilePath, - &i.FileSha256, - &i.ConfidenceScore, - &i.LastSeenAt, - &i.Title, - &i.Author, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetDeviceShelfMapping = `-- name: GetDeviceShelfMapping :one -SELECT id, collection_id, device_id, device_shelf_name, sync_direction, created_at FROM device_shelf_mappings WHERE device_id = $1 AND collection_id = $2 -` - -type GetDeviceShelfMappingParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` -} - -// Get device shelf mapping -func (q *Queries) GetDeviceShelfMapping(ctx context.Context, arg GetDeviceShelfMappingParams) (DeviceShelfMappings, error) { - row := q.db.QueryRow(ctx, GetDeviceShelfMapping, arg.DeviceID, arg.CollectionID) - var i DeviceShelfMappings - err := row.Scan( - &i.ID, - &i.CollectionID, - &i.DeviceID, - &i.DeviceShelfName, - &i.SyncDirection, - &i.CreatedAt, - ) - return i, err -} - -const GetDeviceShelfMappings = `-- name: GetDeviceShelfMappings :many -SELECT dsm.id, dsm.collection_id, dsm.device_id, dsm.device_shelf_name, dsm.sync_direction, dsm.created_at, c.name as collection_name, c.icon as collection_icon -FROM device_shelf_mappings dsm -JOIN collections c ON dsm.collection_id = c.id -WHERE dsm.device_id = $1 -` - -type GetDeviceShelfMappingsRow struct { - ID pgtype.UUID `db:"id" json:"id"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"` - SyncDirection pgtype.Text `db:"sync_direction" json:"sync_direction"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - CollectionName string `db:"collection_name" json:"collection_name"` - CollectionIcon pgtype.Text `db:"collection_icon" json:"collection_icon"` -} - -// Get device shelf mappings -func (q *Queries) GetDeviceShelfMappings(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceShelfMappingsRow, error) { - rows, err := q.db.Query(ctx, GetDeviceShelfMappings, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetDeviceShelfMappingsRow{} - for rows.Next() { - var i GetDeviceShelfMappingsRow - if err := rows.Scan( - &i.ID, - &i.CollectionID, - &i.DeviceID, - &i.DeviceShelfName, - &i.SyncDirection, - &i.CreatedAt, - &i.CollectionName, - &i.CollectionIcon, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetFailedSyncQueueItems = `-- name: GetFailedSyncQueueItems :many -SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue -WHERE status = 'failed' AND attempts < max_attempts -ORDER BY priority ASC, created_at ASC -LIMIT $1 -` - -func (q *Queries) GetFailedSyncQueueItems(ctx context.Context, limit int32) ([]SyncQueue, error) { - rows, err := q.db.Query(ctx, GetFailedSyncQueueItems, limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SyncQueue{} - for rows.Next() { - var i SyncQueue - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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 -JOIN media_items mi ON ke.media_item_id = mi.id -WHERE ke.device_id = $1 AND ke.content_id = $2 -` - -type GetKoboEntitlementByContentIdParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ContentID string `db:"content_id" json:"content_id"` -} - -type GetKoboEntitlementByContentIdRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` - ContentID string `db:"content_id" json:"content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` - PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"` - AccessionDate pgtype.Timestamptz `db:"accession_date" json:"accession_date"` - BookStatus pgtype.Text `db:"book_status" json:"book_status"` - SyncStatus pgtype.Text `db:"sync_status" json:"sync_status"` - KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` -} - -func (q *Queries) GetKoboEntitlementByContentId(ctx context.Context, arg GetKoboEntitlementByContentIdParams) (GetKoboEntitlementByContentIdRow, error) { - row := q.db.QueryRow(ctx, GetKoboEntitlementByContentId, arg.DeviceID, arg.ContentID) - var i GetKoboEntitlementByContentIdRow - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.EntitlementID, - &i.ContentID, - &i.RevisionNumber, - &i.PurchaseDate, - &i.AccessionDate, - &i.BookStatus, - &i.SyncStatus, - &i.KoboMetadata, - &i.CreatedAt, - &i.UpdatedAt, - &i.Title, - &i.Author, - &i.FilePath, - ) - return i, err -} - -const GetKoboEntitlementByEntitlementId = `-- name: GetKoboEntitlementByEntitlementId :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 -JOIN media_items mi ON ke.media_item_id = mi.id -WHERE ke.device_id = $1 AND ke.entitlement_id = $2 -` - -type GetKoboEntitlementByEntitlementIdParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` -} - -type GetKoboEntitlementByEntitlementIdRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` - ContentID string `db:"content_id" json:"content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` - PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"` - AccessionDate pgtype.Timestamptz `db:"accession_date" json:"accession_date"` - BookStatus pgtype.Text `db:"book_status" json:"book_status"` - SyncStatus pgtype.Text `db:"sync_status" json:"sync_status"` - KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` -} - -func (q *Queries) GetKoboEntitlementByEntitlementId(ctx context.Context, arg GetKoboEntitlementByEntitlementIdParams) (GetKoboEntitlementByEntitlementIdRow, error) { - row := q.db.QueryRow(ctx, GetKoboEntitlementByEntitlementId, arg.DeviceID, arg.EntitlementID) - var i GetKoboEntitlementByEntitlementIdRow - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.EntitlementID, - &i.ContentID, - &i.RevisionNumber, - &i.PurchaseDate, - &i.AccessionDate, - &i.BookStatus, - &i.SyncStatus, - &i.KoboMetadata, - &i.CreatedAt, - &i.UpdatedAt, - &i.Title, - &i.Author, - &i.FilePath, - ) - return i, err -} - -const GetKoboEntitlementsForDevice = `-- name: GetKoboEntitlementsForDevice :many -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 -JOIN media_items mi ON ke.media_item_id = mi.id -WHERE ke.device_id = $1 -ORDER BY ke.accession_date DESC -` - -type GetKoboEntitlementsForDeviceRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` - ContentID string `db:"content_id" json:"content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` - PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"` - AccessionDate pgtype.Timestamptz `db:"accession_date" json:"accession_date"` - BookStatus pgtype.Text `db:"book_status" json:"book_status"` - SyncStatus pgtype.Text `db:"sync_status" json:"sync_status"` - KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` -} - -func (q *Queries) GetKoboEntitlementsForDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboEntitlementsForDeviceRow, error) { - rows, err := q.db.Query(ctx, GetKoboEntitlementsForDevice, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetKoboEntitlementsForDeviceRow{} - for rows.Next() { - var i GetKoboEntitlementsForDeviceRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.EntitlementID, - &i.ContentID, - &i.RevisionNumber, - &i.PurchaseDate, - &i.AccessionDate, - &i.BookStatus, - &i.SyncStatus, - &i.KoboMetadata, - &i.CreatedAt, - &i.UpdatedAt, - &i.Title, - &i.Author, - &i.FilePath, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetKoboShelfBookCount = `-- name: GetKoboShelfBookCount :one -SELECT COUNT(*) as book_count -FROM kobo_shelves -WHERE device_id = $1 -` - -func (q *Queries) GetKoboShelfBookCount(ctx context.Context, deviceID pgtype.UUID) (int64, error) { - row := q.db.QueryRow(ctx, GetKoboShelfBookCount, deviceID) - var book_count int64 - err := row.Scan(&book_count) - return book_count, err -} - -const GetKoboShelfBooks = `-- name: GetKoboShelfBooks :many -SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author, mi.file_path, mi.mime_type, mi.entitlement_id, mi.kobo_content_id, mi.revision_number -FROM kobo_shelves ks -JOIN media_items mi ON ks.media_item_id = mi.id -WHERE ks.device_id = $1 -ORDER BY ks.shelf_position ASC, ks.added_at ASC -` - -type GetKoboShelfBooksRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"` - ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"` - AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"` - LastSyncedAt pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` - EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"` - KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` -} - -func (q *Queries) GetKoboShelfBooks(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboShelfBooksRow, error) { - rows, err := q.db.Query(ctx, GetKoboShelfBooks, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetKoboShelfBooksRow{} - for rows.Next() { - var i GetKoboShelfBooksRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.ShelfName, - &i.ShelfPosition, - &i.AddedAt, - &i.LastSyncedAt, - &i.CollectionID, - &i.PositionInCollection, - &i.Title, - &i.Author, - &i.FilePath, - &i.MimeType, - &i.EntitlementID, - &i.KoboContentID, - &i.RevisionNumber, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetKoboShelfBooksByShelfName = `-- name: GetKoboShelfBooksByShelfName :many -SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author, mi.file_path, mi.mime_type, mi.entitlement_id, mi.kobo_content_id, mi.revision_number -FROM kobo_shelves ks -JOIN media_items mi ON ks.media_item_id = mi.id -WHERE ks.device_id = $1 AND ks.shelf_name = $2 -ORDER BY ks.shelf_position ASC, ks.added_at ASC -` - -type GetKoboShelfBooksByShelfNameParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"` -} - -type GetKoboShelfBooksByShelfNameRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"` - ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"` - AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"` - LastSyncedAt pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` - EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"` - KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` -} - -func (q *Queries) GetKoboShelfBooksByShelfName(ctx context.Context, arg GetKoboShelfBooksByShelfNameParams) ([]GetKoboShelfBooksByShelfNameRow, error) { - rows, err := q.db.Query(ctx, GetKoboShelfBooksByShelfName, arg.DeviceID, arg.ShelfName) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetKoboShelfBooksByShelfNameRow{} - for rows.Next() { - var i GetKoboShelfBooksByShelfNameRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.ShelfName, - &i.ShelfPosition, - &i.AddedAt, - &i.LastSyncedAt, - &i.CollectionID, - &i.PositionInCollection, - &i.Title, - &i.Author, - &i.FilePath, - &i.MimeType, - &i.EntitlementID, - &i.KoboContentID, - &i.RevisionNumber, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetKoboShelvesByCollection = `-- name: GetKoboShelvesByCollection :many -SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author -FROM kobo_shelves ks -JOIN media_items mi ON ks.media_item_id = mi.id -WHERE ks.device_id = $1 AND ks.collection_id = $2 -ORDER BY ks.position_in_collection ASC, ks.shelf_position ASC -` - -type GetKoboShelvesByCollectionParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` -} - -type GetKoboShelvesByCollectionRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"` - ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"` - AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"` - LastSyncedAt pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` -} - -// Get Kobo shelves by collection -func (q *Queries) GetKoboShelvesByCollection(ctx context.Context, arg GetKoboShelvesByCollectionParams) ([]GetKoboShelvesByCollectionRow, error) { - rows, err := q.db.Query(ctx, GetKoboShelvesByCollection, arg.DeviceID, arg.CollectionID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetKoboShelvesByCollectionRow{} - for rows.Next() { - var i GetKoboShelvesByCollectionRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.ShelfName, - &i.ShelfPosition, - &i.AddedAt, - &i.LastSyncedAt, - &i.CollectionID, - &i.PositionInCollection, - &i.Title, - &i.Author, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetLibrary = `-- name: GetLibrary :one -SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description -FROM libraries l -JOIN library_types lt ON l.library_type_id = lt.id -WHERE l.id = $1 -` - -type GetLibraryRow struct { - 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"` - TypeName string `db:"type_name" json:"type_name"` - TypeDescription pgtype.Text `db:"type_description" json:"type_description"` -} - -func (q *Queries) GetLibrary(ctx context.Context, id pgtype.UUID) (GetLibraryRow, error) { - row := q.db.QueryRow(ctx, GetLibrary, id) - var i GetLibraryRow - err := row.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.LibraryTypeID, - &i.CreatedByAdminID, - &i.CreatedAt, - &i.UpdatedAt, - &i.TypeName, - &i.TypeDescription, - ) - return i, err -} - -const GetLibraryByFolder = `-- name: GetLibraryByFolder :one -SELECT lf.library_id, 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 lf.folder_path = $1 -` - -type GetLibraryByFolderRow struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - 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) GetLibraryByFolder(ctx context.Context, folderPath string) (GetLibraryByFolderRow, error) { - row := q.db.QueryRow(ctx, GetLibraryByFolder, folderPath) - var i GetLibraryByFolderRow - err := row.Scan( - &i.LibraryID, - &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 -` - -func (q *Queries) GetLibraryFolders(ctx context.Context, libraryID pgtype.UUID) ([]LibraryFolders, error) { - rows, err := q.db.Query(ctx, GetLibraryFolders, libraryID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []LibraryFolders{} - for rows.Next() { - var i LibraryFolders - if err := rows.Scan( - &i.ID, - &i.LibraryID, - &i.FolderPath, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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.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 -` - -func (q *Queries) GetLibraryItems(ctx context.Context, libraryID pgtype.UUID) ([]MediaItems, error) { - rows, err := q.db.Query(ctx, GetLibraryItems, libraryID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaItems{} - for rows.Next() { - var i MediaItems - 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, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetLibraryType = `-- name: GetLibraryType :one -SELECT id, name, description, allowed_extensions, created_at FROM library_types WHERE id = $1 -` - -func (q *Queries) GetLibraryType(ctx context.Context, id pgtype.UUID) (LibraryTypes, error) { - row := q.db.QueryRow(ctx, GetLibraryType, id) - var i LibraryTypes - err := row.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.AllowedExtensions, - &i.CreatedAt, - ) - return i, err -} - -const GetLibraryTypeByName = `-- name: GetLibraryTypeByName :one -SELECT id, name, description, allowed_extensions, created_at FROM library_types WHERE name = $1 -` - -func (q *Queries) GetLibraryTypeByName(ctx context.Context, name string) (LibraryTypes, error) { - row := q.db.QueryRow(ctx, GetLibraryTypeByName, name) - var i LibraryTypes - err := row.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.AllowedExtensions, - &i.CreatedAt, - ) - return i, err -} - -const GetLibraryTypes = `-- name: GetLibraryTypes :many -SELECT id, name, description, allowed_extensions, created_at FROM library_types ORDER BY name -` - -// Library Types queries -func (q *Queries) GetLibraryTypes(ctx context.Context) ([]LibraryTypes, error) { - rows, err := q.db.Query(ctx, GetLibraryTypes) - if err != nil { - return nil, err - } - defer rows.Close() - items := []LibraryTypes{} - for rows.Next() { - var i LibraryTypes - if err := rows.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.AllowedExtensions, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetLibraryVisibility = `-- name: GetLibraryVisibility :one -SELECT id, user_id, library_id, is_visible, created_at, updated_at FROM library_visibility WHERE user_id = $1 AND library_id = $2 -` - -type GetLibraryVisibilityParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` -} - -func (q *Queries) GetLibraryVisibility(ctx context.Context, arg GetLibraryVisibilityParams) (LibraryVisibility, error) { - row := q.db.QueryRow(ctx, GetLibraryVisibility, arg.UserID, arg.LibraryID) - var i LibraryVisibility - err := row.Scan( - &i.ID, - &i.UserID, - &i.LibraryID, - &i.IsVisible, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetMediaHighlight = `-- name: GetMediaHighlight :one -SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data FROM media_highlights WHERE id = $1 -` - -func (q *Queries) GetMediaHighlight(ctx context.Context, id pgtype.UUID) (MediaHighlights, error) { - row := q.db.QueryRow(ctx, GetMediaHighlight, id) - var i MediaHighlights - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.SelectionText, - &i.StartPosition, - &i.EndPosition, - &i.Color, - &i.NoteID, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageStart, - &i.PercentageEnd, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiStart, - &i.EpubcfiEnd, - &i.ChapterReference, - &i.ParagraphStart, - &i.ParagraphEnd, - &i.PanelNumber, - &i.DeviceSyncData, - ) - return i, err -} - -const GetMediaHighlights = `-- name: GetMediaHighlights :many -SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC -` - -type GetMediaHighlightsParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) GetMediaHighlights(ctx context.Context, arg GetMediaHighlightsParams) ([]MediaHighlights, error) { - rows, err := q.db.Query(ctx, GetMediaHighlights, arg.MediaItemID, arg.UserID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaHighlights{} - for rows.Next() { - var i MediaHighlights - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.SelectionText, - &i.StartPosition, - &i.EndPosition, - &i.Color, - &i.NoteID, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageStart, - &i.PercentageEnd, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiStart, - &i.EpubcfiEnd, - &i.ChapterReference, - &i.ParagraphStart, - &i.ParagraphEnd, - &i.PanelNumber, - &i.DeviceSyncData, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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, 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) { - row := q.db.QueryRow(ctx, GetMediaItem, id) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, 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 { - FilePath string `db:"file_path" json:"file_path"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` -} - -func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemByFilePathParams) (MediaItems, error) { - row := q.db.QueryRow(ctx, GetMediaItemByFilePath, arg.FilePath, arg.LibraryID) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, 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) { - row := q.db.QueryRow(ctx, GetMediaItemByFilePathAnyLibrary, filePath) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 -` - -// ============================================ -// KOREADER SYNC PROTOCOL -// ============================================ -func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath string) (MediaItems, error) { - row := q.db.QueryRow(ctx, GetMediaItemByFilePathForSync, filePath) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, 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) { - row := q.db.QueryRow(ctx, GetMediaItemByKoboContentId, koboContentID) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, 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 -func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier pgtype.Text) (MediaItems, error) { - row := q.db.QueryRow(ctx, GetMediaItemByOPFIdentifier, opfIdentifier) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, 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 -func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text) (MediaItems, error) { - row := q.db.QueryRow(ctx, GetMediaItemByOPFUUID, opfUuid) - var i MediaItems - err := row.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, - ) - return i, err -} - -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, 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 -func (q *Queries) GetMediaItemBySHA256(ctx context.Context, fileSha256 pgtype.Text) (MediaItems, error) { - row := q.db.QueryRow(ctx, GetMediaItemBySHA256, fileSha256) - var i MediaItems - err := row.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, - ) - return i, err -} - -const GetMediaItemFormatBySHA256 = `-- name: GetMediaItemFormatBySHA256 :one -SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE file_sha256 = $1 -` - -// Get media item format by SHA-256 -func (q *Queries) GetMediaItemFormatBySHA256(ctx context.Context, fileSha256 pgtype.Text) (MediaItemFormats, error) { - row := q.db.QueryRow(ctx, GetMediaItemFormatBySHA256, fileSha256) - var i MediaItemFormats - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.FormatType, - &i.FilePath, - &i.FileSha256, - &i.FileSizeBytes, - &i.MimeType, - &i.CreatedAt, - &i.ConvertedFromFormatID, - ) - return i, err -} - -const GetMediaItemFormatByType = `-- name: GetMediaItemFormatByType :one -SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE media_item_id = $1 AND format_type = $2 -` - -type GetMediaItemFormatByTypeParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - FormatType string `db:"format_type" json:"format_type"` -} - -// Get media item format by type -func (q *Queries) GetMediaItemFormatByType(ctx context.Context, arg GetMediaItemFormatByTypeParams) (MediaItemFormats, error) { - row := q.db.QueryRow(ctx, GetMediaItemFormatByType, arg.MediaItemID, arg.FormatType) - var i MediaItemFormats - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.FormatType, - &i.FilePath, - &i.FileSha256, - &i.FileSizeBytes, - &i.MimeType, - &i.CreatedAt, - &i.ConvertedFromFormatID, - ) - return i, err -} - -const GetMediaItemFormats = `-- name: GetMediaItemFormats :many -SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE media_item_id = $1 -` - -// Get media item formats -func (q *Queries) GetMediaItemFormats(ctx context.Context, mediaItemID pgtype.UUID) ([]MediaItemFormats, error) { - rows, err := q.db.Query(ctx, GetMediaItemFormats, mediaItemID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaItemFormats{} - for rows.Next() { - var i MediaItemFormats - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.FormatType, - &i.FilePath, - &i.FileSha256, - &i.FileSizeBytes, - &i.MimeType, - &i.CreatedAt, - &i.ConvertedFromFormatID, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetMediaNote = `-- name: GetMediaNote :one -SELECT id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data FROM media_notes WHERE id = $1 -` - -func (q *Queries) GetMediaNote(ctx context.Context, id pgtype.UUID) (MediaNotes, error) { - row := q.db.QueryRow(ctx, GetMediaNote, id) - var i MediaNotes - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Content, - &i.Position, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageLocation, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiLocation, - &i.ChapterReference, - &i.ParagraphReference, - &i.DeviceSyncData, - ) - return i, err -} - -const GetMediaNotes = `-- name: GetMediaNotes :many -SELECT id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data FROM media_notes WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC -` - -type GetMediaNotesParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) GetMediaNotes(ctx context.Context, arg GetMediaNotesParams) ([]MediaNotes, error) { - rows, err := q.db.Query(ctx, GetMediaNotes, arg.MediaItemID, arg.UserID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaNotes{} - for rows.Next() { - var i MediaNotes - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Content, - &i.Position, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageLocation, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiLocation, - &i.ChapterReference, - &i.ParagraphReference, - &i.DeviceSyncData, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetMediaRating = `-- name: GetMediaRating :one -SELECT id, media_item_id, user_id, rating, created_at, updated_at FROM media_ratings WHERE media_item_id = $1 AND user_id = $2 -` - -type GetMediaRatingParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) GetMediaRating(ctx context.Context, arg GetMediaRatingParams) (MediaRatings, error) { - row := q.db.QueryRow(ctx, GetMediaRating, arg.MediaItemID, arg.UserID) - var i MediaRatings - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Rating, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetMediaRatings = `-- name: GetMediaRatings :many -SELECT mr.id, mr.media_item_id, mr.user_id, mr.rating, mr.created_at, mr.updated_at, u.username -FROM media_ratings mr -JOIN users u ON mr.user_id = u.id -WHERE mr.media_item_id = $1 -ORDER BY mr.created_at DESC -` - -type GetMediaRatingsRow struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Rating int32 `db:"rating" json:"rating"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - Username string `db:"username" json:"username"` -} - -func (q *Queries) GetMediaRatings(ctx context.Context, mediaItemID pgtype.UUID) ([]GetMediaRatingsRow, error) { - rows, err := q.db.Query(ctx, GetMediaRatings, mediaItemID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetMediaRatingsRow{} - for rows.Next() { - var i GetMediaRatingsRow - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Rating, - &i.CreatedAt, - &i.UpdatedAt, - &i.Username, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetNextRetryTime = `-- name: GetNextRetryTime :one -SELECT - CASE - WHEN attempts = 0 THEN NOW() - WHEN attempts = 1 THEN NOW() + INTERVAL '1 minute' - WHEN attempts = 2 THEN NOW() + INTERVAL '5 minutes' - WHEN attempts = 3 THEN NOW() + INTERVAL '15 minutes' - WHEN attempts = 4 THEN NOW() + INTERVAL '1 hour' - ELSE NOW() + INTERVAL '24 hours' - END as next_retry_time -` - -func (q *Queries) GetNextRetryTime(ctx context.Context) (interface{}, error) { - row := q.db.QueryRow(ctx, GetNextRetryTime) - var next_retry_time interface{} - err := row.Scan(&next_retry_time) - return next_retry_time, err -} - -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.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 - WHERE rp.media_item_id = mi.id - AND rp.user_id = $2 - AND rp.percentage > 0 - ) -ORDER BY mi.created_at DESC -LIMIT $3 -` - -type GetNotStartedItemsParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Limit int32 `db:"limit" json:"limit"` -} - -func (q *Queries) GetNotStartedItems(ctx context.Context, arg GetNotStartedItemsParams) ([]MediaItems, error) { - rows, err := q.db.Query(ctx, GetNotStartedItems, arg.LibraryID, arg.UserID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaItems{} - for rows.Next() { - var i MediaItems - 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, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetOpdsToken = `-- name: GetOpdsToken :one -SELECT ot.id, ot.device_id, ot.token, ot.token_type, ot.expires_at, ot.created_at, d.device_name, d.device_type -FROM opds_tokens ot -JOIN devices d ON ot.device_id = d.id -WHERE ot.token = $1 AND ot.expires_at > NOW() -` - -type GetOpdsTokenRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - Token string `db:"token" json:"token"` - TokenType pgtype.Text `db:"token_type" json:"token_type"` - ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - DeviceName string `db:"device_name" json:"device_name"` - DeviceType string `db:"device_type" json:"device_type"` -} - -// Get OPDS token -func (q *Queries) GetOpdsToken(ctx context.Context, token string) (GetOpdsTokenRow, error) { - row := q.db.QueryRow(ctx, GetOpdsToken, token) - var i GetOpdsTokenRow - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.Token, - &i.TokenType, - &i.ExpiresAt, - &i.CreatedAt, - &i.DeviceName, - &i.DeviceType, - ) - return i, err -} - -const GetOpdsTokensByDevice = `-- name: GetOpdsTokensByDevice :many -SELECT id, device_id, token, token_type, expires_at, created_at FROM opds_tokens WHERE device_id = $1 AND expires_at > NOW() -` - -// Get OPDS tokens by device -func (q *Queries) GetOpdsTokensByDevice(ctx context.Context, deviceID pgtype.UUID) ([]OpdsTokens, error) { - rows, err := q.db.Query(ctx, GetOpdsTokensByDevice, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []OpdsTokens{} - for rows.Next() { - var i OpdsTokens - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.Token, - &i.TokenType, - &i.ExpiresAt, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetPopularBooks = `-- name: GetPopularBooks :many -SELECT - mi.id, - mi.title, - mi.author, - COUNT(*) as read_count, - AVG(rh.progress_percentage) as avg_completion, - MAX(rh.created_at) as last_read - FROM media_items mi - JOIN reading_history rh ON rh.media_item_id = mi.id - WHERE rh.user_id = $1 - GROUP BY mi.id, mi.title, mi.author - ORDER BY read_count DESC - LIMIT $2 -` - -type GetPopularBooksParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Limit int32 `db:"limit" json:"limit"` -} - -type GetPopularBooksRow struct { - ID pgtype.UUID `db:"id" json:"id"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - ReadCount int64 `db:"read_count" json:"read_count"` - AvgCompletion float64 `db:"avg_completion" json:"avg_completion"` - LastRead interface{} `db:"last_read" json:"last_read"` -} - -// Get most popular books for a user -func (q *Queries) GetPopularBooks(ctx context.Context, arg GetPopularBooksParams) ([]GetPopularBooksRow, error) { - rows, err := q.db.Query(ctx, GetPopularBooks, arg.UserID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetPopularBooksRow{} - for rows.Next() { - var i GetPopularBooksRow - if err := rows.Scan( - &i.ID, - &i.Title, - &i.Author, - &i.ReadCount, - &i.AvgCompletion, - &i.LastRead, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetReadingHistory = `-- name: GetReadingHistory :many -SELECT id, user_id, media_item_id, device_id, progress_percentage, reading_session_start, reading_session_end, pages_read, time_spent_seconds, device_metadata, created_at -FROM reading_history -WHERE user_id = $1 AND media_item_id = $2 -ORDER BY created_at DESC -LIMIT $3 -` - -type GetReadingHistoryParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - Limit int32 `db:"limit" json:"limit"` -} - -// Get reading history for a user and book -func (q *Queries) GetReadingHistory(ctx context.Context, arg GetReadingHistoryParams) ([]ReadingHistory, error) { - rows, err := q.db.Query(ctx, GetReadingHistory, arg.UserID, arg.MediaItemID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ReadingHistory{} - for rows.Next() { - var i ReadingHistory - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.MediaItemID, - &i.DeviceID, - &i.ProgressPercentage, - &i.ReadingSessionStart, - &i.ReadingSessionEnd, - &i.PagesRead, - &i.TimeSpentSeconds, - &i.DeviceMetadata, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetReadingProgress = `-- name: GetReadingProgress :one -SELECT id, media_item_id, user_id, current_page, total_pages, last_read_at, percentage, character_offset, epubcfi, chapter, chapter_progress, viewport_x, viewport_y, zoom_level, scroll_position_x, scroll_position_y, panel_number, reading_mode, last_sync_device, last_sync_source, last_sync_timestamp, conflict_detected, conflict_resolved FROM reading_progress WHERE media_item_id = $1 AND user_id = $2 -` - -type GetReadingProgressParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) GetReadingProgress(ctx context.Context, arg GetReadingProgressParams) (ReadingProgress, error) { - row := q.db.QueryRow(ctx, GetReadingProgress, arg.MediaItemID, arg.UserID) - var i ReadingProgress - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.CurrentPage, - &i.TotalPages, - &i.LastReadAt, - &i.Percentage, - &i.CharacterOffset, - &i.Epubcfi, - &i.Chapter, - &i.ChapterProgress, - &i.ViewportX, - &i.ViewportY, - &i.ZoomLevel, - &i.ScrollPositionX, - &i.ScrollPositionY, - &i.PanelNumber, - &i.ReadingMode, - &i.LastSyncDevice, - &i.LastSyncSource, - &i.LastSyncTimestamp, - &i.ConflictDetected, - &i.ConflictResolved, - ) - return i, err -} - -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.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 -LIMIT $2 -` - -type GetRecentlyAddedItemsParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - Limit int32 `db:"limit" json:"limit"` -} - -func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAddedItemsParams) ([]MediaItems, error) { - rows, err := q.db.Query(ctx, GetRecentlyAddedItems, arg.LibraryID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaItems{} - for rows.Next() { - var i MediaItems - 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, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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.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 - WHERE user_id = $2 - AND percentage >= 1 - ORDER BY media_item_id, last_read_at DESC -) rp ON rp.media_item_id = mi.id -WHERE mi.library_id = $1 -ORDER BY rp.last_read_at DESC -LIMIT $3 -` - -type GetRecentlyReadItemsParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Limit int32 `db:"limit" json:"limit"` -} - -func (q *Queries) GetRecentlyReadItems(ctx context.Context, arg GetRecentlyReadItemsParams) ([]MediaItems, error) { - rows, err := q.db.Query(ctx, GetRecentlyReadItems, arg.LibraryID, arg.UserID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []MediaItems{} - for rows.Next() { - var i MediaItems - 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, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetRefreshToken = `-- name: GetRefreshToken :one -SELECT rt.id, rt.user_id, rt.token, rt.expires_at, rt.created_at, rt.revoked_at, u.email, u.username, u.role -FROM refresh_tokens rt -JOIN users u ON rt.user_id = u.id -WHERE rt.token = $1 AND rt.revoked_at IS NULL AND rt.expires_at > NOW() -` - -type GetRefreshTokenRow struct { - ID pgtype.UUID `db:"id" json:"id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Token pgtype.UUID `db:"token" json:"token"` - ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - RevokedAt pgtype.Timestamptz `db:"revoked_at" json:"revoked_at"` - Email string `db:"email" json:"email"` - Username string `db:"username" json:"username"` - Role string `db:"role" json:"role"` -} - -func (q *Queries) GetRefreshToken(ctx context.Context, token pgtype.UUID) (GetRefreshTokenRow, error) { - row := q.db.QueryRow(ctx, GetRefreshToken, token) - var i GetRefreshTokenRow - err := row.Scan( - &i.ID, - &i.UserID, - &i.Token, - &i.ExpiresAt, - &i.CreatedAt, - &i.RevokedAt, - &i.Email, - &i.Username, - &i.Role, - ) - return i, err -} - -const GetStuckSyncQueueItems = `-- name: GetStuckSyncQueueItems :many -SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue -WHERE status = 'processing' AND created_at < NOW() - INTERVAL '1 hour' -ORDER BY priority ASC, created_at ASC -` - -func (q *Queries) GetStuckSyncQueueItems(ctx context.Context) ([]SyncQueue, error) { - rows, err := q.db.Query(ctx, GetStuckSyncQueueItems) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SyncQueue{} - for rows.Next() { - var i SyncQueue - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetSyncConflict = `-- name: GetSyncConflict :one -SELECT id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at FROM sync_conflicts WHERE id = $1 -` - -func (q *Queries) GetSyncConflict(ctx context.Context, id pgtype.UUID) (SyncConflicts, error) { - row := q.db.QueryRow(ctx, GetSyncConflict, id) - var i SyncConflicts - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.ConflictType, - &i.ConflictData, - &i.ResolutionStatus, - &i.ResolutionData, - &i.ResolvedBy, - &i.ResolvedAt, - &i.CreatedAt, - ) - return i, err -} - -const GetSyncQueueItem = `-- name: GetSyncQueueItem :one -SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue WHERE id = $1 -` - -func (q *Queries) GetSyncQueueItem(ctx context.Context, id pgtype.UUID) (SyncQueue, error) { - row := q.db.QueryRow(ctx, GetSyncQueueItem, id) - var i SyncQueue - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ) - return i, err -} - -const GetSyncQueueStats = `-- name: GetSyncQueueStats :one -SELECT - COUNT(*) FILTER (WHERE status = 'pending') as pending_count, - COUNT(*) FILTER (WHERE status = 'processing') as processing_count, - COUNT(*) FILTER (WHERE status = 'failed') as failed_count, - COUNT(*) FILTER (WHERE status = 'completed') as completed_count, - COUNT(*) as total_count -FROM sync_queue -WHERE device_id = $1 -` - -type GetSyncQueueStatsRow struct { - PendingCount int64 `db:"pending_count" json:"pending_count"` - ProcessingCount int64 `db:"processing_count" json:"processing_count"` - FailedCount int64 `db:"failed_count" json:"failed_count"` - CompletedCount int64 `db:"completed_count" json:"completed_count"` - TotalCount int64 `db:"total_count" json:"total_count"` -} - -func (q *Queries) GetSyncQueueStats(ctx context.Context, deviceID pgtype.UUID) (GetSyncQueueStatsRow, error) { - row := q.db.QueryRow(ctx, GetSyncQueueStats, deviceID) - var i GetSyncQueueStatsRow - err := row.Scan( - &i.PendingCount, - &i.ProcessingCount, - &i.FailedCount, - &i.CompletedCount, - &i.TotalCount, - ) - return i, err -} - -const GetSystemCollectionsForDashboard = `-- name: GetSystemCollectionsForDashboard :many -SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections -WHERE user_id = $1 - AND is_system_collection = true - AND show_on_dashboard = true -ORDER BY priority ASC -` - -// Dashboard collections queries -func (q *Queries) GetSystemCollectionsForDashboard(ctx context.Context, userID pgtype.UUID) ([]Collections, error) { - rows, err := q.db.Query(ctx, GetSystemCollectionsForDashboard, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Collections{} - for rows.Next() { - var i Collections - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetSystemConfig = `-- name: GetSystemConfig :one - -SELECT key, value, updated_at, updated_by FROM system_config WHERE key = $1 -` - -// SYSTEM CONFIG QUERIES -// Get system config -func (q *Queries) GetSystemConfig(ctx context.Context, key string) (SystemConfig, error) { - row := q.db.QueryRow(ctx, GetSystemConfig, key) - var i SystemConfig - err := row.Scan( - &i.Key, - &i.Value, - &i.UpdatedAt, - &i.UpdatedBy, - ) - return i, err -} - -const GetSystemSetting = `-- name: GetSystemSetting :one -SELECT setting_value FROM system_settings WHERE setting_key = $1 -` - -// System Settings queries -func (q *Queries) GetSystemSetting(ctx context.Context, settingKey string) (string, error) { - row := q.db.QueryRow(ctx, GetSystemSetting, settingKey) - var setting_value string - err := row.Scan(&setting_value) - return setting_value, err -} - -const GetUniversalProgress = `-- name: GetUniversalProgress :one -SELECT - rp.id, - rp.media_item_id, - rp.user_id, - rp.current_page, - rp.total_pages, - rp.last_read_at, - rp.percentage, - rp.character_offset, - rp.epubcfi, - rp.chapter, - rp.chapter_progress, - rp.viewport_x, - rp.viewport_y, - rp.zoom_level, - rp.scroll_position_x, - rp.scroll_position_y, - rp.panel_number, - rp.reading_mode, - rp.last_sync_device, - rp.last_sync_source, - rp.last_sync_timestamp, - rp.conflict_detected, - rp.conflict_resolved, - mi.format_group, - mi.format_mimetype, - mi.is_reflowable, - mi.has_fixed_layout, - mi.total_characters, - mi.chapter_count -FROM reading_progress rp -JOIN media_items mi ON rp.media_item_id = mi.id -WHERE rp.media_item_id = $1 AND rp.user_id = $2 -` - -type GetUniversalProgressParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -type GetUniversalProgressRow struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"` - TotalPages pgtype.Int4 `db:"total_pages" json:"total_pages"` - LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"` - Percentage pgtype.Float8 `db:"percentage" json:"percentage"` - CharacterOffset pgtype.Int8 `db:"character_offset" json:"character_offset"` - Epubcfi pgtype.Text `db:"epubcfi" json:"epubcfi"` - Chapter pgtype.Int4 `db:"chapter" json:"chapter"` - ChapterProgress pgtype.Float8 `db:"chapter_progress" json:"chapter_progress"` - ViewportX pgtype.Float8 `db:"viewport_x" json:"viewport_x"` - ViewportY pgtype.Float8 `db:"viewport_y" json:"viewport_y"` - ZoomLevel pgtype.Float8 `db:"zoom_level" json:"zoom_level"` - ScrollPositionX pgtype.Float8 `db:"scroll_position_x" json:"scroll_position_x"` - ScrollPositionY pgtype.Float8 `db:"scroll_position_y" json:"scroll_position_y"` - PanelNumber pgtype.Int4 `db:"panel_number" json:"panel_number"` - ReadingMode pgtype.Text `db:"reading_mode" json:"reading_mode"` - LastSyncDevice pgtype.Text `db:"last_sync_device" json:"last_sync_device"` - LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"` - LastSyncTimestamp pgtype.Timestamptz `db:"last_sync_timestamp" json:"last_sync_timestamp"` - ConflictDetected pgtype.Bool `db:"conflict_detected" json:"conflict_detected"` - ConflictResolved pgtype.Bool `db:"conflict_resolved" json:"conflict_resolved"` - 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"` -} - -// Get universal progress for a book -func (q *Queries) GetUniversalProgress(ctx context.Context, arg GetUniversalProgressParams) (GetUniversalProgressRow, error) { - row := q.db.QueryRow(ctx, GetUniversalProgress, arg.MediaItemID, arg.UserID) - var i GetUniversalProgressRow - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.CurrentPage, - &i.TotalPages, - &i.LastReadAt, - &i.Percentage, - &i.CharacterOffset, - &i.Epubcfi, - &i.Chapter, - &i.ChapterProgress, - &i.ViewportX, - &i.ViewportY, - &i.ZoomLevel, - &i.ScrollPositionX, - &i.ScrollPositionY, - &i.PanelNumber, - &i.ReadingMode, - &i.LastSyncDevice, - &i.LastSyncSource, - &i.LastSyncTimestamp, - &i.ConflictDetected, - &i.ConflictResolved, - &i.FormatGroup, - &i.FormatMimetype, - &i.IsReflowable, - &i.HasFixedLayout, - &i.TotalCharacters, - &i.ChapterCount, - ) - return i, err -} - -const GetUnlinkedBookByContentId = `-- name: GetUnlinkedBookByContentId :one -SELECT id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at FROM unlinked_books WHERE device_id = $1 AND content_id = $2 -` - -type GetUnlinkedBookByContentIdParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ContentID string `db:"content_id" json:"content_id"` -} - -// Get unlinked book by ContentId -func (q *Queries) GetUnlinkedBookByContentId(ctx context.Context, arg GetUnlinkedBookByContentIdParams) (UnlinkedBooks, error) { - row := q.db.QueryRow(ctx, GetUnlinkedBookByContentId, arg.DeviceID, arg.ContentID) - var i UnlinkedBooks - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - ) - return i, err -} - -const GetUnlinkedBookByID = `-- name: GetUnlinkedBookByID :one -SELECT id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at FROM unlinked_books WHERE id = $1 -` - -// Get unlinked book by ID -func (q *Queries) GetUnlinkedBookByID(ctx context.Context, id pgtype.UUID) (UnlinkedBooks, error) { - row := q.db.QueryRow(ctx, GetUnlinkedBookByID, id) - var i UnlinkedBooks - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - ) - return i, err -} - -const GetUnlinkedBooksByDevice = `-- name: GetUnlinkedBooksByDevice :many -SELECT ub.id, ub.device_id, ub.content_id, ub.file_path, ub.title, ub.author, ub.confidence_score, ub.resolved, ub.media_item_id, ub.resolved_at, ub.resolution_method, ub.last_seen_at, ub.created_at, d.device_name, d.device_type -FROM unlinked_books ub -JOIN devices d ON ub.device_id = d.id -WHERE ub.device_id = $1 AND ub.resolved = false -ORDER BY ub.last_seen_at DESC -` - -type GetUnlinkedBooksByDeviceRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ContentID string `db:"content_id" json:"content_id"` - FilePath pgtype.Text `db:"file_path" json:"file_path"` - Title pgtype.Text `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` - Resolved pgtype.Bool `db:"resolved" json:"resolved"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"` - ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"` - LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - DeviceName string `db:"device_name" json:"device_name"` - DeviceType string `db:"device_type" json:"device_type"` -} - -// Get unlinked books for a device -func (q *Queries) GetUnlinkedBooksByDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetUnlinkedBooksByDeviceRow, error) { - rows, err := q.db.Query(ctx, GetUnlinkedBooksByDevice, deviceID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetUnlinkedBooksByDeviceRow{} - for rows.Next() { - var i GetUnlinkedBooksByDeviceRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - &i.DeviceName, - &i.DeviceType, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetUser = `-- name: GetUser :one -SELECT - u.id, - u.email, - u.username, - u.theme, - u.first_name, - u.last_name, - u.role, - u.max_devices, - u.created_at, - u.updated_at, - (SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count -FROM users u -WHERE u.id = $1 -` - -type GetUserRow 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"` - DeviceCount int64 `db:"device_count" json:"device_count"` -} - -func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, error) { - row := q.db.QueryRow(ctx, GetUser, id) - var i GetUserRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.MaxDevices, - &i.CreatedAt, - &i.UpdatedAt, - &i.DeviceCount, - ) - return i, err -} - -const GetUserByEmail = `-- name: GetUserByEmail :one -SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 -` - -type GetUserByEmailRow 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"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` -} - -func (q *Queries) GetUserByEmail(ctx context.Context, email string) (GetUserByEmailRow, error) { - row := q.db.QueryRow(ctx, GetUserByEmail, email) - var i GetUserByEmailRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one -SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1 -` - -type GetUserByEmailOrUsernameRow 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"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` -} - -func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (GetUserByEmailOrUsernameRow, error) { - row := q.db.QueryRow(ctx, GetUserByEmailOrUsername, email) - var i GetUserByEmailOrUsernameRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetUserByUsername = `-- name: GetUserByUsername :one -SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE username = $1 -` - -type GetUserByUsernameRow 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"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` -} - -func (q *Queries) GetUserByUsername(ctx context.Context, username string) (GetUserByUsernameRow, error) { - row := q.db.QueryRow(ctx, GetUserByUsername, username) - var i GetUserByUsernameRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetUserCollectionsForDashboard = `-- name: GetUserCollectionsForDashboard :many -SELECT c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at FROM collections c -WHERE c.user_id = $1 - AND c.show_on_dashboard = true - AND c.is_system_collection = false -ORDER BY priority ASC -` - -func (q *Queries) GetUserCollectionsForDashboard(ctx context.Context, userID pgtype.UUID) ([]Collections, error) { - rows, err := q.db.Query(ctx, GetUserCollectionsForDashboard, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Collections{} - for rows.Next() { - var i Collections - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetUserDeviceUsage = `-- name: GetUserDeviceUsage :many -SELECT - d.id, - d.device_name, - d.device_type, - COUNT(*) as sync_count, - MAX(rh.created_at) as last_sync, - SUM(rh.time_spent_seconds) as total_time_seconds -FROM devices d -JOIN reading_history rh ON rh.device_id = d.id -WHERE d.user_id = $1 -GROUP BY d.id, d.device_name, d.device_type -ORDER BY sync_count DESC -` - -type GetUserDeviceUsageRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceName string `db:"device_name" json:"device_name"` - DeviceType string `db:"device_type" json:"device_type"` - SyncCount int64 `db:"sync_count" json:"sync_count"` - LastSync interface{} `db:"last_sync" json:"last_sync"` - TotalTimeSeconds int64 `db:"total_time_seconds" json:"total_time_seconds"` -} - -// Get user device usage statistics -func (q *Queries) GetUserDeviceUsage(ctx context.Context, userID pgtype.UUID) ([]GetUserDeviceUsageRow, error) { - rows, err := q.db.Query(ctx, GetUserDeviceUsage, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetUserDeviceUsageRow{} - for rows.Next() { - var i GetUserDeviceUsageRow - if err := rows.Scan( - &i.ID, - &i.DeviceName, - &i.DeviceType, - &i.SyncCount, - &i.LastSync, - &i.TotalTimeSeconds, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetUserForLogin = `-- name: GetUserForLogin :one -SELECT id, email, username, password_hash, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1 -` - -type GetUserForLoginRow struct { - ID pgtype.UUID `db:"id" json:"id"` - Email string `db:"email" json:"email"` - Username string `db:"username" json:"username"` - PasswordHash string `db:"password_hash" json:"password_hash"` - 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"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` -} - -func (q *Queries) GetUserForLogin(ctx context.Context, email string) (GetUserForLoginRow, error) { - row := q.db.QueryRow(ctx, GetUserForLogin, email) - var i GetUserForLoginRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.PasswordHash, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const GetUserMediaItemsForSync = `-- name: GetUserMediaItemsForSync :many -SELECT - mi.id, - mi.title, - mi.author, - mi.file_path, - mi.mime_type, - mi.page_count, - mi.format_group, - mi.total_characters, - mi.chapter_count, - mi.entitlement_id, - mi.revision_number, - mi.file_size, - mi.file_sha256 -FROM media_items mi -JOIN library_visibility lv ON mi.library_id = lv.library_id -WHERE lv.user_id = $1 - AND lv.is_visible = true -ORDER BY mi.title ASC -LIMIT 1000 -` - -type GetUserMediaItemsForSyncRow struct { - ID pgtype.UUID `db:"id" json:"id"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` - PageCount pgtype.Int4 `db:"page_count" json:"page_count"` - FormatGroup string `db:"format_group" json:"format_group"` - 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"` - FileSize pgtype.Int8 `db:"file_size" json:"file_size"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` -} - -func (q *Queries) GetUserMediaItemsForSync(ctx context.Context, userID pgtype.UUID) ([]GetUserMediaItemsForSyncRow, error) { - rows, err := q.db.Query(ctx, GetUserMediaItemsForSync, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetUserMediaItemsForSyncRow{} - for rows.Next() { - var i GetUserMediaItemsForSyncRow - if err := rows.Scan( - &i.ID, - &i.Title, - &i.Author, - &i.FilePath, - &i.MimeType, - &i.PageCount, - &i.FormatGroup, - &i.TotalCharacters, - &i.ChapterCount, - &i.EntitlementID, - &i.RevisionNumber, - &i.FileSize, - &i.FileSha256, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetUserPasswordHash = `-- name: GetUserPasswordHash :one -SELECT password_hash FROM users WHERE id = $1 -` - -func (q *Queries) GetUserPasswordHash(ctx context.Context, id pgtype.UUID) (string, error) { - row := q.db.QueryRow(ctx, GetUserPasswordHash, id) - var password_hash string - err := row.Scan(&password_hash) - return password_hash, err -} - -const GetUserProgressForBooks = `-- name: GetUserProgressForBooks :many -SELECT - rp.media_item_id, - rp.user_id, - rp.percentage, - rp.character_offset, - rp.epubcfi, - rp.chapter, - rp.chapter_progress, - rp.current_page, - rp.total_pages, - rp.last_read_at, - rp.last_sync_device, - rp.last_sync_source, - mi.title, - mi.author, - mi.file_path -FROM reading_progress rp -JOIN media_items mi ON rp.media_item_id = mi.id -WHERE rp.user_id = $1 - AND rp.media_item_id = ANY($2::uuid[]) -ORDER BY rp.last_read_at DESC -` - -type GetUserProgressForBooksParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Column2 []pgtype.UUID `db:"column_2" json:"column_2"` -} - -type GetUserProgressForBooksRow struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Percentage pgtype.Float8 `db:"percentage" json:"percentage"` - CharacterOffset pgtype.Int8 `db:"character_offset" json:"character_offset"` - Epubcfi pgtype.Text `db:"epubcfi" json:"epubcfi"` - Chapter pgtype.Int4 `db:"chapter" json:"chapter"` - ChapterProgress pgtype.Float8 `db:"chapter_progress" json:"chapter_progress"` - CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"` - TotalPages pgtype.Int4 `db:"total_pages" json:"total_pages"` - LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"` - LastSyncDevice pgtype.Text `db:"last_sync_device" json:"last_sync_device"` - LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FilePath string `db:"file_path" json:"file_path"` -} - -func (q *Queries) GetUserProgressForBooks(ctx context.Context, arg GetUserProgressForBooksParams) ([]GetUserProgressForBooksRow, error) { - rows, err := q.db.Query(ctx, GetUserProgressForBooks, arg.UserID, arg.Column2) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetUserProgressForBooksRow{} - for rows.Next() { - var i GetUserProgressForBooksRow - if err := rows.Scan( - &i.MediaItemID, - &i.UserID, - &i.Percentage, - &i.CharacterOffset, - &i.Epubcfi, - &i.Chapter, - &i.ChapterProgress, - &i.CurrentPage, - &i.TotalPages, - &i.LastReadAt, - &i.LastSyncDevice, - &i.LastSyncSource, - &i.Title, - &i.Author, - &i.FilePath, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetUserReadingHistory = `-- name: GetUserReadingHistory :many - -SELECT - rh.id, - rh.user_id, - rh.media_item_id, - rh.device_id, - rh.progress_percentage, - rh.reading_session_start, - rh.reading_session_end, - rh.pages_read, - rh.time_spent_seconds, - rh.device_metadata, - rh.created_at, - mi.title, - mi.author, - d.device_name, - d.device_type -FROM reading_history rh -JOIN media_items mi ON rh.media_item_id = mi.id -LEFT JOIN devices d ON rh.device_id = d.id -WHERE rh.user_id = $1 - AND rh.created_at >= $2 - AND rh.created_at <= $3 -ORDER BY rh.created_at DESC -` - -type GetUserReadingHistoryParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - CreatedAt_2 pgtype.Timestamptz `db:"created_at_2" json:"created_at_2"` -} - -type GetUserReadingHistoryRow struct { - ID pgtype.UUID `db:"id" json:"id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ProgressPercentage pgtype.Float8 `db:"progress_percentage" json:"progress_percentage"` - ReadingSessionStart pgtype.Timestamptz `db:"reading_session_start" json:"reading_session_start"` - ReadingSessionEnd pgtype.Timestamptz `db:"reading_session_end" json:"reading_session_end"` - PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"` - TimeSpentSeconds pgtype.Int4 `db:"time_spent_seconds" json:"time_spent_seconds"` - DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - DeviceName pgtype.Text `db:"device_name" json:"device_name"` - DeviceType pgtype.Text `db:"device_type" json:"device_type"` -} - -// Analytics queries -// Get user reading history for analytics -func (q *Queries) GetUserReadingHistory(ctx context.Context, arg GetUserReadingHistoryParams) ([]GetUserReadingHistoryRow, error) { - rows, err := q.db.Query(ctx, GetUserReadingHistory, arg.UserID, arg.CreatedAt, arg.CreatedAt_2) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetUserReadingHistoryRow{} - for rows.Next() { - var i GetUserReadingHistoryRow - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.MediaItemID, - &i.DeviceID, - &i.ProgressPercentage, - &i.ReadingSessionStart, - &i.ReadingSessionEnd, - &i.PagesRead, - &i.TimeSpentSeconds, - &i.DeviceMetadata, - &i.CreatedAt, - &i.Title, - &i.Author, - &i.DeviceName, - &i.DeviceType, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const GetUserVisibleLibraries = `-- name: GetUserVisibleLibraries :many -SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description, - COALESCE(lv.is_visible, true) as is_visible -FROM libraries l -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 -ORDER BY l.created_at ASC -` - -type GetUserVisibleLibrariesRow struct { - 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"` - TypeName string `db:"type_name" json:"type_name"` - TypeDescription pgtype.Text `db:"type_description" json:"type_description"` - IsVisible bool `db:"is_visible" json:"is_visible"` -} - -func (q *Queries) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]GetUserVisibleLibrariesRow, error) { - rows, err := q.db.Query(ctx, GetUserVisibleLibraries, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []GetUserVisibleLibrariesRow{} - for rows.Next() { - var i GetUserVisibleLibrariesRow - if err := rows.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.LibraryTypeID, - &i.CreatedByAdminID, - &i.CreatedAt, - &i.UpdatedAt, - &i.TypeName, - &i.TypeDescription, - &i.IsVisible, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const IncrementSyncQueueAttempts = `-- name: IncrementSyncQueueAttempts :one -UPDATE sync_queue -SET - attempts = attempts + 1, - status = CASE - WHEN attempts + 1 >= max_attempts THEN 'failed' - ELSE 'pending' - END, - error_message = $2 -WHERE id = $1 -RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at -` - -type IncrementSyncQueueAttemptsParams struct { - ID pgtype.UUID `db:"id" json:"id"` - ErrorMessage pgtype.Text `db:"error_message" json:"error_message"` -} - -func (q *Queries) IncrementSyncQueueAttempts(ctx context.Context, arg IncrementSyncQueueAttemptsParams) (SyncQueue, error) { - row := q.db.QueryRow(ctx, IncrementSyncQueueAttempts, arg.ID, arg.ErrorMessage) - var i SyncQueue - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ) - return i, err -} - -const IsBookInCollection = `-- name: IsBookInCollection :one -SELECT EXISTS( - SELECT 1 FROM collection_items - WHERE collection_id = $1 AND media_item_id = $2 -) as in_collection -` - -type IsBookInCollectionParams struct { - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` -} - -// Check if book is in collection -func (q *Queries) IsBookInCollection(ctx context.Context, arg IsBookInCollectionParams) (bool, error) { - row := q.db.QueryRow(ctx, IsBookInCollection, arg.CollectionID, arg.MediaItemID) - var in_collection bool - err := row.Scan(&in_collection) - return in_collection, err -} - -const IsBookOnKoboShelf = `-- name: IsBookOnKoboShelf :one -SELECT EXISTS( - SELECT 1 FROM kobo_shelves - WHERE device_id = $1 AND media_item_id = $2 -) as on_shelf -` - -type IsBookOnKoboShelfParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` -} - -func (q *Queries) IsBookOnKoboShelf(ctx context.Context, arg IsBookOnKoboShelfParams) (bool, error) { - row := q.db.QueryRow(ctx, IsBookOnKoboShelf, arg.DeviceID, arg.MediaItemID) - var on_shelf bool - err := row.Scan(&on_shelf) - return on_shelf, err -} - -const LinkUnlinkedBook = `-- name: LinkUnlinkedBook :one -UPDATE unlinked_books -SET - media_item_id = $2, - confidence_score = $3, - resolved = true, - resolved_at = NOW(), - resolution_method = 'manual_link' -WHERE id = $1 -RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at -` - -type LinkUnlinkedBookParams struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` -} - -// Link unlinked book to media item -func (q *Queries) LinkUnlinkedBook(ctx context.Context, arg LinkUnlinkedBookParams) (UnlinkedBooks, error) { - row := q.db.QueryRow(ctx, LinkUnlinkedBook, arg.ID, arg.MediaItemID, arg.ConfidenceScore) - var i UnlinkedBooks - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - ) - return i, err -} - -const ListAllSyncQueueItems = `-- name: ListAllSyncQueueItems :many -SELECT - sq.id, sq.device_id, sq.media_item_id, sq.sync_type, sq.sync_data, sq.priority, sq.attempts, sq.max_attempts, sq.status, sq.error_message, sq.created_at, sq.processed_at, - d.device_name, - d.device_type, - u.email as user_email, - mi.title as media_title -FROM sync_queue sq -JOIN devices d ON sq.device_id = d.id -JOIN users u ON d.user_id = u.id -LEFT JOIN media_items mi ON sq.media_item_id = mi.id -ORDER BY sq.priority ASC, sq.created_at DESC -LIMIT $1 OFFSET $2 -` - -type ListAllSyncQueueItemsParams struct { - Limit int32 `db:"limit" json:"limit"` - Offset int32 `db:"offset" json:"offset"` -} - -type ListAllSyncQueueItemsRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - SyncType string `db:"sync_type" json:"sync_type"` - SyncData []byte `db:"sync_data" json:"sync_data"` - Priority pgtype.Int4 `db:"priority" json:"priority"` - Attempts pgtype.Int4 `db:"attempts" json:"attempts"` - MaxAttempts pgtype.Int4 `db:"max_attempts" json:"max_attempts"` - Status pgtype.Text `db:"status" json:"status"` - ErrorMessage pgtype.Text `db:"error_message" json:"error_message"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - ProcessedAt pgtype.Timestamptz `db:"processed_at" json:"processed_at"` - DeviceName string `db:"device_name" json:"device_name"` - DeviceType string `db:"device_type" json:"device_type"` - UserEmail string `db:"user_email" json:"user_email"` - MediaTitle pgtype.Text `db:"media_title" json:"media_title"` -} - -func (q *Queries) ListAllSyncQueueItems(ctx context.Context, arg ListAllSyncQueueItemsParams) ([]ListAllSyncQueueItemsRow, error) { - rows, err := q.db.Query(ctx, ListAllSyncQueueItems, arg.Limit, arg.Offset) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListAllSyncQueueItemsRow{} - for rows.Next() { - var i ListAllSyncQueueItemsRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - &i.DeviceName, - &i.DeviceType, - &i.UserEmail, - &i.MediaTitle, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListDevicesByType = `-- name: ListDevicesByType :many -SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_type = $1 ORDER BY created_at DESC -` - -func (q *Queries) ListDevicesByType(ctx context.Context, deviceType string) ([]Devices, error) { - rows, err := q.db.Query(ctx, ListDevicesByType, deviceType) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Devices{} - for rows.Next() { - var i Devices - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListDevicesByUser = `-- name: ListDevicesByUser :many -SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE user_id = $1 ORDER BY created_at DESC -` - -func (q *Queries) ListDevicesByUser(ctx context.Context, userID pgtype.UUID) ([]Devices, error) { - rows, err := q.db.Query(ctx, ListDevicesByUser, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Devices{} - for rows.Next() { - var i Devices - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListLibraries = `-- name: ListLibraries :many -SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description -FROM libraries l -JOIN library_types lt ON l.library_type_id = lt.id -ORDER BY l.created_at DESC -` - -type ListLibrariesRow struct { - 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"` - TypeName string `db:"type_name" json:"type_name"` - TypeDescription pgtype.Text `db:"type_description" json:"type_description"` -} - -func (q *Queries) ListLibraries(ctx context.Context) ([]ListLibrariesRow, error) { - rows, err := q.db.Query(ctx, ListLibraries) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListLibrariesRow{} - for rows.Next() { - var i ListLibrariesRow - if err := rows.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.LibraryTypeID, - &i.CreatedByAdminID, - &i.CreatedAt, - &i.UpdatedAt, - &i.TypeName, - &i.TypeDescription, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -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.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 -ORDER BY mi.created_at DESC LIMIT $1 OFFSET $2 -` - -type ListMediaItemsParams struct { - Limit int32 `db:"limit" json:"limit"` - Offset int32 `db:"offset" json:"offset"` -} - -type ListMediaItemsRow 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) ListMediaItems(ctx context.Context, arg ListMediaItemsParams) ([]ListMediaItemsRow, error) { - rows, err := q.db.Query(ctx, ListMediaItems, arg.Limit, arg.Offset) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListMediaItemsRow{} - for rows.Next() { - var i ListMediaItemsRow - 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 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.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 -WHERE mi.library_id = $1 -ORDER BY mi.created_at DESC -` - -type ListMediaItemsByLibraryRow 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) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.UUID) ([]ListMediaItemsByLibraryRow, error) { - rows, err := q.db.Query(ctx, ListMediaItemsByLibrary, libraryID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListMediaItemsByLibraryRow{} - for rows.Next() { - var i ListMediaItemsByLibraryRow - 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 ListMediaItemsFiltered = `-- name: ListMediaItemsFiltered :many -SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.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 mi.library_id = $2 - AND COALESCE(lv.is_visible, true) = true - AND ($3 = '' OR mi.author ILIKE $3) - AND ($4 = '' OR mi.series ILIKE $4) - AND ($5 = '' OR mi.genre = $5) - AND ($6 = '' OR mi.language = $6) - AND ($7 = 0 OR mi.copyright_year >= $7) - AND ($8 = 0 OR mi.copyright_year <= $8) - AND ($9 = false OR mi.cover_image_path IS NOT NULL) -ORDER BY - CASE - WHEN $10 = 'title ASC' THEN mi.title - ELSE '' - END ASC, - CASE - WHEN $10 = 'title DESC' THEN mi.title - ELSE '' - END DESC, - CASE - WHEN $10 = 'author ASC' THEN COALESCE(mi.author, '') - ELSE '' - END ASC, - CASE - WHEN $10 = 'author DESC' THEN COALESCE(mi.author, '') - ELSE '' - END DESC, - CASE - WHEN $10 = 'created_at ASC' THEN mi.created_at - ELSE '1970-01-01'::timestamp - END ASC, - CASE - WHEN $10 = 'created_at DESC' THEN mi.created_at - ELSE '1970-01-01'::timestamp - END DESC, - mi.created_at DESC -LIMIT $12 OFFSET $11 -` - -type ListMediaItemsFilteredParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - AuthorFilter interface{} `db:"author_filter" json:"author_filter"` - SeriesFilter interface{} `db:"series_filter" json:"series_filter"` - GenreFilter interface{} `db:"genre_filter" json:"genre_filter"` - LanguageFilter interface{} `db:"language_filter" json:"language_filter"` - YearMin interface{} `db:"year_min" json:"year_min"` - YearMax interface{} `db:"year_max" json:"year_max"` - HasCover interface{} `db:"has_cover" json:"has_cover"` - Sort interface{} `db:"sort" json:"sort"` - Offset pgtype.Int4 `db:"offset" json:"offset"` - Limit pgtype.Int4 `db:"limit" json:"limit"` -} - -type ListMediaItemsFilteredRow struct { - ID pgtype.UUID `db:"id" json:"id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - Isbn pgtype.Text `db:"isbn" json:"isbn"` - Description pgtype.Text `db:"description" json:"description"` - FilePath string `db:"file_path" json:"file_path"` - FileSize pgtype.Int8 `db:"file_size" json:"file_size"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` - CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"` - Series pgtype.Text `db:"series" json:"series"` - SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"` - Tags []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) ListMediaItemsFiltered(ctx context.Context, arg ListMediaItemsFilteredParams) ([]ListMediaItemsFilteredRow, error) { - rows, err := q.db.Query(ctx, ListMediaItemsFiltered, - arg.UserID, - arg.LibraryID, - arg.AuthorFilter, - arg.SeriesFilter, - arg.GenreFilter, - arg.LanguageFilter, - arg.YearMin, - arg.YearMax, - arg.HasCover, - arg.Sort, - arg.Offset, - arg.Limit, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListMediaItemsFilteredRow{} - for rows.Next() { - var i ListMediaItemsFilteredRow - if err := rows.Scan( - &i.ID, - &i.LibraryID, - &i.Title, - &i.Author, - &i.Isbn, - &i.Description, - &i.FilePath, - &i.FileSize, - &i.MimeType, - &i.CoverImagePath, - &i.Series, - &i.SeriesNumber, - &i.Tags, - &i.Asin, - &i.DatePublished, - &i.Publisher, - &i.Contributors, - &i.Language, - &i.Edition, - &i.PageCount, - &i.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 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.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 -WHERE mi.library_id = $1 -ORDER BY - CASE - WHEN $2 = 'title ASC' THEN mi.title - ELSE '' - END ASC, - CASE - WHEN $2 = 'title DESC' THEN mi.title - ELSE '' - END DESC, - CASE - WHEN $2 = 'author ASC' THEN COALESCE(mi.author, '') - ELSE '' - END ASC, - CASE - WHEN $2 = 'author DESC' THEN COALESCE(mi.author, '') - ELSE '' - END DESC, - CASE - WHEN $2 = 'created_at ASC' THEN mi.created_at - ELSE '1970-01-01'::timestamp - END ASC, - CASE - WHEN $2 = 'created_at DESC' THEN mi.created_at - ELSE '1970-01-01'::timestamp - END DESC, - CASE - WHEN $2 = 'series ASC' THEN COALESCE(mi.series, '') - ELSE '' - END ASC, - CASE - WHEN $2 = 'series DESC' THEN COALESCE(mi.series, '') - ELSE '' - END DESC, - CASE - WHEN $2 = 'date_published ASC' THEN COALESCE(mi.date_published::text, '') - ELSE '' - END ASC, - CASE - WHEN $2 = 'date_published DESC' THEN COALESCE(mi.date_published::text, '') - ELSE '' - END DESC, - CASE - WHEN $2 = 'copyright_year ASC' THEN COALESCE(mi.copyright_year::text, '0') - ELSE '' - END ASC, - CASE - WHEN $2 = 'copyright_year DESC' THEN COALESCE(mi.copyright_year::text, '0') - ELSE '' - END DESC, - CASE - WHEN $2 = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0') - ELSE '' - END ASC, - CASE - WHEN $2 = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0') - ELSE '' - END DESC, - CASE - WHEN $2 = 'genre ASC' THEN COALESCE(mi.genre, '') - ELSE '' - END ASC, - CASE - WHEN $2 = 'genre DESC' THEN COALESCE(mi.genre, '') - ELSE '' - END DESC, - mi.created_at DESC - LIMIT $4 OFFSET $3 -` - -type ListMediaItemsSortedParams struct { - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - Sort interface{} `db:"sort" json:"sort"` - Offset pgtype.Int4 `db:"offset" json:"offset"` - Limit pgtype.Int4 `db:"limit" json:"limit"` -} - -type ListMediaItemsSortedRow struct { - ID pgtype.UUID `db:"id" json:"id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - Isbn pgtype.Text `db:"isbn" json:"isbn"` - Description pgtype.Text `db:"description" json:"description"` - FilePath string `db:"file_path" json:"file_path"` - FileSize pgtype.Int8 `db:"file_size" json:"file_size"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` - CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"` - Series pgtype.Text `db:"series" json:"series"` - SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"` - Tags []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) ListMediaItemsSorted(ctx context.Context, arg ListMediaItemsSortedParams) ([]ListMediaItemsSortedRow, error) { - rows, err := q.db.Query(ctx, ListMediaItemsSorted, - arg.LibraryID, - arg.Sort, - arg.Offset, - arg.Limit, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListMediaItemsSortedRow{} - for rows.Next() { - var i ListMediaItemsSortedRow - if err := rows.Scan( - &i.ID, - &i.LibraryID, - &i.Title, - &i.Author, - &i.Isbn, - &i.Description, - &i.FilePath, - &i.FileSize, - &i.MimeType, - &i.CoverImagePath, - &i.Series, - &i.SeriesNumber, - &i.Tags, - &i.Asin, - &i.DatePublished, - &i.Publisher, - &i.Contributors, - &i.Language, - &i.Edition, - &i.PageCount, - &i.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 ListPendingSyncQueueItems = `-- name: ListPendingSyncQueueItems :many -SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue -WHERE device_id = $1 AND status = 'pending' -ORDER BY priority ASC, created_at ASC -LIMIT $2 -` - -type ListPendingSyncQueueItemsParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - Limit int32 `db:"limit" json:"limit"` -} - -func (q *Queries) ListPendingSyncQueueItems(ctx context.Context, arg ListPendingSyncQueueItemsParams) ([]SyncQueue, error) { - rows, err := q.db.Query(ctx, ListPendingSyncQueueItems, arg.DeviceID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SyncQueue{} - for rows.Next() { - var i SyncQueue - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListSyncConflictsByMediaItem = `-- name: ListSyncConflictsByMediaItem :many -SELECT id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at FROM sync_conflicts -WHERE media_item_id = $1 AND user_id = $2 -ORDER BY created_at DESC -` - -type ListSyncConflictsByMediaItemParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` -} - -func (q *Queries) ListSyncConflictsByMediaItem(ctx context.Context, arg ListSyncConflictsByMediaItemParams) ([]SyncConflicts, error) { - rows, err := q.db.Query(ctx, ListSyncConflictsByMediaItem, arg.MediaItemID, arg.UserID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SyncConflicts{} - for rows.Next() { - var i SyncConflicts - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.ConflictType, - &i.ConflictData, - &i.ResolutionStatus, - &i.ResolutionData, - &i.ResolvedBy, - &i.ResolvedAt, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListSyncConflictsByUser = `-- name: ListSyncConflictsByUser :many -SELECT sc.id, sc.media_item_id, sc.user_id, sc.conflict_type, sc.conflict_data, sc.resolution_status, sc.resolution_data, sc.resolved_by, sc.resolved_at, sc.created_at, mi.title, mi.author -FROM sync_conflicts sc -JOIN media_items mi ON sc.media_item_id = mi.id -WHERE sc.user_id = $1 AND sc.resolution_status = 'unresolved' -ORDER BY sc.created_at DESC -` - -type ListSyncConflictsByUserRow struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - ConflictType string `db:"conflict_type" json:"conflict_type"` - ConflictData []byte `db:"conflict_data" json:"conflict_data"` - ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"` - ResolutionData []byte `db:"resolution_data" json:"resolution_data"` - ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"` - ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` -} - -func (q *Queries) ListSyncConflictsByUser(ctx context.Context, userID pgtype.UUID) ([]ListSyncConflictsByUserRow, error) { - rows, err := q.db.Query(ctx, ListSyncConflictsByUser, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListSyncConflictsByUserRow{} - for rows.Next() { - var i ListSyncConflictsByUserRow - if err := rows.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.ConflictType, - &i.ConflictData, - &i.ResolutionStatus, - &i.ResolutionData, - &i.ResolvedBy, - &i.ResolvedAt, - &i.CreatedAt, - &i.Title, - &i.Author, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListUnresolvedUnlinkedBooks = `-- name: ListUnresolvedUnlinkedBooks :many -SELECT ub.id, ub.device_id, ub.content_id, ub.file_path, ub.title, ub.author, ub.confidence_score, ub.resolved, ub.media_item_id, ub.resolved_at, ub.resolution_method, ub.last_seen_at, ub.created_at, d.device_name, d.device_type -FROM unlinked_books ub -JOIN devices d ON ub.device_id = d.id -WHERE ub.resolved = false -ORDER BY ub.last_seen_at DESC -LIMIT $1 OFFSET $2 -` - -type ListUnresolvedUnlinkedBooksParams struct { - Limit int32 `db:"limit" json:"limit"` - Offset int32 `db:"offset" json:"offset"` -} - -type ListUnresolvedUnlinkedBooksRow struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - ContentID string `db:"content_id" json:"content_id"` - FilePath pgtype.Text `db:"file_path" json:"file_path"` - Title pgtype.Text `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` - Resolved pgtype.Bool `db:"resolved" json:"resolved"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"` - ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"` - LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - DeviceName string `db:"device_name" json:"device_name"` - DeviceType string `db:"device_type" json:"device_type"` -} - -// List unresolved unlinked books with pagination -func (q *Queries) ListUnresolvedUnlinkedBooks(ctx context.Context, arg ListUnresolvedUnlinkedBooksParams) ([]ListUnresolvedUnlinkedBooksRow, error) { - rows, err := q.db.Query(ctx, ListUnresolvedUnlinkedBooks, arg.Limit, arg.Offset) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListUnresolvedUnlinkedBooksRow{} - for rows.Next() { - var i ListUnresolvedUnlinkedBooksRow - if err := rows.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - &i.DeviceName, - &i.DeviceType, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const ListUsers = `-- name: ListUsers :many -SELECT - u.id, - u.email, - u.username, - u.theme, - u.first_name, - u.last_name, - u.role, - u.max_devices, - u.created_at, - u.updated_at, - (SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count -FROM users u -ORDER BY u.created_at DESC -` - -type ListUsersRow 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"` - DeviceCount int64 `db:"device_count" json:"device_count"` -} - -func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) { - rows, err := q.db.Query(ctx, ListUsers) - if err != nil { - return nil, err - } - defer rows.Close() - items := []ListUsersRow{} - for rows.Next() { - var i ListUsersRow - if err := rows.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Theme, - &i.FirstName, - &i.LastName, - &i.Role, - &i.MaxDevices, - &i.CreatedAt, - &i.UpdatedAt, - &i.DeviceCount, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const QueryMediaItemsByIdentifiers = `-- name: QueryMediaItemsByIdentifiers :many -SELECT - mi.id, - mi.file_sha256, - mi.opf_identifier, - mi.opf_uuid, - mi.isbn, - mi.asin, - mi.title, - mi.author, - mi.file_size, - mi.hash_confidence, - CASE - WHEN $1::uuid IS NOT NULL AND mi.id = $1::uuid THEN 1.0 - WHEN mi.opf_uuid IS NOT NULL AND mi.opf_uuid = $2::text THEN 0.95 - WHEN mi.file_sha256 IS NOT NULL AND mi.file_sha256 = $3::text THEN 0.9 - WHEN mi.opf_identifier IS NOT NULL AND mi.opf_identifier = $4::text THEN 0.85 - WHEN mi.isbn IS NOT NULL AND mi.isbn = $5::text THEN 0.8 - WHEN mi.asin IS NOT NULL AND mi.asin = $6::text THEN 0.8 - ELSE 0.5 - END as confidence_score -FROM media_items mi -WHERE - ($1::uuid IS NULL OR mi.id = $1::uuid) - OR ($2::text IS NULL OR mi.opf_uuid = $2::text) - OR ($3::text IS NULL OR mi.file_sha256 = $3::text) - OR ($4::text IS NULL OR mi.opf_identifier = $4::text) - OR ($5::text IS NULL OR mi.isbn = $5::text) - OR ($6::text IS NULL OR mi.asin = $6::text) - OR ($7::text IS NULL OR mi.title ILIKE '%' || $7::text || '%') -ORDER BY confidence_score DESC -` - -type QueryMediaItemsByIdentifiersParams struct { - Column1 pgtype.UUID `db:"column_1" json:"column_1"` - Column2 string `db:"column_2" json:"column_2"` - Column3 string `db:"column_3" json:"column_3"` - Column4 string `db:"column_4" json:"column_4"` - Column5 string `db:"column_5" json:"column_5"` - Column6 string `db:"column_6" json:"column_6"` - Column7 string `db:"column_7" json:"column_7"` -} - -type QueryMediaItemsByIdentifiersRow struct { - ID pgtype.UUID `db:"id" json:"id"` - 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"` - Isbn pgtype.Text `db:"isbn" json:"isbn"` - Asin pgtype.Text `db:"asin" json:"asin"` - Title string `db:"title" json:"title"` - Author pgtype.Text `db:"author" json:"author"` - FileSize pgtype.Int8 `db:"file_size" json:"file_size"` - HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"` - ConfidenceScore float64 `db:"confidence_score" json:"confidence_score"` -} - -// Query media items by multiple identifiers with confidence scoring -func (q *Queries) QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMediaItemsByIdentifiersParams) ([]QueryMediaItemsByIdentifiersRow, error) { - rows, err := q.db.Query(ctx, QueryMediaItemsByIdentifiers, - arg.Column1, - arg.Column2, - arg.Column3, - arg.Column4, - arg.Column5, - arg.Column6, - arg.Column7, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []QueryMediaItemsByIdentifiersRow{} - for rows.Next() { - var i QueryMediaItemsByIdentifiersRow - if err := rows.Scan( - &i.ID, - &i.FileSha256, - &i.OpfIdentifier, - &i.OpfUuid, - &i.Isbn, - &i.Asin, - &i.Title, - &i.Author, - &i.FileSize, - &i.HashConfidence, - &i.ConfidenceScore, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const RemoveBookFromCollection = `-- name: RemoveBookFromCollection :exec -DELETE FROM collection_items WHERE collection_id = $1 AND media_item_id = $2 -` - -type RemoveBookFromCollectionParams struct { - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` -} - -// Remove book from collection -func (q *Queries) RemoveBookFromCollection(ctx context.Context, arg RemoveBookFromCollectionParams) error { - _, err := q.db.Exec(ctx, RemoveBookFromCollection, arg.CollectionID, arg.MediaItemID) - return err -} - -const RemoveBookFromKoboShelf = `-- name: RemoveBookFromKoboShelf :exec -DELETE FROM kobo_shelves WHERE device_id = $1 AND media_item_id = $2 -` - -type RemoveBookFromKoboShelfParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` -} - -func (q *Queries) RemoveBookFromKoboShelf(ctx context.Context, arg RemoveBookFromKoboShelfParams) error { - _, err := q.db.Exec(ctx, RemoveBookFromKoboShelf, arg.DeviceID, arg.MediaItemID) - return err -} - -const ResetSystemCollectionMetadata = `-- name: ResetSystemCollectionMetadata :exec -UPDATE collections -SET description = $3, - icon = $4, - color = $5, - priority = $6 -WHERE user_id = $1 - AND name = $2 - AND is_system_collection = true -` - -type ResetSystemCollectionMetadataParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` - Description pgtype.Text `db:"description" json:"description"` - Icon pgtype.Text `db:"icon" json:"icon"` - Color pgtype.Text `db:"color" json:"color"` - Priority pgtype.Int4 `db:"priority" json:"priority"` -} - -func (q *Queries) ResetSystemCollectionMetadata(ctx context.Context, arg ResetSystemCollectionMetadataParams) error { - _, err := q.db.Exec(ctx, ResetSystemCollectionMetadata, - arg.UserID, - arg.Name, - arg.Description, - arg.Icon, - arg.Color, - arg.Priority, - ) - return err -} - -const ResolveSyncConflict = `-- name: ResolveSyncConflict :one -UPDATE sync_conflicts -SET - resolution_status = $2, - resolution_data = $3, - resolved_by = $4, - resolved_at = NOW() -WHERE id = $1 -RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at -` - -type ResolveSyncConflictParams struct { - ID pgtype.UUID `db:"id" json:"id"` - ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"` - ResolutionData []byte `db:"resolution_data" json:"resolution_data"` - ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"` -} - -func (q *Queries) ResolveSyncConflict(ctx context.Context, arg ResolveSyncConflictParams) (SyncConflicts, error) { - row := q.db.QueryRow(ctx, ResolveSyncConflict, - arg.ID, - arg.ResolutionStatus, - arg.ResolutionData, - arg.ResolvedBy, - ) - var i SyncConflicts - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.ConflictType, - &i.ConflictData, - &i.ResolutionStatus, - &i.ResolutionData, - &i.ResolvedBy, - &i.ResolvedAt, - &i.CreatedAt, - ) - return i, err -} - -const ResolveUnlinkedBook = `-- name: ResolveUnlinkedBook :one -UPDATE unlinked_books -SET - resolved = true, - media_item_id = $2, - resolved_at = NOW(), - resolution_method = $3 -WHERE id = $1 -RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at -` - -type ResolveUnlinkedBookParams struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"` -} - -// Resolve unlinked book -func (q *Queries) ResolveUnlinkedBook(ctx context.Context, arg ResolveUnlinkedBookParams) (UnlinkedBooks, error) { - row := q.db.QueryRow(ctx, ResolveUnlinkedBook, arg.ID, arg.MediaItemID, arg.ResolutionMethod) - var i UnlinkedBooks - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.ContentID, - &i.FilePath, - &i.Title, - &i.Author, - &i.ConfidenceScore, - &i.Resolved, - &i.MediaItemID, - &i.ResolvedAt, - &i.ResolutionMethod, - &i.LastSeenAt, - &i.CreatedAt, - ) - return i, err -} - -const RevokeAllUserRefreshTokens = `-- name: RevokeAllUserRefreshTokens :exec -UPDATE refresh_tokens SET revoked_at = NOW() WHERE user_id = $1 AND revoked_at IS NULL -` - -func (q *Queries) RevokeAllUserRefreshTokens(ctx context.Context, userID pgtype.UUID) error { - _, err := q.db.Exec(ctx, RevokeAllUserRefreshTokens, userID) - return err -} - -const RevokeDevice = `-- name: RevokeDevice :exec -UPDATE devices -SET - auth_token = NULL, - sync_enabled = false, - updated_at = NOW() -WHERE id = $1 -` - -func (q *Queries) RevokeDevice(ctx context.Context, id pgtype.UUID) error { - _, err := q.db.Exec(ctx, RevokeDevice, id) - return err -} - -const RevokeOpdsToken = `-- name: RevokeOpdsToken :exec -DELETE FROM opds_tokens WHERE token = $1 -` - -// Revoke OPDS token -func (q *Queries) RevokeOpdsToken(ctx context.Context, token string) error { - _, err := q.db.Exec(ctx, RevokeOpdsToken, token) - return err -} - -const RevokeRefreshToken = `-- name: RevokeRefreshToken :exec -UPDATE refresh_tokens SET revoked_at = NOW() WHERE token = $1 -` - -func (q *Queries) RevokeRefreshToken(ctx context.Context, token pgtype.UUID) error { - _, err := q.db.Exec(ctx, RevokeRefreshToken, token) - return err -} - -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.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 ( - mi.title ILIKE $3 OR - mi.author ILIKE $3 OR - mi.series ILIKE $3 OR - $3 = ANY(mi.tags_search) OR - $3 = ANY(mi.contributors_search) - ) - ORDER BY - CASE - WHEN mi.title ILIKE $3 THEN 1 - WHEN mi.author ILIKE $3 THEN 2 - WHEN mi.series ILIKE $3 THEN 3 - WHEN $3 = ANY(mi.tags_search) THEN 4 - ELSE 5 - END, - mi.title ASC -LIMIT $5 OFFSET $4 -` - -type SearchMediaItemsParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID interface{} `db:"library_id" json:"library_id"` - SearchPattern pgtype.Text `db:"search_pattern" json:"search_pattern"` - Offset pgtype.Int4 `db:"offset" json:"offset"` - Limit pgtype.Int4 `db:"limit" json:"limit"` -} - -type SearchMediaItemsRow 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"` -} - -// Search Media Items queries -func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsParams) ([]SearchMediaItemsRow, error) { - rows, err := q.db.Query(ctx, SearchMediaItems, - arg.UserID, - arg.LibraryID, - arg.SearchPattern, - arg.Offset, - arg.Limit, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SearchMediaItemsRow{} - for rows.Next() { - var i SearchMediaItemsRow - 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 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 SetLibraryVisibility = `-- name: SetLibraryVisibility :one -INSERT INTO library_visibility (user_id, library_id, is_visible) -VALUES ($1, $2, $3) -ON CONFLICT (user_id, library_id) -DO UPDATE SET - is_visible = EXCLUDED.is_visible, - updated_at = NOW() -RETURNING id, user_id, library_id, is_visible, created_at, updated_at -` - -type SetLibraryVisibilityParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - IsVisible bool `db:"is_visible" json:"is_visible"` -} - -// Library Visibility queries -func (q *Queries) SetLibraryVisibility(ctx context.Context, arg SetLibraryVisibilityParams) (LibraryVisibility, error) { - row := q.db.QueryRow(ctx, SetLibraryVisibility, arg.UserID, arg.LibraryID, arg.IsVisible) - var i LibraryVisibility - err := row.Scan( - &i.ID, - &i.UserID, - &i.LibraryID, - &i.IsVisible, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const SetSystemConfig = `-- name: SetSystemConfig :one -INSERT INTO system_config (key, value, updated_by) -VALUES ($1, $2, $3) -ON CONFLICT (key) -DO UPDATE SET - value = EXCLUDED.value, - updated_by = EXCLUDED.updated_by, - updated_at = NOW() -RETURNING key, value, updated_at, updated_by -` - -type SetSystemConfigParams struct { - Key string `db:"key" json:"key"` - Value string `db:"value" json:"value"` - UpdatedBy pgtype.UUID `db:"updated_by" json:"updated_by"` -} - -// Set system config -func (q *Queries) SetSystemConfig(ctx context.Context, arg SetSystemConfigParams) (SystemConfig, error) { - row := q.db.QueryRow(ctx, SetSystemConfig, arg.Key, arg.Value, arg.UpdatedBy) - var i SystemConfig - err := row.Scan( - &i.Key, - &i.Value, - &i.UpdatedAt, - &i.UpdatedBy, - ) - return i, err -} - -const UpdateCollection = `-- name: UpdateCollection :one -UPDATE collections -SET - name = $2, - description = $3, - color = $4, - icon = $5, - auto_assign_rules = $6, - view_settings = $7 -WHERE id = $1 -RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at -` - -type UpdateCollectionParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Name string `db:"name" json:"name"` - Description pgtype.Text `db:"description" json:"description"` - Color pgtype.Text `db:"color" json:"color"` - Icon pgtype.Text `db:"icon" json:"icon"` - AutoAssignRules []byte `db:"auto_assign_rules" json:"auto_assign_rules"` - ViewSettings []byte `db:"view_settings" json:"view_settings"` -} - -// Update collection -func (q *Queries) UpdateCollection(ctx context.Context, arg UpdateCollectionParams) (Collections, error) { - row := q.db.QueryRow(ctx, UpdateCollection, - arg.ID, - arg.Name, - arg.Description, - arg.Color, - arg.Icon, - arg.AutoAssignRules, - arg.ViewSettings, - ) - var i Collections - err := row.Scan( - &i.ID, - &i.UserID, - &i.Name, - &i.Description, - &i.Color, - &i.Icon, - &i.AutoAssignRules, - &i.ViewSettings, - &i.ShowOnDashboard, - &i.QueryType, - &i.Priority, - &i.IsSystemCollection, - &i.CreatedAt, - ) - return i, err -} - -const UpdateDashboardPreferences = `-- name: UpdateDashboardPreferences :one -UPDATE user_dashboard_preferences -SET hidden_collections = $2, - collection_order = $3, - items_per_section = $4, - updated_at = NOW() -WHERE user_id = $1 AND library_id = $5 -RETURNING id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at -` - -type UpdateDashboardPreferencesParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - HiddenCollections []string `db:"hidden_collections" json:"hidden_collections"` - CollectionOrder []string `db:"collection_order" json:"collection_order"` - ItemsPerSection pgtype.Int4 `db:"items_per_section" json:"items_per_section"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` -} - -func (q *Queries) UpdateDashboardPreferences(ctx context.Context, arg UpdateDashboardPreferencesParams) (UserDashboardPreferences, error) { - row := q.db.QueryRow(ctx, UpdateDashboardPreferences, - arg.UserID, - arg.HiddenCollections, - arg.CollectionOrder, - arg.ItemsPerSection, - arg.LibraryID, - ) - var i UserDashboardPreferences - err := row.Scan( - &i.ID, - &i.UserID, - &i.LibraryID, - &i.HiddenCollections, - &i.CollectionOrder, - &i.ItemsPerSection, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateDevice = `-- name: UpdateDevice :one -UPDATE devices -SET - device_name = $2, - sync_enabled = $3, - auto_sync = $4, - sync_frequency_minutes = $5, - device_metadata = $6, - updated_at = NOW() -WHERE id = $1 -RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at -` - -type UpdateDeviceParams struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceName string `db:"device_name" json:"device_name"` - SyncEnabled pgtype.Bool `db:"sync_enabled" json:"sync_enabled"` - AutoSync pgtype.Bool `db:"auto_sync" json:"auto_sync"` - SyncFrequencyMinutes pgtype.Int4 `db:"sync_frequency_minutes" json:"sync_frequency_minutes"` - DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"` -} - -func (q *Queries) UpdateDevice(ctx context.Context, arg UpdateDeviceParams) (Devices, error) { - row := q.db.QueryRow(ctx, UpdateDevice, - arg.ID, - arg.DeviceName, - arg.SyncEnabled, - arg.AutoSync, - arg.SyncFrequencyMinutes, - arg.DeviceMetadata, - ) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateDeviceAuthToken = `-- name: UpdateDeviceAuthToken :one -UPDATE devices -SET - auth_token = $2, - updated_at = NOW() -WHERE id = $1 -RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at -` - -type UpdateDeviceAuthTokenParams struct { - ID pgtype.UUID `db:"id" json:"id"` - AuthToken string `db:"auth_token" json:"auth_token"` -} - -func (q *Queries) UpdateDeviceAuthToken(ctx context.Context, arg UpdateDeviceAuthTokenParams) (Devices, error) { - row := q.db.QueryRow(ctx, UpdateDeviceAuthToken, arg.ID, arg.AuthToken) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateDeviceCatalogAvailability = `-- name: UpdateDeviceCatalogAvailability :exec -UPDATE device_catalogs -SET available = $2 -WHERE id = $1 -` - -type UpdateDeviceCatalogAvailabilityParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Available pgtype.Bool `db:"available" json:"available"` -} - -// Update device catalog availability -func (q *Queries) UpdateDeviceCatalogAvailability(ctx context.Context, arg UpdateDeviceCatalogAvailabilityParams) error { - _, err := q.db.Exec(ctx, UpdateDeviceCatalogAvailability, arg.ID, arg.Available) - return err -} - -const UpdateDeviceFileAlias = `-- name: UpdateDeviceFileAlias :one -UPDATE device_file_aliases -SET - media_item_id = $2, - file_sha256 = $3, - confidence_score = $4, - last_seen_at = NOW() -WHERE id = $1 -RETURNING id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at -` - -type UpdateDeviceFileAliasParams struct { - ID pgtype.UUID `db:"id" json:"id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"` -} - -// Update device file alias -func (q *Queries) UpdateDeviceFileAlias(ctx context.Context, arg UpdateDeviceFileAliasParams) (DeviceFileAliases, error) { - row := q.db.QueryRow(ctx, UpdateDeviceFileAlias, - arg.ID, - arg.MediaItemID, - arg.FileSha256, - arg.ConfidenceScore, - ) - var i DeviceFileAliases - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.DeviceID, - &i.FilePath, - &i.FileSha256, - &i.ConfidenceScore, - &i.LastSeenAt, - ) - return i, err -} - -const UpdateDeviceLastSeen = `-- name: UpdateDeviceLastSeen :one -UPDATE devices -SET - last_seen = NOW(), - updated_at = NOW() -WHERE id = $1 -RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at -` - -func (q *Queries) UpdateDeviceLastSeen(ctx context.Context, id pgtype.UUID) (Devices, error) { - row := q.db.QueryRow(ctx, UpdateDeviceLastSeen, id) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateDeviceLastSync = `-- name: UpdateDeviceLastSync :one -UPDATE devices -SET - last_sync = NOW(), - last_seen = NOW(), - updated_at = NOW() -WHERE id = $1 -RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at -` - -func (q *Queries) UpdateDeviceLastSync(ctx context.Context, id pgtype.UUID) (Devices, error) { - row := q.db.QueryRow(ctx, UpdateDeviceLastSync, id) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateDeviceShelfMapping = `-- name: UpdateDeviceShelfMapping :one -UPDATE device_shelf_mappings -SET - device_shelf_name = $2, - sync_direction = $3 -WHERE id = $1 -RETURNING id, collection_id, device_id, device_shelf_name, sync_direction, created_at -` - -type UpdateDeviceShelfMappingParams struct { - ID pgtype.UUID `db:"id" json:"id"` - DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"` - SyncDirection pgtype.Text `db:"sync_direction" json:"sync_direction"` -} - -// Update device shelf mapping -func (q *Queries) UpdateDeviceShelfMapping(ctx context.Context, arg UpdateDeviceShelfMappingParams) (DeviceShelfMappings, error) { - row := q.db.QueryRow(ctx, UpdateDeviceShelfMapping, arg.ID, arg.DeviceShelfName, arg.SyncDirection) - var i DeviceShelfMappings - err := row.Scan( - &i.ID, - &i.CollectionID, - &i.DeviceID, - &i.DeviceShelfName, - &i.SyncDirection, - &i.CreatedAt, - ) - return i, err -} - -const UpdateDeviceSyncTimestamp = `-- name: UpdateDeviceSyncTimestamp :one -UPDATE devices -SET - last_sync = NOW(), - last_seen = NOW(), - updated_at = NOW() -WHERE id = $1 -RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at -` - -func (q *Queries) UpdateDeviceSyncTimestamp(ctx context.Context, id pgtype.UUID) (Devices, error) { - row := q.db.QueryRow(ctx, UpdateDeviceSyncTimestamp, id) - var i Devices - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceName, - &i.DeviceType, - &i.DeviceIdentifier, - &i.AuthToken, - &i.LastSync, - &i.LastSeen, - &i.SyncEnabled, - &i.AutoSync, - &i.SyncFrequencyMinutes, - &i.DeviceMetadata, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateEmail = `-- name: UpdateEmail :exec -UPDATE users SET email = $2, updated_at = NOW() WHERE id = $1 -` - -type UpdateEmailParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Email string `db:"email" json:"email"` -} - -func (q *Queries) UpdateEmail(ctx context.Context, arg UpdateEmailParams) error { - _, err := q.db.Exec(ctx, UpdateEmail, arg.ID, arg.Email) - return err -} - -const UpdateKoboEntitlementRevision = `-- name: UpdateKoboEntitlementRevision :exec -UPDATE kobo_entitlements -SET revision_number = $3, updated_at = NOW() -WHERE device_id = $1 AND entitlement_id = $2 -` - -type UpdateKoboEntitlementRevisionParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` -} - -func (q *Queries) UpdateKoboEntitlementRevision(ctx context.Context, arg UpdateKoboEntitlementRevisionParams) error { - _, err := q.db.Exec(ctx, UpdateKoboEntitlementRevision, arg.DeviceID, arg.EntitlementID, arg.RevisionNumber) - return err -} - -const UpdateKoboEntitlementStatus = `-- name: UpdateKoboEntitlementStatus :exec -UPDATE kobo_entitlements -SET book_status = $3, sync_status = 'synced', updated_at = NOW() -WHERE device_id = $1 AND entitlement_id = $2 -` - -type UpdateKoboEntitlementStatusParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - EntitlementID string `db:"entitlement_id" json:"entitlement_id"` - BookStatus pgtype.Text `db:"book_status" json:"book_status"` -} - -func (q *Queries) UpdateKoboEntitlementStatus(ctx context.Context, arg UpdateKoboEntitlementStatusParams) error { - _, err := q.db.Exec(ctx, UpdateKoboEntitlementStatus, arg.DeviceID, arg.EntitlementID, arg.BookStatus) - return err -} - -const UpdateKoboShelfBookPosition = `-- name: UpdateKoboShelfBookPosition :exec -UPDATE kobo_shelves -SET shelf_position = $3, last_synced_at = NOW() -WHERE device_id = $1 AND media_item_id = $2 -` - -type UpdateKoboShelfBookPositionParams struct { - DeviceID pgtype.UUID `db:"device_id" json:"device_id"` - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"` -} - -func (q *Queries) UpdateKoboShelfBookPosition(ctx context.Context, arg UpdateKoboShelfBookPositionParams) error { - _, err := q.db.Exec(ctx, UpdateKoboShelfBookPosition, arg.DeviceID, arg.MediaItemID, arg.ShelfPosition) - return err -} - -const UpdateKoboShelfCollection = `-- name: UpdateKoboShelfCollection :one -UPDATE kobo_shelves -SET - collection_id = $2, - position_in_collection = $3, - last_synced_at = NOW() -WHERE id = $1 -RETURNING id, device_id, media_item_id, shelf_name, shelf_position, added_at, last_synced_at, collection_id, position_in_collection -` - -type UpdateKoboShelfCollectionParams struct { - ID pgtype.UUID `db:"id" json:"id"` - CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"` - PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"` -} - -// Update Kobo shelves to support collections -func (q *Queries) UpdateKoboShelfCollection(ctx context.Context, arg UpdateKoboShelfCollectionParams) (KoboShelves, error) { - row := q.db.QueryRow(ctx, UpdateKoboShelfCollection, arg.ID, arg.CollectionID, arg.PositionInCollection) - var i KoboShelves - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.ShelfName, - &i.ShelfPosition, - &i.AddedAt, - &i.LastSyncedAt, - &i.CollectionID, - &i.PositionInCollection, - ) - return i, err -} - -const UpdateLibrary = `-- name: UpdateLibrary :one -UPDATE libraries SET - name = $2, - description = $3, - updated_at = NOW() -WHERE id = $1 -RETURNING id, name, description, library_type_id, created_by_admin_id, created_at, updated_at -` - -type UpdateLibraryParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Name string `db:"name" json:"name"` - Description pgtype.Text `db:"description" json:"description"` -} - -func (q *Queries) UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (Libraries, error) { - row := q.db.QueryRow(ctx, UpdateLibrary, arg.ID, arg.Name, arg.Description) - var i Libraries - err := row.Scan( - &i.ID, - &i.Name, - &i.Description, - &i.LibraryTypeID, - &i.CreatedByAdminID, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateMediaHighlight = `-- name: UpdateMediaHighlight :one -UPDATE media_highlights SET - selection_text = $2, - start_position = $3, - end_position = $4, - color = $5, - note_id = $6, - updated_at = NOW() -WHERE id = $1 -RETURNING id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data -` - -type UpdateMediaHighlightParams struct { - ID pgtype.UUID `db:"id" json:"id"` - SelectionText string `db:"selection_text" json:"selection_text"` - StartPosition pgtype.Text `db:"start_position" json:"start_position"` - EndPosition pgtype.Text `db:"end_position" json:"end_position"` - Color pgtype.Text `db:"color" json:"color"` - NoteID pgtype.UUID `db:"note_id" json:"note_id"` -} - -func (q *Queries) UpdateMediaHighlight(ctx context.Context, arg UpdateMediaHighlightParams) (MediaHighlights, error) { - row := q.db.QueryRow(ctx, UpdateMediaHighlight, - arg.ID, - arg.SelectionText, - arg.StartPosition, - arg.EndPosition, - arg.Color, - arg.NoteID, - ) - var i MediaHighlights - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.SelectionText, - &i.StartPosition, - &i.EndPosition, - &i.Color, - &i.NoteID, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageStart, - &i.PercentageEnd, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiStart, - &i.EpubcfiEnd, - &i.ChapterReference, - &i.ParagraphStart, - &i.ParagraphEnd, - &i.PanelNumber, - &i.DeviceSyncData, - ) - return i, err -} - -const UpdateMediaItem = `-- name: UpdateMediaItem :one -UPDATE media_items SET - title = $2, - author = $3, - isbn = $4, - description = $5, - cover_image_path = $6, - series = $7, - series_number = $8, - tags = $9, - tags_search = $10, - asin = $11, - date_published = $12, - publisher = $13, - contributors = $14, - contributors_search = $15, - language = $16, - edition = $17, - page_count = $18, - genre = $19, - copyright_year = $20, - goodreads_id = $21, - openlibrary_id = $22, - google_books_id = $23, - 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, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence -` - -type UpdateMediaItemParams struct { - ID pgtype.UUID `db:"id" json:"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"` - 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"` - TagsSearch []string `db:"tags_search" json:"tags_search"` - 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"` - ContributorsSearch []string `db:"contributors_search" json:"contributors_search"` - 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"` -} - -func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams) (MediaItems, error) { - row := q.db.QueryRow(ctx, UpdateMediaItem, - arg.ID, - arg.Title, - arg.Author, - arg.Isbn, - arg.Description, - arg.CoverImagePath, - arg.Series, - arg.SeriesNumber, - arg.Tags, - arg.TagsSearch, - arg.Asin, - arg.DatePublished, - arg.Publisher, - arg.Contributors, - arg.ContributorsSearch, - arg.Language, - arg.Edition, - arg.PageCount, - arg.Genre, - arg.CopyrightYear, - arg.GoodreadsID, - arg.OpenlibraryID, - arg.GoogleBooksID, - ) - var i MediaItems - err := row.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, - ) - return i, err -} - -const UpdateMediaItemFormat = `-- name: UpdateMediaItemFormat :one -UPDATE media_item_formats -SET - file_path = $2, - file_sha256 = $3, - file_size_bytes = $4, - mime_type = $5 -WHERE id = $1 -RETURNING id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id -` - -type UpdateMediaItemFormatParams struct { - ID pgtype.UUID `db:"id" json:"id"` - FilePath pgtype.Text `db:"file_path" json:"file_path"` - FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"` - FileSizeBytes pgtype.Int8 `db:"file_size_bytes" json:"file_size_bytes"` - MimeType pgtype.Text `db:"mime_type" json:"mime_type"` -} - -// Update media item format -func (q *Queries) UpdateMediaItemFormat(ctx context.Context, arg UpdateMediaItemFormatParams) (MediaItemFormats, error) { - row := q.db.QueryRow(ctx, UpdateMediaItemFormat, - arg.ID, - arg.FilePath, - arg.FileSha256, - arg.FileSizeBytes, - arg.MimeType, - ) - var i MediaItemFormats - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.FormatType, - &i.FilePath, - &i.FileSha256, - &i.FileSizeBytes, - &i.MimeType, - &i.CreatedAt, - &i.ConvertedFromFormatID, - ) - return i, err -} - -const UpdateMediaItemFormatGroup = `-- name: UpdateMediaItemFormatGroup :exec - -UPDATE media_items -SET - format_group = $2, - format_mimetype = $3, - is_reflowable = $4, - has_fixed_layout = $5, - total_characters = $6, - chapter_count = $7, - updated_at = NOW() -WHERE id = $1 -` - -type UpdateMediaItemFormatGroupParams struct { - ID pgtype.UUID `db:"id" json:"id"` - 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"` -} - -// ============================================ -// FORMAT DETECTION & PROGRESS -// ============================================ -// Update media item format group information -func (q *Queries) UpdateMediaItemFormatGroup(ctx context.Context, arg UpdateMediaItemFormatGroupParams) error { - _, err := q.db.Exec(ctx, UpdateMediaItemFormatGroup, - arg.ID, - arg.FormatGroup, - arg.FormatMimetype, - arg.IsReflowable, - arg.HasFixedLayout, - arg.TotalCharacters, - arg.ChapterCount, - ) - return err -} - -const UpdateMediaItemIdentifiers = `-- name: UpdateMediaItemIdentifiers :one - - -UPDATE media_items -SET - file_sha256 = $2, - opf_identifier = $3, - opf_uuid = $4, - 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, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence -` - -type UpdateMediaItemIdentifiersParams struct { - ID pgtype.UUID `db:"id" json:"id"` - 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"` -} - -// Media Items Admin Operations -// ============================================ -// UNIVERSAL BOOK IDENTIFIERS -// ============================================ -// Update media item with universal identifiers -func (q *Queries) UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMediaItemIdentifiersParams) (MediaItems, error) { - row := q.db.QueryRow(ctx, UpdateMediaItemIdentifiers, - arg.ID, - arg.FileSha256, - arg.OpfIdentifier, - arg.OpfUuid, - arg.HashConfidence, - ) - var i MediaItems - err := row.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, - ) - return i, err -} - -const UpdateMediaItemKoboMetadata = `-- name: UpdateMediaItemKoboMetadata :one -UPDATE media_items -SET entitlement_id = $2, - kobo_content_id = $3, - revision_number = COALESCE($4, revision_number) + 1, - 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, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence -` - -type UpdateMediaItemKoboMetadataParams struct { - ID pgtype.UUID `db:"id" json:"id"` - EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"` - KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"` - RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"` - KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"` -} - -func (q *Queries) UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMediaItemKoboMetadataParams) (MediaItems, error) { - row := q.db.QueryRow(ctx, UpdateMediaItemKoboMetadata, - arg.ID, - arg.EntitlementID, - arg.KoboContentID, - arg.RevisionNumber, - arg.KoboMetadata, - ) - var i MediaItems - err := row.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, - ) - return i, err -} - -const UpdateMediaNote = `-- name: UpdateMediaNote :one -UPDATE media_notes SET - content = $2, - position = $3, - updated_at = NOW() -WHERE id = $1 -RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data -` - -type UpdateMediaNoteParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Content string `db:"content" json:"content"` - Position pgtype.Text `db:"position" json:"position"` -} - -func (q *Queries) UpdateMediaNote(ctx context.Context, arg UpdateMediaNoteParams) (MediaNotes, error) { - row := q.db.QueryRow(ctx, UpdateMediaNote, arg.ID, arg.Content, arg.Position) - var i MediaNotes - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Content, - &i.Position, - &i.CreatedAt, - &i.UpdatedAt, - &i.PercentageLocation, - &i.CharacterStart, - &i.CharacterEnd, - &i.EpubcfiLocation, - &i.ChapterReference, - &i.ParagraphReference, - &i.DeviceSyncData, - ) - return i, err -} - -const UpdateMediaRating = `-- name: UpdateMediaRating :one -UPDATE media_ratings SET - rating = $3, - updated_at = NOW() -WHERE media_item_id = $1 AND user_id = $2 -RETURNING id, media_item_id, user_id, rating, created_at, updated_at -` - -type UpdateMediaRatingParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Rating int32 `db:"rating" json:"rating"` -} - -func (q *Queries) UpdateMediaRating(ctx context.Context, arg UpdateMediaRatingParams) (MediaRatings, error) { - row := q.db.QueryRow(ctx, UpdateMediaRating, arg.MediaItemID, arg.UserID, arg.Rating) - var i MediaRatings - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.Rating, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdatePassword = `-- name: UpdatePassword :exec -UPDATE users SET password_hash = $2, updated_at = NOW() WHERE id = $1 -` - -type UpdatePasswordParams struct { - ID pgtype.UUID `db:"id" json:"id"` - PasswordHash string `db:"password_hash" json:"password_hash"` -} - -func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error { - _, err := q.db.Exec(ctx, UpdatePassword, arg.ID, arg.PasswordHash) - return err -} - -const UpdateReadingProgress = `-- name: UpdateReadingProgress :one -INSERT INTO reading_progress (media_item_id, user_id, current_page, total_pages, last_read_at) -VALUES ($1, $2, $3, $4, NOW()) -ON CONFLICT (media_item_id, user_id) -DO UPDATE SET - current_page = EXCLUDED.current_page, - total_pages = EXCLUDED.total_pages, - last_read_at = NOW() -RETURNING id, media_item_id, user_id, current_page, total_pages, last_read_at, percentage, character_offset, epubcfi, chapter, chapter_progress, viewport_x, viewport_y, zoom_level, scroll_position_x, scroll_position_y, panel_number, reading_mode, last_sync_device, last_sync_source, last_sync_timestamp, conflict_detected, conflict_resolved -` - -type UpdateReadingProgressParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"` - TotalPages pgtype.Int4 `db:"total_pages" json:"total_pages"` -} - -func (q *Queries) UpdateReadingProgress(ctx context.Context, arg UpdateReadingProgressParams) (ReadingProgress, error) { - row := q.db.QueryRow(ctx, UpdateReadingProgress, - arg.MediaItemID, - arg.UserID, - arg.CurrentPage, - arg.TotalPages, - ) - var i ReadingProgress - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.CurrentPage, - &i.TotalPages, - &i.LastReadAt, - &i.Percentage, - &i.CharacterOffset, - &i.Epubcfi, - &i.Chapter, - &i.ChapterProgress, - &i.ViewportX, - &i.ViewportY, - &i.ZoomLevel, - &i.ScrollPositionX, - &i.ScrollPositionY, - &i.PanelNumber, - &i.ReadingMode, - &i.LastSyncDevice, - &i.LastSyncSource, - &i.LastSyncTimestamp, - &i.ConflictDetected, - &i.ConflictResolved, - ) - return i, err -} - -const UpdateSyncQueueItemStatus = `-- name: UpdateSyncQueueItemStatus :one -UPDATE sync_queue -SET - status = $2, - attempts = attempts + 1, - error_message = $3, - processed_at = CASE WHEN $2::varchar = 'completed' THEN NOW() ELSE NULL END -WHERE id = $1 -RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at -` - -type UpdateSyncQueueItemStatusParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Status pgtype.Text `db:"status" json:"status"` - ErrorMessage pgtype.Text `db:"error_message" json:"error_message"` -} - -func (q *Queries) UpdateSyncQueueItemStatus(ctx context.Context, arg UpdateSyncQueueItemStatusParams) (SyncQueue, error) { - row := q.db.QueryRow(ctx, UpdateSyncQueueItemStatus, arg.ID, arg.Status, arg.ErrorMessage) - var i SyncQueue - err := row.Scan( - &i.ID, - &i.DeviceID, - &i.MediaItemID, - &i.SyncType, - &i.SyncData, - &i.Priority, - &i.Attempts, - &i.MaxAttempts, - &i.Status, - &i.ErrorMessage, - &i.CreatedAt, - &i.ProcessedAt, - ) - return i, err -} - -const UpdateSystemSetting = `-- name: UpdateSystemSetting :exec -UPDATE system_settings SET setting_value = $2, updated_at = NOW() WHERE setting_key = $1 -` - -type UpdateSystemSettingParams struct { - SettingKey string `db:"setting_key" json:"setting_key"` - SettingValue string `db:"setting_value" json:"setting_value"` -} - -func (q *Queries) UpdateSystemSetting(ctx context.Context, arg UpdateSystemSettingParams) error { - _, err := q.db.Exec(ctx, UpdateSystemSetting, arg.SettingKey, arg.SettingValue) - return err -} - -const UpdateUniversalProgress = `-- name: UpdateUniversalProgress :one -INSERT INTO reading_progress ( - media_item_id, - user_id, - percentage, - character_offset, - epubcfi, - chapter, - chapter_progress, - viewport_x, - viewport_y, - zoom_level, - scroll_position_x, - scroll_position_y, - panel_number, - reading_mode, - last_sync_device, - last_sync_source, - last_sync_timestamp, - current_page, - total_pages, - last_read_at -) -VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, NOW(), $17, $18, NOW() -) -ON CONFLICT (media_item_id, user_id) -DO UPDATE SET - percentage = EXCLUDED.percentage, - character_offset = EXCLUDED.character_offset, - epubcfi = EXCLUDED.epubcfi, - chapter = EXCLUDED.chapter, - chapter_progress = EXCLUDED.chapter_progress, - viewport_x = EXCLUDED.viewport_x, - viewport_y = EXCLUDED.viewport_y, - zoom_level = EXCLUDED.zoom_level, - scroll_position_x = EXCLUDED.scroll_position_x, - scroll_position_y = EXCLUDED.scroll_position_y, - panel_number = EXCLUDED.panel_number, - reading_mode = EXCLUDED.reading_mode, - last_sync_device = EXCLUDED.last_sync_device, - last_sync_source = EXCLUDED.last_sync_source, - last_sync_timestamp = EXCLUDED.last_sync_timestamp, - current_page = EXCLUDED.current_page, - total_pages = EXCLUDED.total_pages, - last_read_at = NOW() -RETURNING id, media_item_id, user_id, current_page, total_pages, last_read_at, percentage, character_offset, epubcfi, chapter, chapter_progress, viewport_x, viewport_y, zoom_level, scroll_position_x, scroll_position_y, panel_number, reading_mode, last_sync_device, last_sync_source, last_sync_timestamp, conflict_detected, conflict_resolved -` - -type UpdateUniversalProgressParams struct { - MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` - UserID pgtype.UUID `db:"user_id" json:"user_id"` - Percentage pgtype.Float8 `db:"percentage" json:"percentage"` - CharacterOffset pgtype.Int8 `db:"character_offset" json:"character_offset"` - Epubcfi pgtype.Text `db:"epubcfi" json:"epubcfi"` - Chapter pgtype.Int4 `db:"chapter" json:"chapter"` - ChapterProgress pgtype.Float8 `db:"chapter_progress" json:"chapter_progress"` - ViewportX pgtype.Float8 `db:"viewport_x" json:"viewport_x"` - ViewportY pgtype.Float8 `db:"viewport_y" json:"viewport_y"` - ZoomLevel pgtype.Float8 `db:"zoom_level" json:"zoom_level"` - ScrollPositionX pgtype.Float8 `db:"scroll_position_x" json:"scroll_position_x"` - ScrollPositionY pgtype.Float8 `db:"scroll_position_y" json:"scroll_position_y"` - PanelNumber pgtype.Int4 `db:"panel_number" json:"panel_number"` - ReadingMode pgtype.Text `db:"reading_mode" json:"reading_mode"` - LastSyncDevice pgtype.Text `db:"last_sync_device" json:"last_sync_device"` - LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"` - CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"` - TotalPages pgtype.Int4 `db:"total_pages" json:"total_pages"` -} - -// Update universal progress -func (q *Queries) UpdateUniversalProgress(ctx context.Context, arg UpdateUniversalProgressParams) (ReadingProgress, error) { - row := q.db.QueryRow(ctx, UpdateUniversalProgress, - arg.MediaItemID, - arg.UserID, - arg.Percentage, - arg.CharacterOffset, - arg.Epubcfi, - arg.Chapter, - arg.ChapterProgress, - arg.ViewportX, - arg.ViewportY, - arg.ZoomLevel, - arg.ScrollPositionX, - arg.ScrollPositionY, - arg.PanelNumber, - arg.ReadingMode, - arg.LastSyncDevice, - arg.LastSyncSource, - arg.CurrentPage, - arg.TotalPages, - ) - var i ReadingProgress - err := row.Scan( - &i.ID, - &i.MediaItemID, - &i.UserID, - &i.CurrentPage, - &i.TotalPages, - &i.LastReadAt, - &i.Percentage, - &i.CharacterOffset, - &i.Epubcfi, - &i.Chapter, - &i.ChapterProgress, - &i.ViewportX, - &i.ViewportY, - &i.ZoomLevel, - &i.ScrollPositionX, - &i.ScrollPositionY, - &i.PanelNumber, - &i.ReadingMode, - &i.LastSyncDevice, - &i.LastSyncSource, - &i.LastSyncTimestamp, - &i.ConflictDetected, - &i.ConflictResolved, - ) - return i, err -} - -const UpdateUserMaxDevices = `-- name: UpdateUserMaxDevices :one -UPDATE users SET max_devices = $2, updated_at = NOW() WHERE id = $1 -RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, updated_at -` - -type UpdateUserMaxDevicesParams struct { - ID pgtype.UUID `db:"id" json:"id"` - MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"` -} - -func (q *Queries) UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDevicesParams) (Users, error) { - row := q.db.QueryRow(ctx, UpdateUserMaxDevices, arg.ID, arg.MaxDevices) - var i Users - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.PasswordHash, - &i.FirstName, - &i.LastName, - &i.Role, - &i.Theme, - &i.MaxDevices, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const UpdateUserProfile = `-- name: UpdateUserProfile :exec -UPDATE users SET first_name = $2, last_name = $3, updated_at = NOW() WHERE id = $1 -` - -type UpdateUserProfileParams struct { - ID pgtype.UUID `db:"id" json:"id"` - FirstName pgtype.Text `db:"first_name" json:"first_name"` - LastName pgtype.Text `db:"last_name" json:"last_name"` -} - -func (q *Queries) UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) error { - _, err := q.db.Exec(ctx, UpdateUserProfile, arg.ID, arg.FirstName, arg.LastName) - return err -} - -const UpdateUserRole = `-- name: UpdateUserRole :one -UPDATE users SET role = $2, updated_at = NOW() WHERE id = $1 -RETURNING id, email, username, role -` - -type UpdateUserRoleParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Role string `db:"role" json:"role"` -} - -type UpdateUserRoleRow struct { - ID pgtype.UUID `db:"id" json:"id"` - Email string `db:"email" json:"email"` - Username string `db:"username" json:"username"` - Role string `db:"role" json:"role"` -} - -func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UpdateUserRoleRow, error) { - row := q.db.QueryRow(ctx, UpdateUserRole, arg.ID, arg.Role) - var i UpdateUserRoleRow - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.Role, - ) - return i, err -} - -const UpdateUserTheme = `-- name: UpdateUserTheme :exec -UPDATE users SET theme = $2, updated_at = NOW() WHERE id = $1 -` - -type UpdateUserThemeParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Theme pgtype.Text `db:"theme" json:"theme"` -} - -func (q *Queries) UpdateUserTheme(ctx context.Context, arg UpdateUserThemeParams) error { - _, err := q.db.Exec(ctx, UpdateUserTheme, arg.ID, arg.Theme) - return err -} - -const UpdateUsername = `-- name: UpdateUsername :exec -UPDATE users SET username = $2, updated_at = NOW() WHERE id = $1 -` - -type UpdateUsernameParams struct { - ID pgtype.UUID `db:"id" json:"id"` - Username string `db:"username" json:"username"` -} - -func (q *Queries) UpdateUsername(ctx context.Context, arg UpdateUsernameParams) error { - _, err := q.db.Exec(ctx, UpdateUsername, arg.ID, arg.Username) - return err -} - -const UpsertDashboardPreferences = `-- name: UpsertDashboardPreferences :one -INSERT INTO user_dashboard_preferences (user_id, library_id, hidden_collections, collection_order, items_per_section) -VALUES ($1, $2, $3, $4, $5) -ON CONFLICT (user_id, library_id) -DO UPDATE SET - hidden_collections = EXCLUDED.hidden_collections, - collection_order = EXCLUDED.collection_order, - items_per_section = EXCLUDED.items_per_section, - updated_at = NOW() -RETURNING id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at -` - -type UpsertDashboardPreferencesParams struct { - UserID pgtype.UUID `db:"user_id" json:"user_id"` - LibraryID pgtype.UUID `db:"library_id" json:"library_id"` - HiddenCollections []string `db:"hidden_collections" json:"hidden_collections"` - CollectionOrder []string `db:"collection_order" json:"collection_order"` - ItemsPerSection pgtype.Int4 `db:"items_per_section" json:"items_per_section"` -} - -func (q *Queries) UpsertDashboardPreferences(ctx context.Context, arg UpsertDashboardPreferencesParams) (UserDashboardPreferences, error) { - row := q.db.QueryRow(ctx, UpsertDashboardPreferences, - arg.UserID, - arg.LibraryID, - arg.HiddenCollections, - arg.CollectionOrder, - arg.ItemsPerSection, - ) - var i UserDashboardPreferences - err := row.Scan( - &i.ID, - &i.UserID, - &i.LibraryID, - &i.HiddenCollections, - &i.CollectionOrder, - &i.ItemsPerSection, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -}