Files
bookhoard/internal/database/queries.sql.go
T
john-okeefe 4c01c0d12e Phase 3 Week 7: Add KOReader bulk sync function to database schema
- Add bulk_update_progress_from_koreader() function for batch processing
- Handles progress, annotations, and conflict detection
- Returns success/failure status for each book
- Supports device matching by UUID, file path, or title/author
- Implements automatic conflict detection for concurrent syncs
- Part of Phase 3 KOReader Integration implementation
2026-01-30 20:54:51 -05:00

4305 lines
137 KiB
Go

// 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 BulkUpdateProgressFromSync = `-- name: BulkUpdateProgressFromSync :many
SELECT bulk_update_progress_from_koreader FROM bulk_update_progress_from_koreader($1::uuid, $2::jsonb)
`
type BulkUpdateProgressFromSyncParams struct {
Column1 pgtype.UUID `db:"column_1" json:"column_1"`
Column2 []byte `db:"column_2" json:"column_2"`
}
func (q *Queries) BulkUpdateProgressFromSync(ctx context.Context, arg BulkUpdateProgressFromSyncParams) ([]interface{}, error) {
rows, err := q.db.Query(ctx, BulkUpdateProgressFromSync, arg.Column1, arg.Column2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []interface{}{}
for rows.Next() {
var bulk_update_progress_from_koreader interface{}
if err := rows.Scan(&bulk_update_progress_from_koreader); err != nil {
return nil, err
}
items = append(items, bulk_update_progress_from_koreader)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const CheckForProgressConflicts = `-- name: CheckForProgressConflicts :one
SELECT COUNT(*) as conflict_count
FROM reading_progress
WHERE media_item_id = $1
AND user_id = $2
AND last_sync_timestamp > NOW() - INTERVAL '5 minutes'
AND last_sync_source != $3
`
type CheckForProgressConflictsParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"`
}
func (q *Queries) CheckForProgressConflicts(ctx context.Context, arg CheckForProgressConflictsParams) (int64, error) {
row := q.db.QueryRow(ctx, CheckForProgressConflicts, arg.MediaItemID, arg.UserID, arg.LastSyncSource)
var conflict_count int64
err := row.Scan(&conflict_count)
return conflict_count, 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 CreateSyncHistoryEntry = `-- name: CreateSyncHistoryEntry :one
INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, status)
VALUES ($1, $2, 'koreader_progress', $3, 5, 'completed')
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`
type CreateSyncHistoryEntryParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
SyncData []byte `db:"sync_data" json:"sync_data"`
}
func (q *Queries) CreateSyncHistoryEntry(ctx context.Context, arg CreateSyncHistoryEntryParams) (SyncQueue, error) {
row := q.db.QueryRow(ctx, CreateSyncHistoryEntry, arg.DeviceID, arg.MediaItemID, arg.SyncData)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const CreateSyncQueueItem = `-- name: CreateSyncQueueItem :one
INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, max_attempts, status)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`
type CreateSyncQueueItemParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
SyncType string `db:"sync_type" json:"sync_type"`
SyncData []byte `db:"sync_data" json:"sync_data"`
Priority pgtype.Int4 `db:"priority" json:"priority"`
MaxAttempts pgtype.Int4 `db:"max_attempts" json:"max_attempts"`
Status pgtype.Text `db:"status" json:"status"`
}
// Sync Queue Management
func (q *Queries) CreateSyncQueueItem(ctx context.Context, arg CreateSyncQueueItemParams) (SyncQueue, error) {
row := q.db.QueryRow(ctx, CreateSyncQueueItem,
arg.DeviceID,
arg.MediaItemID,
arg.SyncType,
arg.SyncData,
arg.Priority,
arg.MaxAttempts,
arg.Status,
)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const 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 GetAnnotationsForBook = `-- name: GetAnnotationsForBook :many
SELECT
mh.id,
mh.selection_text,
mh.start_position,
mh.end_position,
mh.color,
mh.created_at,
mh.updated_at,
'highlight' as annotation_type,
mh.percentage_start,
mh.percentage_end,
mh.epubcfi_start,
mh.epubcfi_end
FROM media_highlights mh
WHERE mh.media_item_id = $1 AND mh.user_id = $2
UNION ALL
SELECT
mn.id,
mn.content,
mn.position,
NULL as end_position,
NULL as color,
mn.created_at,
mn.updated_at,
'note' as annotation_type,
mn.percentage_location as percentage_start,
NULL as percentage_end,
mn.epubcfi_location as epubcfi_start,
NULL as epubcfi_end
FROM media_notes mn
WHERE mn.media_item_id = $1 AND mn.user_id = $2
ORDER BY created_at DESC
`
type GetAnnotationsForBookParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
type GetAnnotationsForBookRow struct {
ID pgtype.UUID `db:"id" json:"id"`
SelectionText string `db:"selection_text" json:"selection_text"`
StartPosition pgtype.Text `db:"start_position" json:"start_position"`
EndPosition pgtype.Text `db:"end_position" json:"end_position"`
Color pgtype.Text `db:"color" json:"color"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
AnnotationType string `db:"annotation_type" json:"annotation_type"`
PercentageStart pgtype.Float8 `db:"percentage_start" json:"percentage_start"`
PercentageEnd pgtype.Float8 `db:"percentage_end" json:"percentage_end"`
EpubcfiStart pgtype.Text `db:"epubcfi_start" json:"epubcfi_start"`
EpubcfiEnd pgtype.Text `db:"epubcfi_end" json:"epubcfi_end"`
}
func (q *Queries) GetAnnotationsForBook(ctx context.Context, arg GetAnnotationsForBookParams) ([]GetAnnotationsForBookRow, error) {
rows, err := q.db.Query(ctx, GetAnnotationsForBook, arg.MediaItemID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetAnnotationsForBookRow{}
for rows.Next() {
var i GetAnnotationsForBookRow
if err := rows.Scan(
&i.ID,
&i.SelectionText,
&i.StartPosition,
&i.EndPosition,
&i.Color,
&i.CreatedAt,
&i.UpdatedAt,
&i.AnnotationType,
&i.PercentageStart,
&i.PercentageEnd,
&i.EpubcfiStart,
&i.EpubcfiEnd,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const 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 GetMediaItemByFilePathForSync = `-- name: GetMediaItemByFilePathForSync :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count FROM media_items WHERE file_path = $1
`
// ============================================
// PHASE 3: KOREADER SYNC PROTOCOL (Weeks 7-9)
// ============================================
func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath string) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByFilePathForSync, filePath)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
)
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 GetUserMediaItemsForSync = `-- name: GetUserMediaItemsForSync :many
SELECT
mi.id,
mi.title,
mi.author,
mi.file_path,
mi.mime_type,
mi.page_count,
mi.format_group,
mi.total_characters,
mi.chapter_count
FROM media_items mi
JOIN library_visibility lv ON mi.library_id = lv.library_id
WHERE lv.user_id = $1
AND lv.is_visible = true
ORDER BY mi.title ASC
LIMIT 1000
`
type GetUserMediaItemsForSyncRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
FormatGroup string `db:"format_group" json:"format_group"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
}
func (q *Queries) GetUserMediaItemsForSync(ctx context.Context, userID pgtype.UUID) ([]GetUserMediaItemsForSyncRow, error) {
rows, err := q.db.Query(ctx, GetUserMediaItemsForSync, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserMediaItemsForSyncRow{}
for rows.Next() {
var i GetUserMediaItemsForSyncRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.Author,
&i.FilePath,
&i.MimeType,
&i.PageCount,
&i.FormatGroup,
&i.TotalCharacters,
&i.ChapterCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserPasswordHash = `-- name: GetUserPasswordHash :one
SELECT password_hash FROM users WHERE id = $1
`
func (q *Queries) GetUserPasswordHash(ctx context.Context, id pgtype.UUID) (string, error) {
row := q.db.QueryRow(ctx, GetUserPasswordHash, id)
var password_hash string
err := row.Scan(&password_hash)
return password_hash, err
}
const GetUserProgressForBooks = `-- name: GetUserProgressForBooks :many
SELECT
rp.media_item_id,
rp.user_id,
rp.percentage,
rp.character_offset,
rp.epubcfi,
rp.chapter,
rp.chapter_progress,
rp.current_page,
rp.total_pages,
rp.last_read_at,
rp.last_sync_device,
rp.last_sync_source,
mi.title,
mi.author,
mi.file_path
FROM reading_progress rp
JOIN media_items mi ON rp.media_item_id = mi.id
WHERE rp.user_id = $1
AND rp.media_item_id = ANY($2::uuid[])
ORDER BY rp.last_read_at DESC
`
type GetUserProgressForBooksParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Column2 []pgtype.UUID `db:"column_2" json:"column_2"`
}
type GetUserProgressForBooksRow struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Percentage pgtype.Float8 `db:"percentage" json:"percentage"`
CharacterOffset pgtype.Int8 `db:"character_offset" json:"character_offset"`
Epubcfi pgtype.Text `db:"epubcfi" json:"epubcfi"`
Chapter pgtype.Int4 `db:"chapter" json:"chapter"`
ChapterProgress pgtype.Float8 `db:"chapter_progress" json:"chapter_progress"`
CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"`
TotalPages pgtype.Int4 `db:"total_pages" json:"total_pages"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
LastSyncDevice pgtype.Text `db:"last_sync_device" json:"last_sync_device"`
LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
}
func (q *Queries) GetUserProgressForBooks(ctx context.Context, arg GetUserProgressForBooksParams) ([]GetUserProgressForBooksRow, error) {
rows, err := q.db.Query(ctx, GetUserProgressForBooks, arg.UserID, arg.Column2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserProgressForBooksRow{}
for rows.Next() {
var i GetUserProgressForBooksRow
if err := rows.Scan(
&i.MediaItemID,
&i.UserID,
&i.Percentage,
&i.CharacterOffset,
&i.Epubcfi,
&i.Chapter,
&i.ChapterProgress,
&i.CurrentPage,
&i.TotalPages,
&i.LastReadAt,
&i.LastSyncDevice,
&i.LastSyncSource,
&i.Title,
&i.Author,
&i.FilePath,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const 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 UpdateDeviceSyncTimestamp = `-- name: UpdateDeviceSyncTimestamp :one
UPDATE devices
SET
last_sync = NOW(),
last_seen = NOW(),
updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
func (q *Queries) UpdateDeviceSyncTimestamp(ctx context.Context, id pgtype.UUID) (Devices, error) {
row := q.db.QueryRow(ctx, UpdateDeviceSyncTimestamp, id)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const 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
}