// 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 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 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 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"` } // ============================================ // PHASE 2: DEVICE MANAGEMENT & AUTH (Weeks 5-6) // ============================================ // 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 CreateEbookNote = `-- name: CreateEbookNote :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 CreateEbookNoteParams 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"` } // Backward compatibility - Ebook Notes queries (using views) func (q *Queries) CreateEbookNote(ctx context.Context, arg CreateEbookNoteParams) (MediaNotes, error) { row := q.db.QueryRow(ctx, CreateEbookNote, 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 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, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id) 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) 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 ` 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 pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` } // 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.Asin, arg.DatePublished, arg.Publisher, arg.Contributors, arg.Language, arg.Edition, arg.PageCount, arg.Genre, arg.CopyrightYear, arg.GoodreadsID, arg.OpenlibraryID, arg.GoogleBooksID, arg.AddedByAdminID, ) 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, ) 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 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 string `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 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 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 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 DeleteEbookNote = `-- name: DeleteEbookNote :exec DELETE FROM media_notes WHERE id = $1 ` func (q *Queries) DeleteEbookNote(ctx context.Context, id pgtype.UUID) error { _, err := q.db.Exec(ctx, DeleteEbookNote, id) 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 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 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 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 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 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 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, ) 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 FROM media_items WHERE file_path = $1 ` func (q *Queries) GetMediaItemByFilePath(ctx context.Context, filePath string) (MediaItems, error) { row := q.db.QueryRow(ctx, GetMediaItemByFilePath, 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, ) return i, err } 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 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 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 string `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 string) (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 GetScanSettings = `-- name: GetScanSettings :one SELECT scan_frequency_minutes, auto_scan_enabled FROM users WHERE id = $1 ` type GetScanSettingsRow struct { ScanFrequencyMinutes pgtype.Int4 `db:"scan_frequency_minutes" json:"scan_frequency_minutes"` AutoScanEnabled pgtype.Bool `db:"auto_scan_enabled" json:"auto_scan_enabled"` } func (q *Queries) GetScanSettings(ctx context.Context, id pgtype.UUID) (GetScanSettingsRow, error) { row := q.db.QueryRow(ctx, GetScanSettings, id) var i GetScanSettingsRow err := row.Scan(&i.ScanFrequencyMinutes, &i.AutoScanEnabled) return i, err } 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 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 GetUser = `-- name: GetUser :one SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE 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"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } 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.CreatedAt, &i.UpdatedAt, ) 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 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 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 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 DESC ` 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 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, 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 pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` 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.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, 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 pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` 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.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, l.name as library_name, lt.name as library_type_name FROM media_items mi JOIN libraries l ON mi.library_id = l.id JOIN library_types lt ON l.library_type_id = lt.id LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1 WHERE mi.library_id = $2 AND COALESCE(lv.is_visible, true) = true AND ($3 = '' OR mi.author ILIKE $3) AND ($4 = '' OR mi.series ILIKE $4) AND ($5 = '' OR mi.genre = $5) AND ($6 = '' OR mi.language = $6) AND ($7 = 0 OR mi.copyright_year >= $7) AND ($8 = 0 OR mi.copyright_year <= $8) AND ($9 = false OR mi.cover_image_path IS NOT NULL) ORDER BY CASE WHEN $10 = 'title ASC' THEN mi.title ELSE '' END ASC, CASE WHEN $10 = 'title DESC' THEN mi.title ELSE '' END DESC, CASE WHEN $10 = 'author ASC' THEN COALESCE(mi.author, '') ELSE '' END ASC, CASE WHEN $10 = 'author DESC' THEN COALESCE(mi.author, '') ELSE '' END DESC, CASE WHEN $10 = 'created_at ASC' THEN mi.created_at ELSE '1970-01-01'::timestamp END ASC, CASE WHEN $10 = 'created_at DESC' THEN mi.created_at ELSE '1970-01-01'::timestamp END DESC, mi.created_at DESC LIMIT $12 OFFSET $11 ` type ListMediaItemsFilteredParams struct { UserID pgtype.UUID `db:"user_id" json:"user_id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` AuthorFilter interface{} `db:"author_filter" json:"author_filter"` SeriesFilter interface{} `db:"series_filter" json:"series_filter"` GenreFilter interface{} `db:"genre_filter" json:"genre_filter"` LanguageFilter interface{} `db:"language_filter" json:"language_filter"` YearMin interface{} `db:"year_min" json:"year_min"` YearMax interface{} `db:"year_max" json:"year_max"` HasCover interface{} `db:"has_cover" json:"has_cover"` Sort interface{} `db:"sort" json:"sort"` Offset pgtype.Int4 `db:"offset" json:"offset"` Limit pgtype.Int4 `db:"limit" json:"limit"` } type ListMediaItemsFilteredRow struct { ID pgtype.UUID `db:"id" json:"id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Title string `db:"title" json:"title"` Author pgtype.Text `db:"author" json:"author"` Isbn pgtype.Text `db:"isbn" json:"isbn"` Description pgtype.Text `db:"description" json:"description"` FilePath string `db:"file_path" json:"file_path"` FileSize pgtype.Int8 `db:"file_size" json:"file_size"` MimeType pgtype.Text `db:"mime_type" json:"mime_type"` CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"` Series pgtype.Text `db:"series" json:"series"` SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"` Tags pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` 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.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, l.name as library_name, lt.name as library_type_name FROM media_items mi JOIN libraries l ON mi.library_id = l.id JOIN library_types lt ON l.library_type_id = lt.id WHERE mi.library_id = $1 ORDER BY CASE WHEN $2 = 'title ASC' THEN mi.title ELSE '' END ASC, CASE WHEN $2 = 'title DESC' THEN mi.title ELSE '' END DESC, CASE WHEN $2 = 'author ASC' THEN COALESCE(mi.author, '') ELSE '' END ASC, CASE WHEN $2 = 'author DESC' THEN COALESCE(mi.author, '') ELSE '' END DESC, CASE WHEN $2 = 'created_at ASC' THEN mi.created_at ELSE '1970-01-01'::timestamp END ASC, CASE WHEN $2 = 'created_at DESC' THEN mi.created_at ELSE '1970-01-01'::timestamp END DESC, CASE WHEN $2 = 'series ASC' THEN COALESCE(mi.series, '') ELSE '' END ASC, CASE WHEN $2 = 'series DESC' THEN COALESCE(mi.series, '') ELSE '' END DESC, CASE WHEN $2 = 'date_published ASC' THEN COALESCE(mi.date_published::text, '') ELSE '' END ASC, CASE WHEN $2 = 'date_published DESC' THEN COALESCE(mi.date_published::text, '') ELSE '' END DESC, CASE WHEN $2 = 'copyright_year ASC' THEN COALESCE(mi.copyright_year::text, '0') ELSE '' END ASC, CASE WHEN $2 = 'copyright_year DESC' THEN COALESCE(mi.copyright_year::text, '0') ELSE '' END DESC, CASE WHEN $2 = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0') ELSE '' END ASC, CASE WHEN $2 = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0') ELSE '' END DESC, CASE WHEN $2 = 'genre ASC' THEN COALESCE(mi.genre, '') ELSE '' END ASC, CASE WHEN $2 = 'genre DESC' THEN COALESCE(mi.genre, '') ELSE '' END DESC, mi.created_at DESC LIMIT $4 OFFSET $3 ` type ListMediaItemsSortedParams struct { LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Sort interface{} `db:"sort" json:"sort"` Offset pgtype.Int4 `db:"offset" json:"offset"` Limit pgtype.Int4 `db:"limit" json:"limit"` } type ListMediaItemsSortedRow struct { ID pgtype.UUID `db:"id" json:"id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` Title string `db:"title" json:"title"` Author pgtype.Text `db:"author" json:"author"` Isbn pgtype.Text `db:"isbn" json:"isbn"` Description pgtype.Text `db:"description" json:"description"` FilePath string `db:"file_path" json:"file_path"` FileSize pgtype.Int8 `db:"file_size" json:"file_size"` MimeType pgtype.Text `db:"mime_type" json:"mime_type"` CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"` Series pgtype.Text `db:"series" json:"series"` SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"` Tags pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` 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.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 ListUsers = `-- name: ListUsers :many SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users ORDER BY 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"` CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } 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.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 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 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 RevokeRefreshToken = `-- name: RevokeRefreshToken :exec UPDATE refresh_tokens SET revoked_at = NOW() WHERE token = $1 ` func (q *Queries) RevokeRefreshToken(ctx context.Context, token string) 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, l.name as library_name, lt.name as library_type_name FROM media_items mi JOIN libraries l ON mi.library_id = l.id JOIN library_types lt ON l.library_type_id = lt.id LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1 WHERE COALESCE(lv.is_visible, true) = true AND ( mi.title ILIKE $2 OR mi.author ILIKE $2 OR mi.series ILIKE $2 OR mi.tags ILIKE $2 OR mi.contributors ILIKE $2 ) ORDER BY CASE WHEN mi.title ILIKE $2 THEN 1 WHEN mi.author ILIKE $2 THEN 2 WHEN mi.series ILIKE $2 THEN 3 WHEN mi.tags ILIKE $2 THEN 4 ELSE 5 END, mi.title ASC LIMIT $4 OFFSET $3 ` type SearchMediaItemsParams struct { UserID pgtype.UUID `db:"user_id" json:"user_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 pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` LibraryName string `db:"library_name" json:"library_name"` LibraryTypeName string `db:"library_type_name" json:"library_type_name"` } // Note: User ebook folders replaced by library folders system // Legacy folder management is now handled through libraries // 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.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.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, 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 ( word_similarity($2, mi.title) > 0.3 OR word_similarity($2, COALESCE(mi.author, '')) > 0.3 OR word_similarity($2, COALESCE(mi.series, '')) > 0.3 OR word_similarity($2, COALESCE(mi.tags, '')) > 0.3 OR word_similarity($2, COALESCE(mi.contributors, '')) > 0.3 ) ORDER BY GREATEST( word_similarity($2, mi.title), word_similarity($2, COALESCE(mi.author, '')), word_similarity($2, COALESCE(mi.series, '')), word_similarity($2, COALESCE(mi.tags, '')), word_similarity($2, COALESCE(mi.contributors, '')) ) DESC, mi.title ASC LIMIT $4 OFFSET $3 ` type SearchMediaItemsFuzzyParams struct { UserID pgtype.UUID `db:"user_id" json:"user_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 pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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"` 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.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.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 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 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 UpdateEbookNote = `-- name: UpdateEbookNote :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 UpdateEbookNoteParams struct { ID pgtype.UUID `db:"id" json:"id"` Content string `db:"content" json:"content"` Position pgtype.Text `db:"position" json:"position"` } func (q *Queries) UpdateEbookNote(ctx context.Context, arg UpdateEbookNoteParams) (MediaNotes, error) { row := q.db.QueryRow(ctx, UpdateEbookNote, 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 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 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, asin = $10, date_published = $11, publisher = $12, contributors = $13, language = $14, edition = $15, page_count = $16, genre = $17, copyright_year = $18, goodreads_id = $19, openlibrary_id = $20, google_books_id = $21, 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 ` 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 pgtype.Text `db:"tags" json:"tags"` Asin pgtype.Text `db:"asin" json:"asin"` DatePublished pgtype.Date `db:"date_published" json:"date_published"` Publisher pgtype.Text `db:"publisher" json:"publisher"` Contributors pgtype.Text `db:"contributors" json:"contributors"` Language pgtype.Text `db:"language" json:"language"` Edition pgtype.Text `db:"edition" json:"edition"` PageCount pgtype.Int4 `db:"page_count" json:"page_count"` 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.Asin, arg.DatePublished, arg.Publisher, arg.Contributors, 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, ) 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"` } // ============================================ // PHASE 1: FORMAT DETECTION & PROGRESS (Week 2) // ============================================ // 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 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 UpdateScanSettings = `-- name: UpdateScanSettings :exec UPDATE users SET scan_frequency_minutes = $2, auto_scan_enabled = $3, updated_at = NOW() WHERE id = $1 ` type UpdateScanSettingsParams struct { ID pgtype.UUID `db:"id" json:"id"` ScanFrequencyMinutes pgtype.Int4 `db:"scan_frequency_minutes" json:"scan_frequency_minutes"` AutoScanEnabled pgtype.Bool `db:"auto_scan_enabled" json:"auto_scan_enabled"` } func (q *Queries) UpdateScanSettings(ctx context.Context, arg UpdateScanSettingsParams) error { _, err := q.db.Exec(ctx, UpdateScanSettings, arg.ID, arg.ScanFrequencyMinutes, arg.AutoScanEnabled) return err } const UpdateSyncQueueItemStatus = `-- name: UpdateSyncQueueItemStatus :one UPDATE sync_queue SET status = $2, attempts = attempts + 1, error_message = $3, processed_at = CASE WHEN $2 = '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 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 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 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 }