Files
bookhoard/internal/database/queries.sql.go
T
john-okeefe 9b171a0060 fix(scanner): prevent duplicate media item imports
A read-then-write race in processMediaFile allowed the same file to be
imported twice: two concurrent scan jobs (startup scan, fsnotify dirty-
directory scan, periodic backup poll, or a manual scan each run on
separate worker goroutines with separate MediaScanner instances) could
both SELECT 'not found' and both INSERT. There was no transaction, no
row lock, no unique constraint on (library_id, file_path), and no
ON CONFLICT clause, so nothing stopped the double insert. Observed in
production as two identical 'Head First SQL' rows created in the same
second (same sha256, size, path, library).

Database enforcement:
- schema.sql: add UNIQUE(library_id, file_path) constraint, guarded so
  re-runs don't error
- schema.sql: add self-healing migration that runs on every startup -
  dedup_media_items_by_path() collapses existing path-duplicates and
  reparent_media_item_children() moves all child rows (progress,
  highlights, bookmarks, notes, collections, formats, aliases, kobo
  entitlements, etc.) onto a survivor before deleting losers, so the
  constraint applies cleanly on already-duplicated servers without
  losing reading history. Survivor picks the row with the most user
  data, ties broken by lowest id
- CreateMediaItem: upsert via ON CONFLICT (library_id, file_path) DO
  UPDATE so concurrent inserts collapse to one row and return it
- CreateMediaItemFormat: upsert via ON CONFLICT (media_item_id,
  format_type), closing the same race on format rows

Application-level guards:
- media_scanner processMediaFile: after computing the file hash, check
  GetMediaItemBySHA256AndLibrary (new query) and treat the file as
  existing when identical content is already in the library under a
  different path (content dedup, library-scoped so multi-library
  setups still work)

Ops tooling:
- scripts/dedup_media_items.sql: standalone idempotent maintenance
  script with a dry-run report (path + content duplicate groups, child
  row counts) and transactional cleanup, for servers that prefer to
  dedup manually before upgrading

Verified against the live database: the duplicate pair was collapsed
(reading_progress preserved on the survivor), schema.sql re-runs are a
no-op, and the constraint is in place with 62 unique books remaining.
2026-08-14 08:18:36 -04:00

12478 lines
406 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: queries.sql
package database
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const AddBookToCollection = `-- name: AddBookToCollection :one
INSERT INTO collection_items (collection_id, media_item_id, added_by_user_id)
VALUES ($1, $2, $3)
ON CONFLICT (collection_id, media_item_id) DO NOTHING
RETURNING id, collection_id, media_item_id, added_at, added_by_user_id, excluded
`
type AddBookToCollectionParams struct {
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
AddedByUserID pgtype.UUID `db:"added_by_user_id" json:"added_by_user_id"`
}
// COLLECTION ITEMS QUERIES
// Add book to collection
func (q *Queries) AddBookToCollection(ctx context.Context, arg AddBookToCollectionParams) (CollectionItems, error) {
row := q.db.QueryRow(ctx, AddBookToCollection, arg.CollectionID, arg.MediaItemID, arg.AddedByUserID)
var i CollectionItems
err := row.Scan(
&i.ID,
&i.CollectionID,
&i.MediaItemID,
&i.AddedAt,
&i.AddedByUserID,
&i.Excluded,
)
return i, err
}
const AddBookToKoboShelf = `-- name: AddBookToKoboShelf :one
INSERT INTO kobo_shelves (device_id, media_item_id, shelf_name, shelf_position)
VALUES ($1, $2, $3, $4)
ON CONFLICT (device_id, media_item_id)
DO UPDATE SET
shelf_name = EXCLUDED.shelf_name,
shelf_position = EXCLUDED.shelf_position,
last_synced_at = NOW()
RETURNING id, device_id, media_item_id, shelf_name, shelf_position, added_at, last_synced_at, collection_id, position_in_collection
`
type AddBookToKoboShelfParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
}
// ============================================
// KOBO SHELF MANAGEMENT QUERIES
// ============================================
func (q *Queries) AddBookToKoboShelf(ctx context.Context, arg AddBookToKoboShelfParams) (KoboShelves, error) {
row := q.db.QueryRow(ctx, AddBookToKoboShelf,
arg.DeviceID,
arg.MediaItemID,
arg.ShelfName,
arg.ShelfPosition,
)
var i KoboShelves
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.ShelfName,
&i.ShelfPosition,
&i.AddedAt,
&i.LastSyncedAt,
&i.CollectionID,
&i.PositionInCollection,
)
return i, err
}
const AddLibraryFolder = `-- name: AddLibraryFolder :one
INSERT INTO library_folders (library_id, folder_path) VALUES ($1, $2) RETURNING id, library_id, folder_path, created_at
`
type AddLibraryFolderParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
FolderPath string `db:"folder_path" json:"folder_path"`
}
// Library Folders queries
func (q *Queries) AddLibraryFolder(ctx context.Context, arg AddLibraryFolderParams) (LibraryFolders, error) {
row := q.db.QueryRow(ctx, AddLibraryFolder, arg.LibraryID, arg.FolderPath)
var i LibraryFolders
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.FolderPath,
&i.CreatedAt,
)
return i, err
}
const BulkUpdateFormatGroups = `-- name: BulkUpdateFormatGroups :exec
UPDATE media_items m
SET
format_group = detect_format_group(m.mime_type, m.file_path),
format_mimetype = m.mime_type,
is_reflowable = (detect_format_group(m.mime_type, m.file_path) = 'reflowable'),
has_fixed_layout = (detect_format_group(m.mime_type, m.file_path) IN ('fixed_layout', 'comic_archive')),
updated_at = NOW()
WHERE m.format_group IS NULL OR m.format_group = 'unknown'
`
// Bulk update format group for all media items
func (q *Queries) BulkUpdateFormatGroups(ctx context.Context) error {
_, err := q.db.Exec(ctx, BulkUpdateFormatGroups)
return err
}
const BulkUpdateProgressFromSync = `-- name: BulkUpdateProgressFromSync :many
SELECT bulk_update_progress_from_koreader FROM bulk_update_progress_from_koreader($1::uuid, $2::jsonb)
`
type BulkUpdateProgressFromSyncParams struct {
Column1 pgtype.UUID `db:"column_1" json:"column_1"`
Column2 []byte `db:"column_2" json:"column_2"`
}
func (q *Queries) BulkUpdateProgressFromSync(ctx context.Context, arg BulkUpdateProgressFromSyncParams) ([]interface{}, error) {
rows, err := q.db.Query(ctx, BulkUpdateProgressFromSync, arg.Column1, arg.Column2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []interface{}{}
for rows.Next() {
var bulk_update_progress_from_koreader interface{}
if err := rows.Scan(&bulk_update_progress_from_koreader); err != nil {
return nil, err
}
items = append(items, bulk_update_progress_from_koreader)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const 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 CleanupExpiredOpdsTokens = `-- name: CleanupExpiredOpdsTokens :exec
DELETE FROM opds_tokens WHERE expires_at < NOW()
`
// Cleanup expired OPDS tokens
func (q *Queries) CleanupExpiredOpdsTokens(ctx context.Context) error {
_, err := q.db.Exec(ctx, CleanupExpiredOpdsTokens)
return err
}
const CleanupExpiredRefreshTokens = `-- name: CleanupExpiredRefreshTokens :exec
DELETE FROM refresh_tokens WHERE expires_at < NOW() OR (revoked_at IS NOT NULL AND revoked_at < NOW() - make_interval(secs => $1::double precision))
`
func (q *Queries) CleanupExpiredRefreshTokens(ctx context.Context, dollar_1 float64) error {
_, err := q.db.Exec(ctx, CleanupExpiredRefreshTokens, dollar_1)
return err
}
const ClearDeviceSyncQueue = `-- name: ClearDeviceSyncQueue :exec
DELETE FROM sync_queue WHERE device_id = $1
`
func (q *Queries) ClearDeviceSyncQueue(ctx context.Context, deviceID pgtype.UUID) error {
_, err := q.db.Exec(ctx, ClearDeviceSyncQueue, deviceID)
return err
}
const ClearKoboShelf = `-- name: ClearKoboShelf :exec
DELETE FROM kobo_shelves WHERE device_id = $1
`
func (q *Queries) ClearKoboShelf(ctx context.Context, deviceID pgtype.UUID) error {
_, err := q.db.Exec(ctx, ClearKoboShelf, deviceID)
return err
}
const ClearKoboShelfByName = `-- name: ClearKoboShelfByName :exec
DELETE FROM kobo_shelves WHERE device_id = $1 AND shelf_name = $2
`
type ClearKoboShelfByNameParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
}
func (q *Queries) ClearKoboShelfByName(ctx context.Context, arg ClearKoboShelfByNameParams) error {
_, err := q.db.Exec(ctx, ClearKoboShelfByName, arg.DeviceID, arg.ShelfName)
return err
}
const CountAdmins = `-- name: CountAdmins :one
SELECT COUNT(*) FROM users WHERE role = 'admin'
`
func (q *Queries) CountAdmins(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, CountAdmins)
var count int64
err := row.Scan(&count)
return count, err
}
const CountUnlinkedBooks = `-- name: CountUnlinkedBooks :one
SELECT COUNT(*) as count
FROM unlinked_books
WHERE device_id = $1 AND resolved = false
`
// Count unlinked books for a device
func (q *Queries) CountUnlinkedBooks(ctx context.Context, deviceID pgtype.UUID) (int64, error) {
row := q.db.QueryRow(ctx, CountUnlinkedBooks, deviceID)
var count int64
err := row.Scan(&count)
return count, err
}
const CountUserDevices = `-- name: CountUserDevices :one
SELECT COUNT(*) FROM devices WHERE user_id = $1
`
func (q *Queries) CountUserDevices(ctx context.Context, userID pgtype.UUID) (int64, error) {
row := q.db.QueryRow(ctx, CountUserDevices, userID)
var count int64
err := row.Scan(&count)
return count, err
}
const CreateAutoResolvedSyncConflict = `-- name: CreateAutoResolvedSyncConflict :one
INSERT INTO sync_conflicts (media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_at)
VALUES ($1, $2, $3, $4, 'auto_resolved', $5, NOW())
RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at
`
type CreateAutoResolvedSyncConflictParams 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"`
ResolutionData []byte `db:"resolution_data" json:"resolution_data"`
}
func (q *Queries) CreateAutoResolvedSyncConflict(ctx context.Context, arg CreateAutoResolvedSyncConflictParams) (SyncConflicts, error) {
row := q.db.QueryRow(ctx, CreateAutoResolvedSyncConflict,
arg.MediaItemID,
arg.UserID,
arg.ConflictType,
arg.ConflictData,
arg.ResolutionData,
)
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 CreateCollection = `-- name: CreateCollection :one
INSERT INTO collections (user_id, name, description, color, icon, auto_assign_rules, view_settings)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at
`
type CreateCollectionParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
Color pgtype.Text `db:"color" json:"color"`
Icon pgtype.Text `db:"icon" json:"icon"`
AutoAssignRules []byte `db:"auto_assign_rules" json:"auto_assign_rules"`
ViewSettings []byte `db:"view_settings" json:"view_settings"`
}
// COLLECTIONS QUERIES
// Create collection
func (q *Queries) CreateCollection(ctx context.Context, arg CreateCollectionParams) (Collections, error) {
row := q.db.QueryRow(ctx, CreateCollection,
arg.UserID,
arg.Name,
arg.Description,
arg.Color,
arg.Icon,
arg.AutoAssignRules,
arg.ViewSettings,
)
var i Collections
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
)
return i, err
}
const CreateDevice = `-- name: CreateDevice :one
INSERT INTO devices (user_id, device_name, device_type, device_identifier, auth_token, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
type CreateDeviceParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
DeviceName string `db:"device_name" json:"device_name"`
DeviceType string `db:"device_type" json:"device_type"`
DeviceIdentifier string `db:"device_identifier" json:"device_identifier"`
AuthToken string `db:"auth_token" json:"auth_token"`
SyncEnabled pgtype.Bool `db:"sync_enabled" json:"sync_enabled"`
AutoSync pgtype.Bool `db:"auto_sync" json:"auto_sync"`
SyncFrequencyMinutes pgtype.Int4 `db:"sync_frequency_minutes" json:"sync_frequency_minutes"`
DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"`
}
// ============================================
// DEVICE MANAGEMENT & AUTH
// ============================================
// Device Registration & Management
func (q *Queries) CreateDevice(ctx context.Context, arg CreateDeviceParams) (Devices, error) {
row := q.db.QueryRow(ctx, CreateDevice,
arg.UserID,
arg.DeviceName,
arg.DeviceType,
arg.DeviceIdentifier,
arg.AuthToken,
arg.SyncEnabled,
arg.AutoSync,
arg.SyncFrequencyMinutes,
arg.DeviceMetadata,
)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateDeviceCatalog = `-- name: CreateDeviceCatalog :one
INSERT INTO device_catalogs (device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (device_id, kobo_content_id)
DO UPDATE SET
available = EXCLUDED.available,
delivery_date = COALESCE(EXCLUDED.delivery_date, device_catalogs.delivery_date),
delivery_method = EXCLUDED.delivery_method
RETURNING id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method
`
type CreateDeviceCatalogParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"`
KoboContentID string `db:"kobo_content_id" json:"kobo_content_id"`
ContentIDType pgtype.Text `db:"content_id_type" json:"content_id_type"`
Available pgtype.Bool `db:"available" json:"available"`
DeliveryDate pgtype.Timestamptz `db:"delivery_date" json:"delivery_date"`
DeliveryMethod pgtype.Text `db:"delivery_method" json:"delivery_method"`
}
// DEVICE CATALOGS QUERIES
// Create device catalog entry
func (q *Queries) CreateDeviceCatalog(ctx context.Context, arg CreateDeviceCatalogParams) (DeviceCatalogs, error) {
row := q.db.QueryRow(ctx, CreateDeviceCatalog,
arg.DeviceID,
arg.MediaItemID,
arg.BookhoardUuid,
arg.KoboContentID,
arg.ContentIDType,
arg.Available,
arg.DeliveryDate,
arg.DeliveryMethod,
)
var i DeviceCatalogs
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.BookhoardUuid,
&i.KoboContentID,
&i.ContentIDType,
&i.Available,
&i.DeliveryDate,
&i.DeliveryMethod,
)
return i, err
}
const CreateDeviceFileAlias = `-- name: CreateDeviceFileAlias :one
INSERT INTO device_file_aliases (media_item_id, device_id, file_path, file_sha256, confidence_score)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at
`
type CreateDeviceFileAliasParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
FilePath string `db:"file_path" json:"file_path"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}
// DEVICE FILE ALIASES QUERIES
// Create device file alias
func (q *Queries) CreateDeviceFileAlias(ctx context.Context, arg CreateDeviceFileAliasParams) (DeviceFileAliases, error) {
row := q.db.QueryRow(ctx, CreateDeviceFileAlias,
arg.MediaItemID,
arg.DeviceID,
arg.FilePath,
arg.FileSha256,
arg.ConfidenceScore,
)
var i DeviceFileAliases
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.DeviceID,
&i.FilePath,
&i.FileSha256,
&i.ConfidenceScore,
&i.LastSeenAt,
)
return i, err
}
const CreateDeviceShelfMapping = `-- name: CreateDeviceShelfMapping :one
INSERT INTO device_shelf_mappings (collection_id, device_id, device_shelf_name, sync_direction)
VALUES ($1, $2, $3, $4)
ON CONFLICT (collection_id, device_id)
DO UPDATE SET
device_shelf_name = EXCLUDED.device_shelf_name,
sync_direction = EXCLUDED.sync_direction
RETURNING id, collection_id, device_id, device_shelf_name, sync_direction, created_at
`
type CreateDeviceShelfMappingParams struct {
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"`
SyncDirection pgtype.Text `db:"sync_direction" json:"sync_direction"`
}
// DEVICE SHELF MAPPINGS QUERIES
// Create device shelf mapping
func (q *Queries) CreateDeviceShelfMapping(ctx context.Context, arg CreateDeviceShelfMappingParams) (DeviceShelfMappings, error) {
row := q.db.QueryRow(ctx, CreateDeviceShelfMapping,
arg.CollectionID,
arg.DeviceID,
arg.DeviceShelfName,
arg.SyncDirection,
)
var i DeviceShelfMappings
err := row.Scan(
&i.ID,
&i.CollectionID,
&i.DeviceID,
&i.DeviceShelfName,
&i.SyncDirection,
&i.CreatedAt,
)
return i, err
}
const CreateDictionaryEntry = `-- name: CreateDictionaryEntry :one
INSERT INTO dictionary_cache (word, definition, part_of_speech, example, etymology, accessed_at)
VALUES ($1, $2, $3, $4, $5, NOW())
RETURNING id, word, definition, part_of_speech, example, etymology, created_at, accessed_at
`
type CreateDictionaryEntryParams struct {
Word string `db:"word" json:"word"`
Definition string `db:"definition" json:"definition"`
PartOfSpeech pgtype.Text `db:"part_of_speech" json:"part_of_speech"`
Example pgtype.Text `db:"example" json:"example"`
Etymology pgtype.Text `db:"etymology" json:"etymology"`
}
func (q *Queries) CreateDictionaryEntry(ctx context.Context, arg CreateDictionaryEntryParams) (DictionaryCache, error) {
row := q.db.QueryRow(ctx, CreateDictionaryEntry,
arg.Word,
arg.Definition,
arg.PartOfSpeech,
arg.Example,
arg.Etymology,
)
var i DictionaryCache
err := row.Scan(
&i.ID,
&i.Word,
&i.Definition,
&i.PartOfSpeech,
&i.Example,
&i.Etymology,
&i.CreatedAt,
&i.AccessedAt,
)
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 CreateMediaBookmark = `-- name: CreateMediaBookmark :one
INSERT INTO media_bookmarks (media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at
`
type CreateMediaBookmarkParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
PageNumber pgtype.Int4 `db:"page_number" json:"page_number"`
ChapterNumber pgtype.Int4 `db:"chapter_number" json:"chapter_number"`
CfiPosition pgtype.Text `db:"cfi_position" json:"cfi_position"`
Title string `db:"title" json:"title"`
Position pgtype.Text `db:"position" json:"position"`
Notes pgtype.Text `db:"notes" json:"notes"`
}
func (q *Queries) CreateMediaBookmark(ctx context.Context, arg CreateMediaBookmarkParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, CreateMediaBookmark,
arg.MediaItemID,
arg.UserID,
arg.PageNumber,
arg.ChapterNumber,
arg.CfiPosition,
arg.Title,
arg.Position,
arg.Notes,
)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const CreateMediaBookmarkFull = `-- name: CreateMediaBookmarkFull :one
INSERT INTO media_bookmarks (
media_item_id, user_id, page_number, chapter_number,
cfi_position, title, position, notes,
percentage_location, epubcfi_location, chapter_reference,
dedup_key, last_modified_at, last_modified_source,
device_sync_data
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
) RETURNING id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at
`
type CreateMediaBookmarkFullParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
PageNumber pgtype.Int4 `db:"page_number" json:"page_number"`
ChapterNumber pgtype.Int4 `db:"chapter_number" json:"chapter_number"`
CfiPosition pgtype.Text `db:"cfi_position" json:"cfi_position"`
Title string `db:"title" json:"title"`
Position pgtype.Text `db:"position" json:"position"`
Notes pgtype.Text `db:"notes" json:"notes"`
PercentageLocation pgtype.Float8 `db:"percentage_location" json:"percentage_location"`
EpubcfiLocation pgtype.Text `db:"epubcfi_location" json:"epubcfi_location"`
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
}
func (q *Queries) CreateMediaBookmarkFull(ctx context.Context, arg CreateMediaBookmarkFullParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, CreateMediaBookmarkFull,
arg.MediaItemID,
arg.UserID,
arg.PageNumber,
arg.ChapterNumber,
arg.CfiPosition,
arg.Title,
arg.Position,
arg.Notes,
arg.PercentageLocation,
arg.EpubcfiLocation,
arg.ChapterReference,
arg.DedupKey,
arg.LastModifiedAt,
arg.LastModifiedSource,
arg.DeviceSyncData,
)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
)
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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at
`
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const CreateMediaHighlightFull = `-- name: CreateMediaHighlightFull :one
INSERT INTO media_highlights (
media_item_id, user_id, selection_text,
start_position, end_position, color, note_text,
percentage_start, percentage_end,
epubcfi_start, epubcfi_end,
chapter_reference,
dedup_key, last_modified_at, last_modified_source,
device_sync_data
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16
) 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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at
`
type CreateMediaHighlightFullParams 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"`
NoteText pgtype.Text `db:"note_text" json:"note_text"`
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"`
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
}
func (q *Queries) CreateMediaHighlightFull(ctx context.Context, arg CreateMediaHighlightFullParams) (MediaHighlights, error) {
row := q.db.QueryRow(ctx, CreateMediaHighlightFull,
arg.MediaItemID,
arg.UserID,
arg.SelectionText,
arg.StartPosition,
arg.EndPosition,
arg.Color,
arg.NoteText,
arg.PercentageStart,
arg.PercentageEnd,
arg.EpubcfiStart,
arg.EpubcfiEnd,
arg.ChapterReference,
arg.DedupKey,
arg.LastModifiedAt,
arg.LastModifiedSource,
arg.DeviceSyncData,
)
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const CreateMediaItem = `-- name: CreateMediaItem :one
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, library_type_name)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44)
ON CONFLICT (library_id, file_path) DO UPDATE SET updated_at = NOW()
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type CreateMediaItemParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
}
// Media Items queries
func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, CreateMediaItem,
arg.LibraryID,
arg.Title,
arg.Author,
arg.Isbn,
arg.Description,
arg.FilePath,
arg.FileSize,
arg.MimeType,
arg.CoverImagePath,
arg.Series,
arg.SeriesNumber,
arg.Tags,
arg.TagsSearch,
arg.Asin,
arg.DatePublished,
arg.Publisher,
arg.Contributors,
arg.ContributorsSearch,
arg.Language,
arg.Edition,
arg.PageCount,
arg.Genre,
arg.CopyrightYear,
arg.GoodreadsID,
arg.OpenlibraryID,
arg.GoogleBooksID,
arg.AddedByAdminID,
arg.CreatedAt,
arg.ImportedAt,
arg.MangaType,
arg.ReadingDirection,
arg.SeriesCount,
arg.Volume,
arg.Imprint,
arg.AgeRating,
arg.WebUrl,
arg.StoryArc,
arg.IsBlackAndWhite,
arg.MetadataNotes,
arg.CommunityRating,
arg.AlternateInfo,
arg.ScanInformation,
arg.Summary,
arg.LibraryTypeName,
)
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const CreateMediaItemFormat = `-- name: CreateMediaItemFormat :one
INSERT INTO media_item_formats (media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, converted_from_format_id)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (media_item_id, format_type) DO UPDATE SET
file_path = EXCLUDED.file_path,
file_sha256 = EXCLUDED.file_sha256,
file_size_bytes = EXCLUDED.file_size_bytes,
mime_type = EXCLUDED.mime_type
RETURNING id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id
`
type CreateMediaItemFormatParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
FormatType string `db:"format_type" json:"format_type"`
FilePath pgtype.Text `db:"file_path" json:"file_path"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
FileSizeBytes pgtype.Int8 `db:"file_size_bytes" json:"file_size_bytes"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
ConvertedFromFormatID pgtype.UUID `db:"converted_from_format_id" json:"converted_from_format_id"`
}
// MEDIA ITEM FORMATS QUERIES
// Create media item format
func (q *Queries) CreateMediaItemFormat(ctx context.Context, arg CreateMediaItemFormatParams) (MediaItemFormats, error) {
row := q.db.QueryRow(ctx, CreateMediaItemFormat,
arg.MediaItemID,
arg.FormatType,
arg.FilePath,
arg.FileSha256,
arg.FileSizeBytes,
arg.MimeType,
arg.ConvertedFromFormatID,
)
var i MediaItemFormats
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.FormatType,
&i.FilePath,
&i.FileSha256,
&i.FileSizeBytes,
&i.MimeType,
&i.CreatedAt,
&i.ConvertedFromFormatID,
)
return i, err
}
const CreateMediaNote = `-- name: CreateMediaNote :one
INSERT INTO media_notes (media_item_id, user_id, content, position)
VALUES ($1, $2, $3, $4)
RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at
`
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const CreateMediaNoteFull = `-- name: CreateMediaNoteFull :one
INSERT INTO media_notes (
media_item_id, user_id, content, position,
percentage_location, character_start, character_end,
epubcfi_location, chapter_reference, paragraph_reference,
dedup_key, last_modified_at, last_modified_source,
device_sync_data
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14
) 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, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at
`
type CreateMediaNoteFullParams 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"`
PercentageLocation pgtype.Float8 `db:"percentage_location" json:"percentage_location"`
CharacterStart pgtype.Int4 `db:"character_start" json:"character_start"`
CharacterEnd pgtype.Int4 `db:"character_end" json:"character_end"`
EpubcfiLocation pgtype.Text `db:"epubcfi_location" json:"epubcfi_location"`
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
ParagraphReference pgtype.Int4 `db:"paragraph_reference" json:"paragraph_reference"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
}
func (q *Queries) CreateMediaNoteFull(ctx context.Context, arg CreateMediaNoteFullParams) (MediaNotes, error) {
row := q.db.QueryRow(ctx, CreateMediaNoteFull,
arg.MediaItemID,
arg.UserID,
arg.Content,
arg.Position,
arg.PercentageLocation,
arg.CharacterStart,
arg.CharacterEnd,
arg.EpubcfiLocation,
arg.ChapterReference,
arg.ParagraphReference,
arg.DedupKey,
arg.LastModifiedAt,
arg.LastModifiedSource,
arg.DeviceSyncData,
)
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const CreateMediaRating = `-- name: CreateMediaRating :one
INSERT INTO media_ratings (media_item_id, user_id, rating)
VALUES ($1, $2, $3)
ON CONFLICT (media_item_id, user_id)
DO UPDATE SET
rating = EXCLUDED.rating,
updated_at = NOW()
RETURNING id, media_item_id, user_id, rating, created_at, updated_at
`
type CreateMediaRatingParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Rating int32 `db:"rating" json:"rating"`
}
func (q *Queries) CreateMediaRating(ctx context.Context, arg CreateMediaRatingParams) (MediaRatings, error) {
row := q.db.QueryRow(ctx, CreateMediaRating, arg.MediaItemID, arg.UserID, arg.Rating)
var i MediaRatings
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.Rating,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateOpdsToken = `-- name: CreateOpdsToken :one
INSERT INTO opds_tokens (device_id, token, token_type, expires_at)
VALUES ($1, $2, $3, $4)
RETURNING id, device_id, token, token_type, expires_at, created_at
`
type CreateOpdsTokenParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
Token string `db:"token" json:"token"`
TokenType pgtype.Text `db:"token_type" json:"token_type"`
ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
}
// OPDS TOKENS QUERIES
// Create OPDS token
func (q *Queries) CreateOpdsToken(ctx context.Context, arg CreateOpdsTokenParams) (OpdsTokens, error) {
row := q.db.QueryRow(ctx, CreateOpdsToken,
arg.DeviceID,
arg.Token,
arg.TokenType,
arg.ExpiresAt,
)
var i OpdsTokens
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.Token,
&i.TokenType,
&i.ExpiresAt,
&i.CreatedAt,
)
return i, err
}
const CreateOrUpdateKoboEntitlement = `-- name: CreateOrUpdateKoboEntitlement :one
INSERT INTO kobo_entitlements (device_id, media_item_id, entitlement_id, content_id, revision_number, purchase_date, kobo_metadata)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (device_id, entitlement_id)
DO UPDATE SET
content_id = EXCLUDED.content_id,
revision_number = EXCLUDED.revision_number,
purchase_date = COALESCE(EXCLUDED.purchase_date, kobo_entitlements.purchase_date),
book_status = 'installed',
sync_status = 'synced',
kobo_metadata = EXCLUDED.kobo_metadata,
updated_at = NOW()
RETURNING id, device_id, media_item_id, entitlement_id, content_id, revision_number, purchase_date, accession_date, book_status, sync_status, kobo_metadata, created_at, updated_at
`
type CreateOrUpdateKoboEntitlementParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
ContentID string `db:"content_id" json:"content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
}
// ============================================
// KOBO ENTITLEMENT QUERIES
// ============================================
func (q *Queries) CreateOrUpdateKoboEntitlement(ctx context.Context, arg CreateOrUpdateKoboEntitlementParams) (KoboEntitlements, error) {
row := q.db.QueryRow(ctx, CreateOrUpdateKoboEntitlement,
arg.DeviceID,
arg.MediaItemID,
arg.EntitlementID,
arg.ContentID,
arg.RevisionNumber,
arg.PurchaseDate,
arg.KoboMetadata,
)
var i KoboEntitlements
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.EntitlementID,
&i.ContentID,
&i.RevisionNumber,
&i.PurchaseDate,
&i.AccessionDate,
&i.BookStatus,
&i.SyncStatus,
&i.KoboMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateProcessingIssue = `-- name: CreateProcessingIssue :one
INSERT INTO processing_issues (media_item_id, library_id, issue_type, issue_description, severity)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (media_item_id, issue_type)
DO UPDATE SET issue_description = EXCLUDED.issue_description,
severity = EXCLUDED.severity,
resolved = false,
resolved_at = NULL
RETURNING id, media_item_id, library_id, issue_type, issue_description, severity, resolved, resolved_at, created_at
`
type CreateProcessingIssueParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
IssueType string `db:"issue_type" json:"issue_type"`
IssueDescription string `db:"issue_description" json:"issue_description"`
Severity string `db:"severity" json:"severity"`
}
// ============================================================================
// PROCESSING ISSUES QUERIES
// ============================================================================
func (q *Queries) CreateProcessingIssue(ctx context.Context, arg CreateProcessingIssueParams) (ProcessingIssues, error) {
row := q.db.QueryRow(ctx, CreateProcessingIssue,
arg.MediaItemID,
arg.LibraryID,
arg.IssueType,
arg.IssueDescription,
arg.Severity,
)
var i ProcessingIssues
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.LibraryID,
&i.IssueType,
&i.IssueDescription,
&i.Severity,
&i.Resolved,
&i.ResolvedAt,
&i.CreatedAt,
)
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 CreateReadingSpeed = `-- name: CreateReadingSpeed :one
INSERT INTO reading_speed (user_id, media_item_id, pages_per_minute, pages_read, total_reading_minutes, last_read_at)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, user_id, media_item_id, words_per_minute, pages_per_minute, pages_read, total_reading_minutes, last_read_at, updated_at
`
type CreateReadingSpeedParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PagesPerMinute pgtype.Float4 `db:"pages_per_minute" json:"pages_per_minute"`
PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"`
TotalReadingMinutes pgtype.Float4 `db:"total_reading_minutes" json:"total_reading_minutes"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
}
func (q *Queries) CreateReadingSpeed(ctx context.Context, arg CreateReadingSpeedParams) (ReadingSpeed, error) {
row := q.db.QueryRow(ctx, CreateReadingSpeed,
arg.UserID,
arg.MediaItemID,
arg.PagesPerMinute,
arg.PagesRead,
arg.TotalReadingMinutes,
arg.LastReadAt,
)
var i ReadingSpeed
err := row.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.WordsPerMinute,
&i.PagesPerMinute,
&i.PagesRead,
&i.TotalReadingMinutes,
&i.LastReadAt,
&i.UpdatedAt,
)
return i, err
}
const CreateRefreshToken = `-- name: CreateRefreshToken :one
INSERT INTO refresh_tokens (user_id, token, expires_at)
VALUES ($1, $2, $3)
RETURNING id, user_id, token, expires_at, created_at, revoked_at
`
type CreateRefreshTokenParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Token pgtype.UUID `db:"token" json:"token"`
ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
}
// Refresh Tokens queries
func (q *Queries) CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshTokens, error) {
row := q.db.QueryRow(ctx, CreateRefreshToken, arg.UserID, arg.Token, arg.ExpiresAt)
var i RefreshTokens
err := row.Scan(
&i.ID,
&i.UserID,
&i.Token,
&i.ExpiresAt,
&i.CreatedAt,
&i.RevokedAt,
)
return i, err
}
const CreateSavedFilter = `-- name: CreateSavedFilter :one
INSERT INTO saved_filters (user_id, name, resource_type, filters)
VALUES ($1, $2, $3, $4)
RETURNING id, user_id, name, resource_type, filters, created_at, updated_at
`
type CreateSavedFilterParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
ResourceType string `db:"resource_type" json:"resource_type"`
Filters []byte `db:"filters" json:"filters"`
}
func (q *Queries) CreateSavedFilter(ctx context.Context, arg CreateSavedFilterParams) (SavedFilters, error) {
row := q.db.QueryRow(ctx, CreateSavedFilter,
arg.UserID,
arg.Name,
arg.ResourceType,
arg.Filters,
)
var i SavedFilters
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.ResourceType,
&i.Filters,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateSyncConflict = `-- name: CreateSyncConflict :one
INSERT INTO sync_conflicts (media_item_id, user_id, conflict_type, conflict_data)
VALUES ($1, $2, $3, $4)
RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at
`
type CreateSyncConflictParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
ConflictType string `db:"conflict_type" json:"conflict_type"`
ConflictData []byte `db:"conflict_data" json:"conflict_data"`
}
// Conflict Resolution
func (q *Queries) CreateSyncConflict(ctx context.Context, arg CreateSyncConflictParams) (SyncConflicts, error) {
row := q.db.QueryRow(ctx, CreateSyncConflict,
arg.MediaItemID,
arg.UserID,
arg.ConflictType,
arg.ConflictData,
)
var i SyncConflicts
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.ConflictType,
&i.ConflictData,
&i.ResolutionStatus,
&i.ResolutionData,
&i.ResolvedBy,
&i.ResolvedAt,
&i.CreatedAt,
)
return i, err
}
const CreateSyncHistoryEntry = `-- name: CreateSyncHistoryEntry :one
INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, status)
VALUES ($1, $2, 'koreader_progress', $3, 5, 'completed')
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`
type CreateSyncHistoryEntryParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
SyncData []byte `db:"sync_data" json:"sync_data"`
}
func (q *Queries) CreateSyncHistoryEntry(ctx context.Context, arg CreateSyncHistoryEntryParams) (SyncQueue, error) {
row := q.db.QueryRow(ctx, CreateSyncHistoryEntry, arg.DeviceID, arg.MediaItemID, arg.SyncData)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const CreateSyncQueueItem = `-- name: CreateSyncQueueItem :one
INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, max_attempts, status)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`
type CreateSyncQueueItemParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
SyncType string `db:"sync_type" json:"sync_type"`
SyncData []byte `db:"sync_data" json:"sync_data"`
Priority pgtype.Int4 `db:"priority" json:"priority"`
MaxAttempts pgtype.Int4 `db:"max_attempts" json:"max_attempts"`
Status pgtype.Text `db:"status" json:"status"`
}
// Sync Queue Management
func (q *Queries) CreateSyncQueueItem(ctx context.Context, arg CreateSyncQueueItemParams) (SyncQueue, error) {
row := q.db.QueryRow(ctx, CreateSyncQueueItem,
arg.DeviceID,
arg.MediaItemID,
arg.SyncType,
arg.SyncData,
arg.Priority,
arg.MaxAttempts,
arg.Status,
)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const CreateSystemCollection = `-- name: CreateSystemCollection :one
INSERT INTO collections (user_id, name, description, icon, color, show_on_dashboard, query_type, priority, is_system_collection, auto_assign_rules)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true, 'null'::jsonb)
RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at
`
type CreateSystemCollectionParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
Icon pgtype.Text `db:"icon" json:"icon"`
Color pgtype.Text `db:"color" json:"color"`
ShowOnDashboard pgtype.Bool `db:"show_on_dashboard" json:"show_on_dashboard"`
QueryType pgtype.Text `db:"query_type" json:"query_type"`
Priority pgtype.Int4 `db:"priority" json:"priority"`
}
func (q *Queries) CreateSystemCollection(ctx context.Context, arg CreateSystemCollectionParams) (Collections, error) {
row := q.db.QueryRow(ctx, CreateSystemCollection,
arg.UserID,
arg.Name,
arg.Description,
arg.Icon,
arg.Color,
arg.ShowOnDashboard,
arg.QueryType,
arg.Priority,
)
var i Collections
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
)
return i, err
}
const CreateUnlinkedBook = `-- name: CreateUnlinkedBook :one
INSERT INTO unlinked_books (device_id, content_id, file_path, title, author, confidence_score)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at
`
type CreateUnlinkedBookParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ContentID string `db:"content_id" json:"content_id"`
FilePath pgtype.Text `db:"file_path" json:"file_path"`
Title pgtype.Text `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}
// ============================================
// ENHANCED KOBO SYNC
// ============================================
// Create unlinked book entry
func (q *Queries) CreateUnlinkedBook(ctx context.Context, arg CreateUnlinkedBookParams) (UnlinkedBooks, error) {
row := q.db.QueryRow(ctx, CreateUnlinkedBook,
arg.DeviceID,
arg.ContentID,
arg.FilePath,
arg.Title,
arg.Author,
arg.ConfidenceScore,
)
var i UnlinkedBooks
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
)
return i, err
}
const CreateUser = `-- name: CreateUser :one
INSERT INTO users (email, username, password_hash, first_name, last_name, theme, role)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, email, username, theme, first_name, last_name, role, created_at, updated_at
`
type CreateUserParams struct {
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
PasswordHash string `db:"password_hash" json:"password_hash"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Theme pgtype.Text `db:"theme" json:"theme"`
Role string `db:"role" json:"role"`
}
type CreateUserRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) {
row := q.db.QueryRow(ctx, CreateUser,
arg.Email,
arg.Username,
arg.PasswordHash,
arg.FirstName,
arg.LastName,
arg.Theme,
arg.Role,
)
var i CreateUserRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const DeleteCollection = `-- name: DeleteCollection :exec
DELETE FROM collections WHERE id = $1
`
// Delete collection
func (q *Queries) DeleteCollection(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteCollection, id)
return err
}
const DeleteDevice = `-- name: DeleteDevice :exec
DELETE FROM devices WHERE id = $1
`
func (q *Queries) DeleteDevice(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteDevice, id)
return err
}
const DeleteDeviceByToken = `-- name: DeleteDeviceByToken :exec
DELETE FROM devices WHERE auth_token = $1
`
func (q *Queries) DeleteDeviceByToken(ctx context.Context, authToken string) error {
_, err := q.db.Exec(ctx, DeleteDeviceByToken, authToken)
return err
}
const DeleteDeviceCatalog = `-- name: DeleteDeviceCatalog :exec
DELETE FROM device_catalogs WHERE id = $1
`
// Delete device catalog entry
func (q *Queries) DeleteDeviceCatalog(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteDeviceCatalog, id)
return err
}
const DeleteDeviceFileAlias = `-- name: DeleteDeviceFileAlias :exec
DELETE FROM device_file_aliases WHERE id = $1
`
// Delete device file alias
func (q *Queries) DeleteDeviceFileAlias(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteDeviceFileAlias, id)
return err
}
const DeleteDeviceShelfMapping = `-- name: DeleteDeviceShelfMapping :exec
DELETE FROM device_shelf_mappings WHERE id = $1
`
// Delete device shelf mapping
func (q *Queries) DeleteDeviceShelfMapping(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteDeviceShelfMapping, id)
return err
}
const DeleteKoboEntitlement = `-- name: DeleteKoboEntitlement :exec
DELETE FROM kobo_entitlements WHERE device_id = $1 AND entitlement_id = $2
`
type DeleteKoboEntitlementParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
}
func (q *Queries) DeleteKoboEntitlement(ctx context.Context, arg DeleteKoboEntitlementParams) error {
_, err := q.db.Exec(ctx, DeleteKoboEntitlement, arg.DeviceID, arg.EntitlementID)
return err
}
const DeleteLibrary = `-- name: DeleteLibrary :exec
DELETE FROM libraries WHERE id = $1
`
func (q *Queries) DeleteLibrary(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteLibrary, id)
return err
}
const DeleteLibraryFolder = `-- name: DeleteLibraryFolder :one
DELETE FROM library_folders WHERE library_id = $1 AND folder_path = $2 RETURNING id, library_id, folder_path, created_at
`
type DeleteLibraryFolderParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
FolderPath string `db:"folder_path" json:"folder_path"`
}
func (q *Queries) DeleteLibraryFolder(ctx context.Context, arg DeleteLibraryFolderParams) (LibraryFolders, error) {
row := q.db.QueryRow(ctx, DeleteLibraryFolder, arg.LibraryID, arg.FolderPath)
var i LibraryFolders
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.FolderPath,
&i.CreatedAt,
)
return i, err
}
const DeleteMediaBookmark = `-- name: DeleteMediaBookmark :exec
DELETE FROM media_bookmarks
WHERE id = $1
`
func (q *Queries) DeleteMediaBookmark(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteMediaBookmark, id)
return err
}
const DeleteMediaHighlight = `-- name: DeleteMediaHighlight :exec
DELETE FROM media_highlights WHERE id = $1
`
func (q *Queries) DeleteMediaHighlight(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteMediaHighlight, id)
return err
}
const DeleteMediaItem = `-- name: DeleteMediaItem :exec
DELETE FROM media_items WHERE id = $1
`
func (q *Queries) DeleteMediaItem(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteMediaItem, id)
return err
}
const DeleteMediaItemFormat = `-- name: DeleteMediaItemFormat :exec
DELETE FROM media_item_formats WHERE id = $1
`
// Delete media item format
func (q *Queries) DeleteMediaItemFormat(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteMediaItemFormat, id)
return err
}
const DeleteMediaNote = `-- name: DeleteMediaNote :exec
DELETE FROM media_notes WHERE id = $1
`
func (q *Queries) DeleteMediaNote(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteMediaNote, id)
return err
}
const DeleteMediaRating = `-- name: DeleteMediaRating :exec
DELETE FROM media_ratings WHERE media_item_id = $1 AND user_id = $2
`
type DeleteMediaRatingParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) DeleteMediaRating(ctx context.Context, arg DeleteMediaRatingParams) error {
_, err := q.db.Exec(ctx, DeleteMediaRating, arg.MediaItemID, arg.UserID)
return err
}
const DeleteProcessingIssue = `-- name: DeleteProcessingIssue :one
DELETE FROM processing_issues
WHERE id = $1
RETURNING id, media_item_id, library_id, issue_type, issue_description, severity, resolved, resolved_at, created_at
`
func (q *Queries) DeleteProcessingIssue(ctx context.Context, id pgtype.UUID) (ProcessingIssues, error) {
row := q.db.QueryRow(ctx, DeleteProcessingIssue, id)
var i ProcessingIssues
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.LibraryID,
&i.IssueType,
&i.IssueDescription,
&i.Severity,
&i.Resolved,
&i.ResolvedAt,
&i.CreatedAt,
)
return i, 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 DeleteSavedFilter = `-- name: DeleteSavedFilter :one
DELETE FROM saved_filters
WHERE id = $1 AND user_id = $2
RETURNING id, user_id, name, resource_type, filters, created_at, updated_at
`
type DeleteSavedFilterParams struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) DeleteSavedFilter(ctx context.Context, arg DeleteSavedFilterParams) (SavedFilters, error) {
row := q.db.QueryRow(ctx, DeleteSavedFilter, arg.ID, arg.UserID)
var i SavedFilters
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.ResourceType,
&i.Filters,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const DeleteSyncConflict = `-- name: DeleteSyncConflict :exec
DELETE FROM sync_conflicts WHERE id = $1
`
func (q *Queries) DeleteSyncConflict(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteSyncConflict, id)
return err
}
const DeleteSyncQueueItem = `-- name: DeleteSyncQueueItem :exec
DELETE FROM sync_queue WHERE id = $1
`
func (q *Queries) DeleteSyncQueueItem(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteSyncQueueItem, id)
return err
}
const DeleteSystemConfig = `-- name: DeleteSystemConfig :exec
DELETE FROM system_config WHERE key = $1
`
// Delete system config
func (q *Queries) DeleteSystemConfig(ctx context.Context, key string) error {
_, err := q.db.Exec(ctx, DeleteSystemConfig, key)
return err
}
const DeleteUnlinkedBook = `-- name: DeleteUnlinkedBook :exec
DELETE FROM unlinked_books WHERE id = $1
`
// Delete unlinked book
func (q *Queries) DeleteUnlinkedBook(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteUnlinkedBook, id)
return err
}
const DeleteUser = `-- name: DeleteUser :exec
DELETE FROM users WHERE id = $1
`
func (q *Queries) DeleteUser(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteUser, id)
return err
}
const DeleteUserSystemCollection = `-- name: DeleteUserSystemCollection :exec
DELETE FROM collections
WHERE user_id = $1
AND name = $2
AND is_system_collection = true
`
type DeleteUserSystemCollectionParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
}
func (q *Queries) DeleteUserSystemCollection(ctx context.Context, arg DeleteUserSystemCollectionParams) error {
_, err := q.db.Exec(ctx, DeleteUserSystemCollection, arg.UserID, arg.Name)
return err
}
const GenerateKoboEntitlementId = `-- name: GenerateKoboEntitlementId :one
SELECT 'kobo_' || uuid_generate_v4()::TEXT as entitlement_id
`
func (q *Queries) GenerateKoboEntitlementId(ctx context.Context) (interface{}, error) {
row := q.db.QueryRow(ctx, GenerateKoboEntitlementId)
var entitlement_id interface{}
err := row.Scan(&entitlement_id)
return entitlement_id, err
}
const GetActiveAnnotationsForBook = `-- name: GetActiveAnnotationsForBook :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,
mh.note_text,
mh.dedup_key,
mh.last_modified_at,
mh.last_modified_source
FROM media_highlights mh
WHERE mh.media_item_id = $1 AND mh.user_id = $2 AND mh.deleted = FALSE
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,
NULL as note_text,
mn.dedup_key,
mn.last_modified_at,
mn.last_modified_source
FROM media_notes mn
WHERE mn.media_item_id = $1 AND mn.user_id = $2 AND mn.deleted = FALSE
ORDER BY created_at DESC
`
type GetActiveAnnotationsForBookParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
type GetActiveAnnotationsForBookRow 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"`
NoteText pgtype.Text `db:"note_text" json:"note_text"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
}
// ============================================
// ANNOTATION SERVE QUERIES
// ============================================
func (q *Queries) GetActiveAnnotationsForBook(ctx context.Context, arg GetActiveAnnotationsForBookParams) ([]GetActiveAnnotationsForBookRow, error) {
rows, err := q.db.Query(ctx, GetActiveAnnotationsForBook, arg.MediaItemID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetActiveAnnotationsForBookRow{}
for rows.Next() {
var i GetActiveAnnotationsForBookRow
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,
&i.NoteText,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllSystemConfig = `-- name: GetAllSystemConfig :many
SELECT key, value, updated_at, updated_by FROM system_config ORDER BY key
`
// Get all system config
func (q *Queries) GetAllSystemConfig(ctx context.Context) ([]SystemConfig, error) {
rows, err := q.db.Query(ctx, GetAllSystemConfig)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SystemConfig{}
for rows.Next() {
var i SystemConfig
if err := rows.Scan(
&i.Key,
&i.Value,
&i.UpdatedAt,
&i.UpdatedBy,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllSystemSettings = `-- name: GetAllSystemSettings :many
SELECT setting_key, setting_value, description FROM system_settings ORDER BY setting_key
`
type GetAllSystemSettingsRow struct {
SettingKey string `db:"setting_key" json:"setting_key"`
SettingValue string `db:"setting_value" json:"setting_value"`
Description pgtype.Text `db:"description" json:"description"`
}
func (q *Queries) GetAllSystemSettings(ctx context.Context) ([]GetAllSystemSettingsRow, error) {
rows, err := q.db.Query(ctx, GetAllSystemSettings)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetAllSystemSettingsRow{}
for rows.Next() {
var i GetAllSystemSettingsRow
if err := rows.Scan(&i.SettingKey, &i.SettingValue, &i.Description); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllSystemSettingsFull = `-- name: GetAllSystemSettingsFull :many
SELECT id, setting_key, setting_value, description, updated_at, setting_type, min_value, max_value, requires_restart, category FROM system_settings ORDER BY category, setting_key
`
func (q *Queries) GetAllSystemSettingsFull(ctx context.Context) ([]SystemSettings, error) {
rows, err := q.db.Query(ctx, GetAllSystemSettingsFull)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SystemSettings{}
for rows.Next() {
var i SystemSettings
if err := rows.Scan(
&i.ID,
&i.SettingKey,
&i.SettingValue,
&i.Description,
&i.UpdatedAt,
&i.SettingType,
&i.MinValue,
&i.MaxValue,
&i.RequiresRestart,
&i.Category,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAnnotationsForBook = `-- name: GetAnnotationsForBook :many
SELECT
mh.id,
mh.selection_text,
mh.start_position,
mh.end_position,
mh.color,
mh.created_at,
mh.updated_at,
'highlight' as annotation_type,
mh.percentage_start,
mh.percentage_end,
mh.epubcfi_start,
mh.epubcfi_end
FROM media_highlights mh
WHERE mh.media_item_id = $1 AND mh.user_id = $2 AND COALESCE(mh.deleted, FALSE) = FALSE
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 AND COALESCE(mn.deleted, FALSE) = FALSE
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 GetBooksByTag = `-- name: GetBooksByTag :many
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items
WHERE library_id = $1 AND tags @> ARRAY[$2::text]
ORDER BY title ASC
`
type GetBooksByTagParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Column2 string `db:"column_2" json:"column_2"`
}
func (q *Queries) GetBooksByTag(ctx context.Context, arg GetBooksByTagParams) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetBooksByTag, arg.LibraryID, arg.Column2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCollection = `-- name: GetCollection :one
SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections WHERE id = $1
`
// Get collection
func (q *Queries) GetCollection(ctx context.Context, id pgtype.UUID) (Collections, error) {
row := q.db.QueryRow(ctx, GetCollection, id)
var i Collections
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
)
return i, err
}
const GetCollectionItems = `-- name: GetCollectionItems :many
SELECT ci.id, ci.collection_id, ci.media_item_id, ci.added_at, ci.added_by_user_id, ci.excluded, mi.title, mi.author, mi.cover_image_path, mi.library_id
FROM collection_items ci
JOIN media_items mi ON ci.media_item_id = mi.id
WHERE ci.collection_id = $1
ORDER BY ci.added_at DESC
`
type GetCollectionItemsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"`
AddedByUserID pgtype.UUID `db:"added_by_user_id" json:"added_by_user_id"`
Excluded pgtype.Bool `db:"excluded" json:"excluded"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
// Get collection items
func (q *Queries) GetCollectionItems(ctx context.Context, collectionID pgtype.UUID) ([]GetCollectionItemsRow, error) {
rows, err := q.db.Query(ctx, GetCollectionItems, collectionID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetCollectionItemsRow{}
for rows.Next() {
var i GetCollectionItemsRow
if err := rows.Scan(
&i.ID,
&i.CollectionID,
&i.MediaItemID,
&i.AddedAt,
&i.AddedByUserID,
&i.Excluded,
&i.Title,
&i.Author,
&i.CoverImagePath,
&i.LibraryID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCollectionItemsForDashboard = `-- name: GetCollectionItemsForDashboard :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, ci.excluded FROM media_items mi
INNER JOIN collection_items ci ON ci.media_item_id = mi.id
WHERE ci.collection_id = $1
AND ($2::uuid IS NULL OR mi.library_id = $2::uuid)
ORDER BY ci.added_at DESC
LIMIT $3
`
type GetCollectionItemsForDashboardParams struct {
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type GetCollectionItemsForDashboardRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
Excluded pgtype.Bool `db:"excluded" json:"excluded"`
}
func (q *Queries) GetCollectionItemsForDashboard(ctx context.Context, arg GetCollectionItemsForDashboardParams) ([]GetCollectionItemsForDashboardRow, error) {
rows, err := q.db.Query(ctx, GetCollectionItemsForDashboard, arg.CollectionID, arg.LibraryID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetCollectionItemsForDashboardRow{}
for rows.Next() {
var i GetCollectionItemsForDashboardRow
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.Excluded,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCollectionWithBookCount = `-- name: GetCollectionWithBookCount :one
SELECT
c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at,
COUNT(ci.id) as book_count
FROM collections c
LEFT JOIN collection_items ci ON c.id = ci.collection_id
WHERE c.id = $1
GROUP BY c.id
`
type GetCollectionWithBookCountRow struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
Color pgtype.Text `db:"color" json:"color"`
Icon pgtype.Text `db:"icon" json:"icon"`
AutoAssignRules []byte `db:"auto_assign_rules" json:"auto_assign_rules"`
ViewSettings []byte `db:"view_settings" json:"view_settings"`
ShowOnDashboard pgtype.Bool `db:"show_on_dashboard" json:"show_on_dashboard"`
QueryType pgtype.Text `db:"query_type" json:"query_type"`
Priority pgtype.Int4 `db:"priority" json:"priority"`
IsSystemCollection pgtype.Bool `db:"is_system_collection" json:"is_system_collection"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
BookCount int64 `db:"book_count" json:"book_count"`
}
// Get collection with book count
func (q *Queries) GetCollectionWithBookCount(ctx context.Context, id pgtype.UUID) (GetCollectionWithBookCountRow, error) {
row := q.db.QueryRow(ctx, GetCollectionWithBookCount, id)
var i GetCollectionWithBookCountRow
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
&i.BookCount,
)
return i, err
}
const GetCollectionsByUser = `-- name: GetCollectionsByUser :many
SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections WHERE user_id = $1 ORDER BY created_at DESC
`
// Get collections by user
func (q *Queries) GetCollectionsByUser(ctx context.Context, userID pgtype.UUID) ([]Collections, error) {
rows, err := q.db.Query(ctx, GetCollectionsByUser, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Collections{}
for rows.Next() {
var i Collections
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCollectionsForBook = `-- name: GetCollectionsForBook :many
SELECT c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at
FROM collections c
JOIN collection_items ci ON c.id = ci.collection_id
WHERE ci.media_item_id = $1
`
// Get collections for book
func (q *Queries) GetCollectionsForBook(ctx context.Context, mediaItemID pgtype.UUID) ([]Collections, error) {
rows, err := q.db.Query(ctx, GetCollectionsForBook, mediaItemID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Collections{}
for rows.Next() {
var i Collections
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetContinueReadingItems = `-- name: GetContinueReadingItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
INNER JOIN (
SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at
FROM reading_progress
WHERE user_id = $1
AND percentage > 0
AND percentage < 1
ORDER BY media_item_id, last_read_at DESC
) rp ON rp.media_item_id = mi.id
WHERE ($2::uuid IS NULL OR mi.library_id = $2::uuid)
ORDER BY rp.last_read_at DESC
LIMIT $3
`
type GetContinueReadingItemsParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
// Smart section queries (for system collections)
func (q *Queries) GetContinueReadingItems(ctx context.Context, arg GetContinueReadingItemsParams) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetContinueReadingItems, arg.UserID, arg.LibraryID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetContinueSeriesItems = `-- name: GetContinueSeriesItems :many
WITH user_series_progress AS (
SELECT mi.series,
MAX(mi.series_number) as max_read_number,
MAX(rp.last_read_at) as last_read_at
FROM reading_progress rp
JOIN media_items mi ON mi.id = rp.media_item_id
WHERE rp.user_id = $2
AND rp.percentage > 0
AND mi.series IS NOT NULL AND mi.series != ''
AND ($3::uuid IS NULL OR mi.library_id = $3::uuid)
GROUP BY mi.series
),
next_books AS (
SELECT DISTINCT ON (mi.series) mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence,
usp.last_read_at
FROM media_items mi
JOIN user_series_progress usp ON mi.series = usp.series
WHERE ($3::uuid IS NULL OR mi.library_id = $3::uuid)
AND (mi.series_number > usp.max_read_number OR usp.max_read_number IS NULL)
ORDER BY mi.series, mi.series_number ASC NULLS LAST
)
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence, last_read_at FROM next_books
ORDER BY last_read_at DESC NULLS LAST
LIMIT $1
`
type GetContinueSeriesItemsParams struct {
Limit pgtype.Int4 `db:"limit" json:"limit"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
type GetContinueSeriesItemsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
LastReadAt interface{} `db:"last_read_at" json:"last_read_at"`
}
func (q *Queries) GetContinueSeriesItems(ctx context.Context, arg GetContinueSeriesItemsParams) ([]GetContinueSeriesItemsRow, error) {
rows, err := q.db.Query(ctx, GetContinueSeriesItems, arg.Limit, arg.UserID, arg.LibraryID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetContinueSeriesItemsRow{}
for rows.Next() {
var i GetContinueSeriesItemsRow
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.LastReadAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetDashboardPreferences = `-- name: GetDashboardPreferences :one
SELECT id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at FROM user_dashboard_preferences
WHERE user_id = $1 AND ($2::uuid IS NULL OR library_id = $2::uuid)
`
type GetDashboardPreferencesParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
// ============================================
// CAROUSEL-STYLE DASHBOARD
// ============================================
// Dashboard preferences queries
func (q *Queries) GetDashboardPreferences(ctx context.Context, arg GetDashboardPreferencesParams) (UserDashboardPreferences, error) {
row := q.db.QueryRow(ctx, GetDashboardPreferences, arg.UserID, arg.LibraryID)
var i UserDashboardPreferences
err := row.Scan(
&i.ID,
&i.UserID,
&i.LibraryID,
&i.HiddenCollections,
&i.CollectionOrder,
&i.ItemsPerSection,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetDevice = `-- name: GetDevice :one
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE id = $1
`
func (q *Queries) GetDevice(ctx context.Context, id pgtype.UUID) (Devices, error) {
row := q.db.QueryRow(ctx, GetDevice, id)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetDeviceByAuthToken = `-- name: GetDeviceByAuthToken :one
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE auth_token = $1
`
func (q *Queries) GetDeviceByAuthToken(ctx context.Context, authToken string) (Devices, error) {
row := q.db.QueryRow(ctx, GetDeviceByAuthToken, authToken)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetDeviceByIdentifier = `-- name: GetDeviceByIdentifier :one
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_identifier = $1
`
func (q *Queries) GetDeviceByIdentifier(ctx context.Context, deviceIdentifier string) (Devices, error) {
row := q.db.QueryRow(ctx, GetDeviceByIdentifier, deviceIdentifier)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetDeviceCatalogByBookhoardUUID = `-- name: GetDeviceCatalogByBookhoardUUID :one
SELECT id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method FROM device_catalogs WHERE device_id = $1 AND bookhoard_uuid = $2
`
type GetDeviceCatalogByBookhoardUUIDParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"`
}
// Get device catalog by Bookhoard UUID
func (q *Queries) GetDeviceCatalogByBookhoardUUID(ctx context.Context, arg GetDeviceCatalogByBookhoardUUIDParams) (DeviceCatalogs, error) {
row := q.db.QueryRow(ctx, GetDeviceCatalogByBookhoardUUID, arg.DeviceID, arg.BookhoardUuid)
var i DeviceCatalogs
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.BookhoardUuid,
&i.KoboContentID,
&i.ContentIDType,
&i.Available,
&i.DeliveryDate,
&i.DeliveryMethod,
)
return i, err
}
const GetDeviceCatalogByKoboContentId = `-- name: GetDeviceCatalogByKoboContentId :one
SELECT id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method FROM device_catalogs WHERE kobo_content_id = $1
`
// Get device catalog by Kobo ContentId
func (q *Queries) GetDeviceCatalogByKoboContentId(ctx context.Context, koboContentID string) (DeviceCatalogs, error) {
row := q.db.QueryRow(ctx, GetDeviceCatalogByKoboContentId, koboContentID)
var i DeviceCatalogs
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.BookhoardUuid,
&i.KoboContentID,
&i.ContentIDType,
&i.Available,
&i.DeliveryDate,
&i.DeliveryMethod,
)
return i, err
}
const GetDeviceCatalogEntries = `-- name: GetDeviceCatalogEntries :many
SELECT dc.id, dc.device_id, dc.media_item_id, dc.bookhoard_uuid, dc.kobo_content_id, dc.content_id_type, dc.available, dc.delivery_date, dc.delivery_method, mi.title, mi.author
FROM device_catalogs dc
JOIN media_items mi ON dc.media_item_id = mi.id
WHERE dc.device_id = $1 AND dc.available = true
ORDER BY dc.delivery_date DESC
`
type GetDeviceCatalogEntriesRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"`
KoboContentID string `db:"kobo_content_id" json:"kobo_content_id"`
ContentIDType pgtype.Text `db:"content_id_type" json:"content_id_type"`
Available pgtype.Bool `db:"available" json:"available"`
DeliveryDate pgtype.Timestamptz `db:"delivery_date" json:"delivery_date"`
DeliveryMethod pgtype.Text `db:"delivery_method" json:"delivery_method"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
}
// Get device catalog entries
func (q *Queries) GetDeviceCatalogEntries(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceCatalogEntriesRow, error) {
rows, err := q.db.Query(ctx, GetDeviceCatalogEntries, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetDeviceCatalogEntriesRow{}
for rows.Next() {
var i GetDeviceCatalogEntriesRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.BookhoardUuid,
&i.KoboContentID,
&i.ContentIDType,
&i.Available,
&i.DeliveryDate,
&i.DeliveryMethod,
&i.Title,
&i.Author,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetDeviceFileAlias = `-- name: GetDeviceFileAlias :one
SELECT id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at FROM device_file_aliases WHERE device_id = $1 AND file_path = $2
`
type GetDeviceFileAliasParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
FilePath string `db:"file_path" json:"file_path"`
}
// Get device file alias
func (q *Queries) GetDeviceFileAlias(ctx context.Context, arg GetDeviceFileAliasParams) (DeviceFileAliases, error) {
row := q.db.QueryRow(ctx, GetDeviceFileAlias, arg.DeviceID, arg.FilePath)
var i DeviceFileAliases
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.DeviceID,
&i.FilePath,
&i.FileSha256,
&i.ConfidenceScore,
&i.LastSeenAt,
)
return i, err
}
const GetDeviceFileAliasBySHA256 = `-- name: GetDeviceFileAliasBySHA256 :one
SELECT dfa.id, dfa.media_item_id, dfa.device_id, dfa.file_path, dfa.file_sha256, dfa.confidence_score, dfa.last_seen_at, mi.title, mi.author
FROM device_file_aliases dfa
JOIN media_items mi ON dfa.media_item_id = mi.id
WHERE dfa.file_sha256 = $1
`
type GetDeviceFileAliasBySHA256Row struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
FilePath string `db:"file_path" json:"file_path"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
}
// Get device file alias by SHA-256
func (q *Queries) GetDeviceFileAliasBySHA256(ctx context.Context, fileSha256 pgtype.Text) (GetDeviceFileAliasBySHA256Row, error) {
row := q.db.QueryRow(ctx, GetDeviceFileAliasBySHA256, fileSha256)
var i GetDeviceFileAliasBySHA256Row
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.DeviceID,
&i.FilePath,
&i.FileSha256,
&i.ConfidenceScore,
&i.LastSeenAt,
&i.Title,
&i.Author,
)
return i, err
}
const GetDeviceFileAliasesByDevice = `-- name: GetDeviceFileAliasesByDevice :many
SELECT dfa.id, dfa.media_item_id, dfa.device_id, dfa.file_path, dfa.file_sha256, dfa.confidence_score, dfa.last_seen_at, mi.title, mi.author
FROM device_file_aliases dfa
JOIN media_items mi ON dfa.media_item_id = mi.id
WHERE dfa.device_id = $1
ORDER BY dfa.last_seen_at DESC
`
type GetDeviceFileAliasesByDeviceRow struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
FilePath string `db:"file_path" json:"file_path"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
}
// Get device file aliases by device
func (q *Queries) GetDeviceFileAliasesByDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceFileAliasesByDeviceRow, error) {
rows, err := q.db.Query(ctx, GetDeviceFileAliasesByDevice, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetDeviceFileAliasesByDeviceRow{}
for rows.Next() {
var i GetDeviceFileAliasesByDeviceRow
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.DeviceID,
&i.FilePath,
&i.FileSha256,
&i.ConfidenceScore,
&i.LastSeenAt,
&i.Title,
&i.Author,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetDeviceShelfMapping = `-- name: GetDeviceShelfMapping :one
SELECT id, collection_id, device_id, device_shelf_name, sync_direction, created_at FROM device_shelf_mappings WHERE device_id = $1 AND collection_id = $2
`
type GetDeviceShelfMappingParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
}
// Get device shelf mapping
func (q *Queries) GetDeviceShelfMapping(ctx context.Context, arg GetDeviceShelfMappingParams) (DeviceShelfMappings, error) {
row := q.db.QueryRow(ctx, GetDeviceShelfMapping, arg.DeviceID, arg.CollectionID)
var i DeviceShelfMappings
err := row.Scan(
&i.ID,
&i.CollectionID,
&i.DeviceID,
&i.DeviceShelfName,
&i.SyncDirection,
&i.CreatedAt,
)
return i, err
}
const GetDeviceShelfMappings = `-- name: GetDeviceShelfMappings :many
SELECT dsm.id, dsm.collection_id, dsm.device_id, dsm.device_shelf_name, dsm.sync_direction, dsm.created_at, c.name as collection_name, c.icon as collection_icon
FROM device_shelf_mappings dsm
JOIN collections c ON dsm.collection_id = c.id
WHERE dsm.device_id = $1
`
type GetDeviceShelfMappingsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"`
SyncDirection pgtype.Text `db:"sync_direction" json:"sync_direction"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
CollectionName string `db:"collection_name" json:"collection_name"`
CollectionIcon pgtype.Text `db:"collection_icon" json:"collection_icon"`
}
// Get device shelf mappings
func (q *Queries) GetDeviceShelfMappings(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceShelfMappingsRow, error) {
rows, err := q.db.Query(ctx, GetDeviceShelfMappings, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetDeviceShelfMappingsRow{}
for rows.Next() {
var i GetDeviceShelfMappingsRow
if err := rows.Scan(
&i.ID,
&i.CollectionID,
&i.DeviceID,
&i.DeviceShelfName,
&i.SyncDirection,
&i.CreatedAt,
&i.CollectionName,
&i.CollectionIcon,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetDictionaryEntry = `-- name: GetDictionaryEntry :one
SELECT id, word, definition, part_of_speech, example, etymology, created_at, accessed_at FROM dictionary_cache
WHERE word = $1
`
func (q *Queries) GetDictionaryEntry(ctx context.Context, word string) (DictionaryCache, error) {
row := q.db.QueryRow(ctx, GetDictionaryEntry, word)
var i DictionaryCache
err := row.Scan(
&i.ID,
&i.Word,
&i.Definition,
&i.PartOfSpeech,
&i.Example,
&i.Etymology,
&i.CreatedAt,
&i.AccessedAt,
)
return i, err
}
const GetDistinctSeries = `-- name: GetDistinctSeries :many
SELECT series, COUNT(*) as book_count,
MAX(series_count) as total_in_series,
MAX(created_at) as last_entry_at
FROM media_items
WHERE ($1::uuid IS NULL OR library_id = $1::uuid) AND series IS NOT NULL AND series != ''
GROUP BY series
ORDER BY MAX(created_at) DESC
LIMIT $3 OFFSET $2
`
type GetDistinctSeriesParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type GetDistinctSeriesRow struct {
Series pgtype.Text `db:"series" json:"series"`
BookCount int64 `db:"book_count" json:"book_count"`
TotalInSeries interface{} `db:"total_in_series" json:"total_in_series"`
LastEntryAt interface{} `db:"last_entry_at" json:"last_entry_at"`
}
func (q *Queries) GetDistinctSeries(ctx context.Context, arg GetDistinctSeriesParams) ([]GetDistinctSeriesRow, error) {
rows, err := q.db.Query(ctx, GetDistinctSeries, arg.LibraryID, arg.Offset, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetDistinctSeriesRow{}
for rows.Next() {
var i GetDistinctSeriesRow
if err := rows.Scan(
&i.Series,
&i.BookCount,
&i.TotalInSeries,
&i.LastEntryAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetDistinctSeriesCount = `-- name: GetDistinctSeriesCount :one
SELECT COUNT(DISTINCT series)::int
FROM media_items
WHERE ($1::uuid IS NULL OR library_id = $1::uuid) AND series IS NOT NULL AND series != ''
`
func (q *Queries) GetDistinctSeriesCount(ctx context.Context, libraryID pgtype.UUID) (int32, error) {
row := q.db.QueryRow(ctx, GetDistinctSeriesCount, libraryID)
var column_1 int32
err := row.Scan(&column_1)
return column_1, err
}
const GetFailedSyncQueueItems = `-- name: GetFailedSyncQueueItems :many
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue
WHERE status = 'failed' AND attempts < max_attempts
ORDER BY priority ASC, created_at ASC
LIMIT $1
`
func (q *Queries) GetFailedSyncQueueItems(ctx context.Context, limit int32) ([]SyncQueue, error) {
rows, err := q.db.Query(ctx, GetFailedSyncQueueItems, limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SyncQueue{}
for rows.Next() {
var i SyncQueue
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetFirstAdmin = `-- name: GetFirstAdmin :one
SELECT id FROM users
WHERE role = 'admin'
ORDER BY created_at ASC
LIMIT 1
`
func (q *Queries) GetFirstAdmin(ctx context.Context) (pgtype.UUID, error) {
row := q.db.QueryRow(ctx, GetFirstAdmin)
var id pgtype.UUID
err := row.Scan(&id)
return id, err
}
const GetFirstAdminExclude = `-- name: GetFirstAdminExclude :one
SELECT id, email, username, theme, first_name, last_name, role, max_devices, created_at, updated_at FROM users
WHERE role = 'admin' AND id != $1
ORDER BY created_at ASC
LIMIT 1
`
type GetFirstAdminExcludeRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetFirstAdminExclude(ctx context.Context, id pgtype.UUID) (GetFirstAdminExcludeRow, error) {
row := q.db.QueryRow(ctx, GetFirstAdminExclude, id)
var i GetFirstAdminExcludeRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.MaxDevices,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetKoboEntitlementByContentId = `-- name: GetKoboEntitlementByContentId :one
SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path
FROM kobo_entitlements ke
JOIN media_items mi ON ke.media_item_id = mi.id
WHERE ke.device_id = $1 AND ke.content_id = $2
`
type GetKoboEntitlementByContentIdParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ContentID string `db:"content_id" json:"content_id"`
}
type GetKoboEntitlementByContentIdRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
ContentID string `db:"content_id" json:"content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
AccessionDate pgtype.Timestamptz `db:"accession_date" json:"accession_date"`
BookStatus pgtype.Text `db:"book_status" json:"book_status"`
SyncStatus pgtype.Text `db:"sync_status" json:"sync_status"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
}
func (q *Queries) GetKoboEntitlementByContentId(ctx context.Context, arg GetKoboEntitlementByContentIdParams) (GetKoboEntitlementByContentIdRow, error) {
row := q.db.QueryRow(ctx, GetKoboEntitlementByContentId, arg.DeviceID, arg.ContentID)
var i GetKoboEntitlementByContentIdRow
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.EntitlementID,
&i.ContentID,
&i.RevisionNumber,
&i.PurchaseDate,
&i.AccessionDate,
&i.BookStatus,
&i.SyncStatus,
&i.KoboMetadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.Title,
&i.Author,
&i.FilePath,
)
return i, err
}
const GetKoboEntitlementByEntitlementId = `-- name: GetKoboEntitlementByEntitlementId :one
SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path
FROM kobo_entitlements ke
JOIN media_items mi ON ke.media_item_id = mi.id
WHERE ke.device_id = $1 AND ke.entitlement_id = $2
`
type GetKoboEntitlementByEntitlementIdParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
}
type GetKoboEntitlementByEntitlementIdRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
ContentID string `db:"content_id" json:"content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
AccessionDate pgtype.Timestamptz `db:"accession_date" json:"accession_date"`
BookStatus pgtype.Text `db:"book_status" json:"book_status"`
SyncStatus pgtype.Text `db:"sync_status" json:"sync_status"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
}
func (q *Queries) GetKoboEntitlementByEntitlementId(ctx context.Context, arg GetKoboEntitlementByEntitlementIdParams) (GetKoboEntitlementByEntitlementIdRow, error) {
row := q.db.QueryRow(ctx, GetKoboEntitlementByEntitlementId, arg.DeviceID, arg.EntitlementID)
var i GetKoboEntitlementByEntitlementIdRow
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.EntitlementID,
&i.ContentID,
&i.RevisionNumber,
&i.PurchaseDate,
&i.AccessionDate,
&i.BookStatus,
&i.SyncStatus,
&i.KoboMetadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.Title,
&i.Author,
&i.FilePath,
)
return i, err
}
const GetKoboEntitlementsForDevice = `-- name: GetKoboEntitlementsForDevice :many
SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path
FROM kobo_entitlements ke
JOIN media_items mi ON ke.media_item_id = mi.id
WHERE ke.device_id = $1
ORDER BY ke.accession_date DESC
`
type GetKoboEntitlementsForDeviceRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
ContentID string `db:"content_id" json:"content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
PurchaseDate pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
AccessionDate pgtype.Timestamptz `db:"accession_date" json:"accession_date"`
BookStatus pgtype.Text `db:"book_status" json:"book_status"`
SyncStatus pgtype.Text `db:"sync_status" json:"sync_status"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
}
func (q *Queries) GetKoboEntitlementsForDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboEntitlementsForDeviceRow, error) {
rows, err := q.db.Query(ctx, GetKoboEntitlementsForDevice, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetKoboEntitlementsForDeviceRow{}
for rows.Next() {
var i GetKoboEntitlementsForDeviceRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.EntitlementID,
&i.ContentID,
&i.RevisionNumber,
&i.PurchaseDate,
&i.AccessionDate,
&i.BookStatus,
&i.SyncStatus,
&i.KoboMetadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.Title,
&i.Author,
&i.FilePath,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetKoboShelfBookCount = `-- name: GetKoboShelfBookCount :one
SELECT COUNT(*) as book_count
FROM kobo_shelves
WHERE device_id = $1
`
func (q *Queries) GetKoboShelfBookCount(ctx context.Context, deviceID pgtype.UUID) (int64, error) {
row := q.db.QueryRow(ctx, GetKoboShelfBookCount, deviceID)
var book_count int64
err := row.Scan(&book_count)
return book_count, err
}
const GetKoboShelfBooks = `-- name: GetKoboShelfBooks :many
SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author, mi.file_path, mi.mime_type, mi.entitlement_id, mi.kobo_content_id, mi.revision_number
FROM kobo_shelves ks
JOIN media_items mi ON ks.media_item_id = mi.id
WHERE ks.device_id = $1
ORDER BY ks.shelf_position ASC, ks.added_at ASC
`
type GetKoboShelfBooksRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"`
LastSyncedAt pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
}
func (q *Queries) GetKoboShelfBooks(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboShelfBooksRow, error) {
rows, err := q.db.Query(ctx, GetKoboShelfBooks, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetKoboShelfBooksRow{}
for rows.Next() {
var i GetKoboShelfBooksRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.ShelfName,
&i.ShelfPosition,
&i.AddedAt,
&i.LastSyncedAt,
&i.CollectionID,
&i.PositionInCollection,
&i.Title,
&i.Author,
&i.FilePath,
&i.MimeType,
&i.EntitlementID,
&i.KoboContentID,
&i.RevisionNumber,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetKoboShelfBooksByShelfName = `-- name: GetKoboShelfBooksByShelfName :many
SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author, mi.file_path, mi.mime_type, mi.entitlement_id, mi.kobo_content_id, mi.revision_number
FROM kobo_shelves ks
JOIN media_items mi ON ks.media_item_id = mi.id
WHERE ks.device_id = $1 AND ks.shelf_name = $2
ORDER BY ks.shelf_position ASC, ks.added_at ASC
`
type GetKoboShelfBooksByShelfNameParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
}
type GetKoboShelfBooksByShelfNameRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"`
LastSyncedAt pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
}
func (q *Queries) GetKoboShelfBooksByShelfName(ctx context.Context, arg GetKoboShelfBooksByShelfNameParams) ([]GetKoboShelfBooksByShelfNameRow, error) {
rows, err := q.db.Query(ctx, GetKoboShelfBooksByShelfName, arg.DeviceID, arg.ShelfName)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetKoboShelfBooksByShelfNameRow{}
for rows.Next() {
var i GetKoboShelfBooksByShelfNameRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.ShelfName,
&i.ShelfPosition,
&i.AddedAt,
&i.LastSyncedAt,
&i.CollectionID,
&i.PositionInCollection,
&i.Title,
&i.Author,
&i.FilePath,
&i.MimeType,
&i.EntitlementID,
&i.KoboContentID,
&i.RevisionNumber,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetKoboShelvesByCollection = `-- name: GetKoboShelvesByCollection :many
SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author
FROM kobo_shelves ks
JOIN media_items mi ON ks.media_item_id = mi.id
WHERE ks.device_id = $1 AND ks.collection_id = $2
ORDER BY ks.position_in_collection ASC, ks.shelf_position ASC
`
type GetKoboShelvesByCollectionParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
}
type GetKoboShelvesByCollectionRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
AddedAt pgtype.Timestamptz `db:"added_at" json:"added_at"`
LastSyncedAt pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
}
// Get Kobo shelves by collection
func (q *Queries) GetKoboShelvesByCollection(ctx context.Context, arg GetKoboShelvesByCollectionParams) ([]GetKoboShelvesByCollectionRow, error) {
rows, err := q.db.Query(ctx, GetKoboShelvesByCollection, arg.DeviceID, arg.CollectionID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetKoboShelvesByCollectionRow{}
for rows.Next() {
var i GetKoboShelvesByCollectionRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.ShelfName,
&i.ShelfPosition,
&i.AddedAt,
&i.LastSyncedAt,
&i.CollectionID,
&i.PositionInCollection,
&i.Title,
&i.Author,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetLibrary = `-- name: GetLibrary :one
SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description
FROM libraries l
JOIN library_types lt ON l.library_type_id = lt.id
WHERE l.id = $1
`
type GetLibraryRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
LibraryTypeID pgtype.UUID `db:"library_type_id" json:"library_type_id"`
CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
TypeName string `db:"type_name" json:"type_name"`
TypeDescription pgtype.Text `db:"type_description" json:"type_description"`
}
func (q *Queries) GetLibrary(ctx context.Context, id pgtype.UUID) (GetLibraryRow, error) {
row := q.db.QueryRow(ctx, GetLibrary, id)
var i GetLibraryRow
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.LibraryTypeID,
&i.CreatedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
&i.TypeName,
&i.TypeDescription,
)
return i, err
}
const GetLibraryByFolder = `-- name: GetLibraryByFolder :one
SELECT lf.library_id, l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at FROM library_folders lf
JOIN libraries l ON lf.library_id = l.id
WHERE lf.folder_path = $1
`
type GetLibraryByFolderRow struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
ID pgtype.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
LibraryTypeID pgtype.UUID `db:"library_type_id" json:"library_type_id"`
CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetLibraryByFolder(ctx context.Context, folderPath string) (GetLibraryByFolderRow, error) {
row := q.db.QueryRow(ctx, GetLibraryByFolder, folderPath)
var i GetLibraryByFolderRow
err := row.Scan(
&i.LibraryID,
&i.ID,
&i.Name,
&i.Description,
&i.LibraryTypeID,
&i.CreatedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetLibraryByFolderPathPrefix = `-- name: GetLibraryByFolderPathPrefix :one
SELECT lf.library_id, lf.folder_path, l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at FROM library_folders lf
JOIN libraries l ON lf.library_id = l.id
WHERE $1 LIKE lf.folder_path || '%'
ORDER BY LENGTH(lf.folder_path) DESC
LIMIT 1
`
type GetLibraryByFolderPathPrefixRow struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
FolderPath string `db:"folder_path" json:"folder_path"`
ID pgtype.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
LibraryTypeID pgtype.UUID `db:"library_type_id" json:"library_type_id"`
CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetLibraryByFolderPathPrefix(ctx context.Context, folderPath string) (GetLibraryByFolderPathPrefixRow, error) {
row := q.db.QueryRow(ctx, GetLibraryByFolderPathPrefix, folderPath)
var i GetLibraryByFolderPathPrefixRow
err := row.Scan(
&i.LibraryID,
&i.FolderPath,
&i.ID,
&i.Name,
&i.Description,
&i.LibraryTypeID,
&i.CreatedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetLibraryFolders = `-- name: GetLibraryFolders :many
SELECT id, library_id, folder_path, created_at FROM library_folders WHERE library_id = $1 ORDER BY created_at
`
func (q *Queries) GetLibraryFolders(ctx context.Context, libraryID pgtype.UUID) ([]LibraryFolders, error) {
rows, err := q.db.Query(ctx, GetLibraryFolders, libraryID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []LibraryFolders{}
for rows.Next() {
var i LibraryFolders
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.FolderPath,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetLibraryItems = `-- name: GetLibraryItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE ($1::uuid IS NULL OR mi.library_id = $1::uuid)
ORDER BY mi.created_at DESC
`
func (q *Queries) GetLibraryItems(ctx context.Context, libraryID pgtype.UUID) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetLibraryItems, libraryID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetLibraryType = `-- name: GetLibraryType :one
SELECT id, name, description, allowed_extensions, created_at FROM library_types WHERE id = $1
`
func (q *Queries) GetLibraryType(ctx context.Context, id pgtype.UUID) (LibraryTypes, error) {
row := q.db.QueryRow(ctx, GetLibraryType, id)
var i LibraryTypes
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.AllowedExtensions,
&i.CreatedAt,
)
return i, err
}
const GetLibraryTypeByName = `-- name: GetLibraryTypeByName :one
SELECT id, name, description, allowed_extensions, created_at FROM library_types WHERE name = $1
`
func (q *Queries) GetLibraryTypeByName(ctx context.Context, name string) (LibraryTypes, error) {
row := q.db.QueryRow(ctx, GetLibraryTypeByName, name)
var i LibraryTypes
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.AllowedExtensions,
&i.CreatedAt,
)
return i, err
}
const GetLibraryTypes = `-- name: GetLibraryTypes :many
SELECT id, name, description, allowed_extensions, created_at FROM library_types ORDER BY name
`
// Library Types queries
func (q *Queries) GetLibraryTypes(ctx context.Context) ([]LibraryTypes, error) {
rows, err := q.db.Query(ctx, GetLibraryTypes)
if err != nil {
return nil, err
}
defer rows.Close()
items := []LibraryTypes{}
for rows.Next() {
var i LibraryTypes
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.AllowedExtensions,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetLibraryVisibility = `-- name: GetLibraryVisibility :one
SELECT id, user_id, library_id, is_visible, created_at, updated_at FROM library_visibility WHERE user_id = $1 AND library_id = $2
`
type GetLibraryVisibilityParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
func (q *Queries) GetLibraryVisibility(ctx context.Context, arg GetLibraryVisibilityParams) (LibraryVisibility, error) {
row := q.db.QueryRow(ctx, GetLibraryVisibility, arg.UserID, arg.LibraryID)
var i LibraryVisibility
err := row.Scan(
&i.ID,
&i.UserID,
&i.LibraryID,
&i.IsVisible,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetLibraryWithType = `-- name: GetLibraryWithType :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,
lt.allowed_extensions
FROM libraries l
JOIN library_types lt ON l.library_type_id = lt.id
WHERE l.id = $1
`
type GetLibraryWithTypeRow 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"`
AllowedExtensions []string `db:"allowed_extensions" json:"allowed_extensions"`
}
// ============================================================================
// LIBRARY WITH TYPE INFO QUERIES
// ============================================================================
func (q *Queries) GetLibraryWithType(ctx context.Context, id pgtype.UUID) (GetLibraryWithTypeRow, error) {
row := q.db.QueryRow(ctx, GetLibraryWithType, id)
var i GetLibraryWithTypeRow
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.LibraryTypeID,
&i.CreatedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
&i.TypeName,
&i.TypeDescription,
&i.AllowedExtensions,
)
return i, err
}
const GetMediaBookmark = `-- name: GetMediaBookmark :one
SELECT id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at FROM media_bookmarks WHERE id = $1
`
func (q *Queries) GetMediaBookmark(ctx context.Context, id pgtype.UUID) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, GetMediaBookmark, id)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const GetMediaBookmarkByDedupKey = `-- name: GetMediaBookmarkByDedupKey :one
SELECT id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at FROM media_bookmarks
WHERE user_id = $1 AND media_item_id = $2 AND dedup_key = $3
ORDER BY deleted ASC, deleted_at DESC NULLS LAST
LIMIT 1
`
type GetMediaBookmarkByDedupKeyParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
}
// ============================================
// ANNOTATION SYNC QUERIES (bookmarks)
// ============================================
func (q *Queries) GetMediaBookmarkByDedupKey(ctx context.Context, arg GetMediaBookmarkByDedupKeyParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, GetMediaBookmarkByDedupKey, arg.UserID, arg.MediaItemID, arg.DedupKey)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const GetMediaBookmarks = `-- name: GetMediaBookmarks :many
SELECT id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at FROM media_bookmarks
WHERE media_item_id = $1 AND user_id = $2 AND COALESCE(deleted, FALSE) = FALSE
ORDER BY created_at DESC
`
type GetMediaBookmarksParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) GetMediaBookmarks(ctx context.Context, arg GetMediaBookmarksParams) ([]MediaBookmarks, error) {
rows, err := q.db.Query(ctx, GetMediaBookmarks, arg.MediaItemID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaBookmarks{}
for rows.Next() {
var i MediaBookmarks
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at 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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const GetMediaHighlightByDedupKey = `-- name: GetMediaHighlightByDedupKey :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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at FROM media_highlights
WHERE user_id = $1 AND media_item_id = $2 AND dedup_key = $3
ORDER BY deleted ASC, deleted_at DESC NULLS LAST
LIMIT 1
`
type GetMediaHighlightByDedupKeyParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
}
// ============================================
// ANNOTATION SYNC QUERIES (highlights)
// ============================================
func (q *Queries) GetMediaHighlightByDedupKey(ctx context.Context, arg GetMediaHighlightByDedupKeyParams) (MediaHighlights, error) {
row := q.db.QueryRow(ctx, GetMediaHighlightByDedupKey, arg.UserID, arg.MediaItemID, arg.DedupKey)
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
)
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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 AND COALESCE(deleted, FALSE) = FALSE 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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
); 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, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE id = $1
`
func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error) {
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemByFilePath = `-- name: GetMediaItemByFilePath :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 AND library_id = $2
`
type GetMediaItemByFilePathParams struct {
FilePath string `db:"file_path" json:"file_path"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemByFilePathParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByFilePath, arg.FilePath, arg.LibraryID)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemByFilePathAnyLibrary = `-- name: GetMediaItemByFilePathAnyLibrary :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 LIMIT 1
`
func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath string) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByFilePathAnyLibrary, filePath)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemByFilePathForSync = `-- name: GetMediaItemByFilePathForSync :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1
`
// ============================================
// KOREADER SYNC PROTOCOL
// ============================================
func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath string) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByFilePathForSync, filePath)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemByKoboContentId = `-- name: GetMediaItemByKoboContentId :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE kobo_content_id = $1
`
func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID pgtype.Text) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByKoboContentId, koboContentID)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemByOPFIdentifier = `-- name: GetMediaItemByOPFIdentifier :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_identifier = $1
`
// Get media item by OPF identifier
func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier pgtype.Text) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByOPFIdentifier, opfIdentifier)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemByOPFUUID = `-- name: GetMediaItemByOPFUUID :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_uuid = $1
`
// Get media item by OPF UUID
func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemByOPFUUID, opfUuid)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemBySHA256 = `-- name: GetMediaItemBySHA256 :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $1
`
// Get media item by SHA-256 hash
func (q *Queries) GetMediaItemBySHA256(ctx context.Context, fileSha256 pgtype.Text) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemBySHA256, fileSha256)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemBySHA256AndLibrary = `-- name: GetMediaItemBySHA256AndLibrary :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, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $1 AND library_id = $2
`
type GetMediaItemBySHA256AndLibraryParams struct {
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
// Get media item by SHA-256 hash within a specific library (content dedup)
func (q *Queries) GetMediaItemBySHA256AndLibrary(ctx context.Context, arg GetMediaItemBySHA256AndLibraryParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, GetMediaItemBySHA256AndLibrary, arg.FileSha256, arg.LibraryID)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const GetMediaItemFormatBySHA256 = `-- name: GetMediaItemFormatBySHA256 :one
SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE file_sha256 = $1
`
// Get media item format by SHA-256
func (q *Queries) GetMediaItemFormatBySHA256(ctx context.Context, fileSha256 pgtype.Text) (MediaItemFormats, error) {
row := q.db.QueryRow(ctx, GetMediaItemFormatBySHA256, fileSha256)
var i MediaItemFormats
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.FormatType,
&i.FilePath,
&i.FileSha256,
&i.FileSizeBytes,
&i.MimeType,
&i.CreatedAt,
&i.ConvertedFromFormatID,
)
return i, err
}
const GetMediaItemFormatByType = `-- name: GetMediaItemFormatByType :one
SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE media_item_id = $1 AND format_type = $2
`
type GetMediaItemFormatByTypeParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
FormatType string `db:"format_type" json:"format_type"`
}
// Get media item format by type
func (q *Queries) GetMediaItemFormatByType(ctx context.Context, arg GetMediaItemFormatByTypeParams) (MediaItemFormats, error) {
row := q.db.QueryRow(ctx, GetMediaItemFormatByType, arg.MediaItemID, arg.FormatType)
var i MediaItemFormats
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.FormatType,
&i.FilePath,
&i.FileSha256,
&i.FileSizeBytes,
&i.MimeType,
&i.CreatedAt,
&i.ConvertedFromFormatID,
)
return i, err
}
const GetMediaItemFormats = `-- name: GetMediaItemFormats :many
SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE media_item_id = $1
`
// Get media item formats
func (q *Queries) GetMediaItemFormats(ctx context.Context, mediaItemID pgtype.UUID) ([]MediaItemFormats, error) {
rows, err := q.db.Query(ctx, GetMediaItemFormats, mediaItemID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItemFormats{}
for rows.Next() {
var i MediaItemFormats
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.FormatType,
&i.FilePath,
&i.FileSha256,
&i.FileSizeBytes,
&i.MimeType,
&i.CreatedAt,
&i.ConvertedFromFormatID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetMediaNote = `-- name: GetMediaNote :one
SELECT id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at 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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const GetMediaNoteByDedupKey = `-- name: GetMediaNoteByDedupKey :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, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at FROM media_notes
WHERE user_id = $1 AND media_item_id = $2 AND dedup_key = $3
ORDER BY deleted ASC, deleted_at DESC NULLS LAST
LIMIT 1
`
type GetMediaNoteByDedupKeyParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
}
// ============================================
// ANNOTATION SYNC QUERIES (notes)
// ============================================
func (q *Queries) GetMediaNoteByDedupKey(ctx context.Context, arg GetMediaNoteByDedupKeyParams) (MediaNotes, error) {
row := q.db.QueryRow(ctx, GetMediaNoteByDedupKey, arg.UserID, arg.MediaItemID, arg.DedupKey)
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
)
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, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at FROM media_notes WHERE media_item_id = $1 AND user_id = $2 AND COALESCE(deleted, FALSE) = FALSE 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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetMediaRating = `-- name: GetMediaRating :one
SELECT id, media_item_id, user_id, rating, created_at, updated_at FROM media_ratings WHERE media_item_id = $1 AND user_id = $2
`
type GetMediaRatingParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) GetMediaRating(ctx context.Context, arg GetMediaRatingParams) (MediaRatings, error) {
row := q.db.QueryRow(ctx, GetMediaRating, arg.MediaItemID, arg.UserID)
var i MediaRatings
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.Rating,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetMediaRatings = `-- name: GetMediaRatings :many
SELECT mr.id, mr.media_item_id, mr.user_id, mr.rating, mr.created_at, mr.updated_at, u.username
FROM media_ratings mr
JOIN users u ON mr.user_id = u.id
WHERE mr.media_item_id = $1
ORDER BY mr.created_at DESC
`
type GetMediaRatingsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Rating int32 `db:"rating" json:"rating"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
Username string `db:"username" json:"username"`
}
func (q *Queries) GetMediaRatings(ctx context.Context, mediaItemID pgtype.UUID) ([]GetMediaRatingsRow, error) {
rows, err := q.db.Query(ctx, GetMediaRatings, mediaItemID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetMediaRatingsRow{}
for rows.Next() {
var i GetMediaRatingsRow
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.Rating,
&i.CreatedAt,
&i.UpdatedAt,
&i.Username,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetNextRetryTime = `-- name: GetNextRetryTime :one
SELECT
CASE
WHEN attempts = 0 THEN NOW()
WHEN attempts = 1 THEN NOW() + INTERVAL '1 minute'
WHEN attempts = 2 THEN NOW() + INTERVAL '5 minutes'
WHEN attempts = 3 THEN NOW() + INTERVAL '15 minutes'
WHEN attempts = 4 THEN NOW() + INTERVAL '1 hour'
ELSE NOW() + INTERVAL '24 hours'
END as next_retry_time
`
func (q *Queries) GetNextRetryTime(ctx context.Context) (interface{}, error) {
row := q.db.QueryRow(ctx, GetNextRetryTime)
var next_retry_time interface{}
err := row.Scan(&next_retry_time)
return next_retry_time, err
}
const GetNotStartedItems = `-- name: GetNotStartedItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE ($1::uuid IS NULL OR mi.library_id = $1::uuid)
AND NOT EXISTS (
SELECT 1 FROM reading_progress rp
WHERE rp.media_item_id = mi.id
AND rp.user_id = $2
AND rp.percentage > 0
)
ORDER BY mi.created_at DESC
LIMIT $3
`
type GetNotStartedItemsParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
func (q *Queries) GetNotStartedItems(ctx context.Context, arg GetNotStartedItemsParams) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetNotStartedItems, arg.LibraryID, arg.UserID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetOpdsToken = `-- name: GetOpdsToken :one
SELECT ot.id, ot.device_id, ot.token, ot.token_type, ot.expires_at, ot.created_at, d.device_name, d.device_type
FROM opds_tokens ot
JOIN devices d ON ot.device_id = d.id
WHERE ot.token = $1 AND ot.expires_at > NOW()
`
type GetOpdsTokenRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
Token string `db:"token" json:"token"`
TokenType pgtype.Text `db:"token_type" json:"token_type"`
ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
DeviceName string `db:"device_name" json:"device_name"`
DeviceType string `db:"device_type" json:"device_type"`
}
// Get OPDS token
func (q *Queries) GetOpdsToken(ctx context.Context, token string) (GetOpdsTokenRow, error) {
row := q.db.QueryRow(ctx, GetOpdsToken, token)
var i GetOpdsTokenRow
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.Token,
&i.TokenType,
&i.ExpiresAt,
&i.CreatedAt,
&i.DeviceName,
&i.DeviceType,
)
return i, err
}
const GetOpdsTokensByDevice = `-- name: GetOpdsTokensByDevice :many
SELECT id, device_id, token, token_type, expires_at, created_at FROM opds_tokens WHERE device_id = $1 AND expires_at > NOW()
`
// Get OPDS tokens by device
func (q *Queries) GetOpdsTokensByDevice(ctx context.Context, deviceID pgtype.UUID) ([]OpdsTokens, error) {
rows, err := q.db.Query(ctx, GetOpdsTokensByDevice, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []OpdsTokens{}
for rows.Next() {
var i OpdsTokens
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.Token,
&i.TokenType,
&i.ExpiresAt,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetPanelData = `-- name: GetPanelData :one
SELECT id, media_item_id, page_number, detection_method, panels, created_at, updated_at FROM panel_data
WHERE media_item_id = $1 AND page_number = $2
`
type GetPanelDataParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PageNumber int32 `db:"page_number" json:"page_number"`
}
func (q *Queries) GetPanelData(ctx context.Context, arg GetPanelDataParams) (PanelData, error) {
row := q.db.QueryRow(ctx, GetPanelData, arg.MediaItemID, arg.PageNumber)
var i PanelData
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.PageNumber,
&i.DetectionMethod,
&i.Panels,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetPopularBooks = `-- name: GetPopularBooks :many
SELECT
mi.id,
mi.title,
mi.author,
COUNT(*) as read_count,
AVG(rh.progress_percentage) as avg_completion,
MAX(rh.created_at) as last_read
FROM media_items mi
JOIN reading_history rh ON rh.media_item_id = mi.id
WHERE rh.user_id = $1
GROUP BY mi.id, mi.title, mi.author
ORDER BY read_count DESC
LIMIT $2
`
type GetPopularBooksParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Limit int32 `db:"limit" json:"limit"`
}
type GetPopularBooksRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
ReadCount int64 `db:"read_count" json:"read_count"`
AvgCompletion float64 `db:"avg_completion" json:"avg_completion"`
LastRead interface{} `db:"last_read" json:"last_read"`
}
// Get most popular books for a user
func (q *Queries) GetPopularBooks(ctx context.Context, arg GetPopularBooksParams) ([]GetPopularBooksRow, error) {
rows, err := q.db.Query(ctx, GetPopularBooks, arg.UserID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetPopularBooksRow{}
for rows.Next() {
var i GetPopularBooksRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.Author,
&i.ReadCount,
&i.AvgCompletion,
&i.LastRead,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetProcessingIssueStats = `-- name: GetProcessingIssueStats :one
SELECT
COUNT(*) FILTER (WHERE severity = 'error' AND resolved = false) as error_count,
COUNT(*) FILTER (WHERE severity = 'warning' AND resolved = false) as warning_count,
COUNT(*) FILTER (WHERE severity = 'info' AND resolved = false) as info_count
FROM processing_issues
WHERE library_id = $1
`
type GetProcessingIssueStatsRow struct {
ErrorCount int64 `db:"error_count" json:"error_count"`
WarningCount int64 `db:"warning_count" json:"warning_count"`
InfoCount int64 `db:"info_count" json:"info_count"`
}
func (q *Queries) GetProcessingIssueStats(ctx context.Context, libraryID pgtype.UUID) (GetProcessingIssueStatsRow, error) {
row := q.db.QueryRow(ctx, GetProcessingIssueStats, libraryID)
var i GetProcessingIssueStatsRow
err := row.Scan(&i.ErrorCount, &i.WarningCount, &i.InfoCount)
return i, err
}
const GetReaderSettings = `-- name: GetReaderSettings :one
SELECT setting_value FROM reader_settings
WHERE user_id = $1 AND setting_key = 'reader_settings'
`
func (q *Queries) GetReaderSettings(ctx context.Context, userID pgtype.UUID) ([]byte, error) {
row := q.db.QueryRow(ctx, GetReaderSettings, userID)
var setting_value []byte
err := row.Scan(&setting_value)
return setting_value, err
}
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, context_text, 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.ContextText,
&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 GetReadingSpeed = `-- name: GetReadingSpeed :one
SELECT id, user_id, media_item_id, words_per_minute, pages_per_minute, pages_read, total_reading_minutes, last_read_at, updated_at FROM reading_speed
WHERE user_id = $1 AND media_item_id = $2
`
type GetReadingSpeedParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
func (q *Queries) GetReadingSpeed(ctx context.Context, arg GetReadingSpeedParams) (ReadingSpeed, error) {
row := q.db.QueryRow(ctx, GetReadingSpeed, arg.UserID, arg.MediaItemID)
var i ReadingSpeed
err := row.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.WordsPerMinute,
&i.PagesPerMinute,
&i.PagesRead,
&i.TotalReadingMinutes,
&i.LastReadAt,
&i.UpdatedAt,
)
return i, err
}
const GetRecentlyAddedItems = `-- name: GetRecentlyAddedItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE ($1::uuid IS NULL OR mi.library_id = $1::uuid)
ORDER BY mi.imported_at DESC NULLS LAST, mi.created_at DESC
LIMIT $2
`
type GetRecentlyAddedItemsParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAddedItemsParams) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetRecentlyAddedItems, arg.LibraryID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetRecentlyReadItems = `-- name: GetRecentlyReadItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
INNER JOIN (
SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at
FROM reading_progress
WHERE user_id = $1
AND percentage >= 1
ORDER BY media_item_id, last_read_at DESC
) rp ON rp.media_item_id = mi.id
WHERE ($2::uuid IS NULL OR mi.library_id = $2::uuid)
ORDER BY rp.last_read_at DESC
LIMIT $3
`
type GetRecentlyReadItemsParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
func (q *Queries) GetRecentlyReadItems(ctx context.Context, arg GetRecentlyReadItemsParams) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetRecentlyReadItems, arg.UserID, arg.LibraryID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetRefreshToken = `-- name: GetRefreshToken :one
SELECT rt.id, rt.user_id, rt.token, rt.expires_at, rt.created_at, rt.revoked_at, u.email, u.username, u.role
FROM refresh_tokens rt
JOIN users u ON rt.user_id = u.id
WHERE rt.token = $1 AND rt.revoked_at IS NULL AND rt.expires_at > NOW()
`
type GetRefreshTokenRow struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Token pgtype.UUID `db:"token" json:"token"`
ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
RevokedAt pgtype.Timestamptz `db:"revoked_at" json:"revoked_at"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Role string `db:"role" json:"role"`
}
func (q *Queries) GetRefreshToken(ctx context.Context, token pgtype.UUID) (GetRefreshTokenRow, error) {
row := q.db.QueryRow(ctx, GetRefreshToken, token)
var i GetRefreshTokenRow
err := row.Scan(
&i.ID,
&i.UserID,
&i.Token,
&i.ExpiresAt,
&i.CreatedAt,
&i.RevokedAt,
&i.Email,
&i.Username,
&i.Role,
)
return i, err
}
const GetSavedFilterByID = `-- name: GetSavedFilterByID :one
SELECT id, user_id, name, resource_type, filters, created_at, updated_at FROM saved_filters
WHERE id = $1 AND user_id = $2
`
type GetSavedFilterByIDParams struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) GetSavedFilterByID(ctx context.Context, arg GetSavedFilterByIDParams) (SavedFilters, error) {
row := q.db.QueryRow(ctx, GetSavedFilterByID, arg.ID, arg.UserID)
var i SavedFilters
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.ResourceType,
&i.Filters,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetSavedFilters = `-- name: GetSavedFilters :many
SELECT id, user_id, name, resource_type, filters, created_at, updated_at FROM saved_filters
WHERE user_id = $1 AND resource_type = $2
ORDER BY created_at DESC
`
type GetSavedFiltersParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
ResourceType string `db:"resource_type" json:"resource_type"`
}
func (q *Queries) GetSavedFilters(ctx context.Context, arg GetSavedFiltersParams) ([]SavedFilters, error) {
rows, err := q.db.Query(ctx, GetSavedFilters, arg.UserID, arg.ResourceType)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SavedFilters{}
for rows.Next() {
var i SavedFilters
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.ResourceType,
&i.Filters,
&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 GetSeriesBooks = `-- name: GetSeriesBooks :many
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items
WHERE series = $1
ORDER BY series_number ASC NULLS LAST
`
func (q *Queries) GetSeriesBooks(ctx context.Context, series pgtype.Text) ([]MediaItems, error) {
rows, err := q.db.Query(ctx, GetSeriesBooks, series)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaItems{}
for rows.Next() {
var i MediaItems
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetSeriesCovers = `-- name: GetSeriesCovers :many
SELECT cover_image_path, library_id
FROM media_items
WHERE ($1::uuid IS NULL OR library_id = $1::uuid) AND series = $2 AND cover_image_path IS NOT NULL AND cover_image_path != ''
ORDER BY series_number ASC NULLS LAST
LIMIT $3
`
type GetSeriesCoversParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Series pgtype.Text `db:"series" json:"series"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type GetSeriesCoversRow struct {
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
func (q *Queries) GetSeriesCovers(ctx context.Context, arg GetSeriesCoversParams) ([]GetSeriesCoversRow, error) {
rows, err := q.db.Query(ctx, GetSeriesCovers, arg.LibraryID, arg.Series, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetSeriesCoversRow{}
for rows.Next() {
var i GetSeriesCoversRow
if err := rows.Scan(&i.CoverImagePath, &i.LibraryID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetStuckSyncQueueItems = `-- name: GetStuckSyncQueueItems :many
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue
WHERE status = 'processing' AND created_at < NOW() - INTERVAL '1 hour'
ORDER BY priority ASC, created_at ASC
`
func (q *Queries) GetStuckSyncQueueItems(ctx context.Context) ([]SyncQueue, error) {
rows, err := q.db.Query(ctx, GetStuckSyncQueueItems)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SyncQueue{}
for rows.Next() {
var i SyncQueue
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetSyncConflict = `-- name: GetSyncConflict :one
SELECT id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at FROM sync_conflicts WHERE id = $1
`
func (q *Queries) GetSyncConflict(ctx context.Context, id pgtype.UUID) (SyncConflicts, error) {
row := q.db.QueryRow(ctx, GetSyncConflict, id)
var i SyncConflicts
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.ConflictType,
&i.ConflictData,
&i.ResolutionStatus,
&i.ResolutionData,
&i.ResolvedBy,
&i.ResolvedAt,
&i.CreatedAt,
)
return i, err
}
const GetSyncQueueItem = `-- name: GetSyncQueueItem :one
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue WHERE id = $1
`
func (q *Queries) GetSyncQueueItem(ctx context.Context, id pgtype.UUID) (SyncQueue, error) {
row := q.db.QueryRow(ctx, GetSyncQueueItem, id)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const GetSyncQueueStats = `-- name: GetSyncQueueStats :one
SELECT
COUNT(*) FILTER (WHERE status = 'pending') as pending_count,
COUNT(*) FILTER (WHERE status = 'processing') as processing_count,
COUNT(*) FILTER (WHERE status = 'failed') as failed_count,
COUNT(*) FILTER (WHERE status = 'completed') as completed_count,
COUNT(*) as total_count
FROM sync_queue
WHERE device_id = $1
`
type GetSyncQueueStatsRow struct {
PendingCount int64 `db:"pending_count" json:"pending_count"`
ProcessingCount int64 `db:"processing_count" json:"processing_count"`
FailedCount int64 `db:"failed_count" json:"failed_count"`
CompletedCount int64 `db:"completed_count" json:"completed_count"`
TotalCount int64 `db:"total_count" json:"total_count"`
}
func (q *Queries) GetSyncQueueStats(ctx context.Context, deviceID pgtype.UUID) (GetSyncQueueStatsRow, error) {
row := q.db.QueryRow(ctx, GetSyncQueueStats, deviceID)
var i GetSyncQueueStatsRow
err := row.Scan(
&i.PendingCount,
&i.ProcessingCount,
&i.FailedCount,
&i.CompletedCount,
&i.TotalCount,
)
return i, err
}
const GetSystemCollectionsForDashboard = `-- name: GetSystemCollectionsForDashboard :many
SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections
WHERE user_id = $1
AND is_system_collection = true
AND show_on_dashboard = true
ORDER BY priority ASC
`
// Dashboard collections queries
func (q *Queries) GetSystemCollectionsForDashboard(ctx context.Context, userID pgtype.UUID) ([]Collections, error) {
rows, err := q.db.Query(ctx, GetSystemCollectionsForDashboard, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Collections{}
for rows.Next() {
var i Collections
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetSystemConfig = `-- name: GetSystemConfig :one
SELECT key, value, updated_at, updated_by FROM system_config WHERE key = $1
`
// SYSTEM CONFIG QUERIES
// Get system config
func (q *Queries) GetSystemConfig(ctx context.Context, key string) (SystemConfig, error) {
row := q.db.QueryRow(ctx, GetSystemConfig, key)
var i SystemConfig
err := row.Scan(
&i.Key,
&i.Value,
&i.UpdatedAt,
&i.UpdatedBy,
)
return i, err
}
const GetSystemSetting = `-- name: GetSystemSetting :one
SELECT setting_value FROM system_settings WHERE setting_key = $1
`
// System Settings queries
func (q *Queries) GetSystemSetting(ctx context.Context, settingKey string) (string, error) {
row := q.db.QueryRow(ctx, GetSystemSetting, settingKey)
var setting_value string
err := row.Scan(&setting_value)
return setting_value, err
}
const GetSystemSettingFull = `-- name: GetSystemSettingFull :one
SELECT id, setting_key, setting_value, description, updated_at, setting_type, min_value, max_value, requires_restart, category FROM system_settings WHERE setting_key = $1
`
func (q *Queries) GetSystemSettingFull(ctx context.Context, settingKey string) (SystemSettings, error) {
row := q.db.QueryRow(ctx, GetSystemSettingFull, settingKey)
var i SystemSettings
err := row.Scan(
&i.ID,
&i.SettingKey,
&i.SettingValue,
&i.Description,
&i.UpdatedAt,
&i.SettingType,
&i.MinValue,
&i.MaxValue,
&i.RequiresRestart,
&i.Category,
)
return i, err
}
const GetSystemTimezone = `-- name: GetSystemTimezone :one
SELECT setting_value FROM system_settings WHERE setting_key = 'default_timezone'
`
func (q *Queries) GetSystemTimezone(ctx context.Context) (string, error) {
row := q.db.QueryRow(ctx, GetSystemTimezone)
var setting_value string
err := row.Scan(&setting_value)
return setting_value, err
}
const GetTombstonedAnnotationsForBook = `-- name: GetTombstonedAnnotationsForBook :many
SELECT
mh.id,
mh.dedup_key,
'highlight' as annotation_type,
mh.device_sync_data,
mh.deleted_at
FROM media_highlights mh
WHERE mh.media_item_id = $1 AND mh.user_id = $2 AND mh.deleted = TRUE AND mh.deleted_at > $3
UNION ALL
SELECT
mn.id,
mn.dedup_key,
'note' as annotation_type,
mn.device_sync_data,
mn.deleted_at
FROM media_notes mn
WHERE mn.media_item_id = $1 AND mn.user_id = $2 AND mn.deleted = TRUE AND mn.deleted_at > $3
UNION ALL
SELECT
mb.id,
mb.dedup_key,
'bookmark' as annotation_type,
mb.device_sync_data,
mb.deleted_at
FROM media_bookmarks mb
WHERE mb.media_item_id = $1 AND mb.user_id = $2 AND mb.deleted = TRUE AND mb.deleted_at > $3
ORDER BY deleted_at DESC
`
type GetTombstonedAnnotationsForBookParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
DeletedAt pgtype.Timestamptz `db:"deleted_at" json:"deleted_at"`
}
type GetTombstonedAnnotationsForBookRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
AnnotationType string `db:"annotation_type" json:"annotation_type"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
DeletedAt pgtype.Timestamptz `db:"deleted_at" json:"deleted_at"`
}
func (q *Queries) GetTombstonedAnnotationsForBook(ctx context.Context, arg GetTombstonedAnnotationsForBookParams) ([]GetTombstonedAnnotationsForBookRow, error) {
rows, err := q.db.Query(ctx, GetTombstonedAnnotationsForBook, arg.MediaItemID, arg.UserID, arg.DeletedAt)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetTombstonedAnnotationsForBookRow{}
for rows.Next() {
var i GetTombstonedAnnotationsForBookRow
if err := rows.Scan(
&i.ID,
&i.DedupKey,
&i.AnnotationType,
&i.DeviceSyncData,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
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.context_text,
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"`
ContextText pgtype.Text `db:"context_text" json:"context_text"`
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.ContextText,
&i.Chapter,
&i.ChapterProgress,
&i.ViewportX,
&i.ViewportY,
&i.ZoomLevel,
&i.ScrollPositionX,
&i.ScrollPositionY,
&i.PanelNumber,
&i.ReadingMode,
&i.LastSyncDevice,
&i.LastSyncSource,
&i.LastSyncTimestamp,
&i.ConflictDetected,
&i.ConflictResolved,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
)
return i, err
}
const GetUnlinkedBookByContentId = `-- name: GetUnlinkedBookByContentId :one
SELECT id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at FROM unlinked_books WHERE device_id = $1 AND content_id = $2
`
type GetUnlinkedBookByContentIdParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ContentID string `db:"content_id" json:"content_id"`
}
// Get unlinked book by ContentId
func (q *Queries) GetUnlinkedBookByContentId(ctx context.Context, arg GetUnlinkedBookByContentIdParams) (UnlinkedBooks, error) {
row := q.db.QueryRow(ctx, GetUnlinkedBookByContentId, arg.DeviceID, arg.ContentID)
var i UnlinkedBooks
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
)
return i, err
}
const GetUnlinkedBookByID = `-- name: GetUnlinkedBookByID :one
SELECT id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at FROM unlinked_books WHERE id = $1
`
// Get unlinked book by ID
func (q *Queries) GetUnlinkedBookByID(ctx context.Context, id pgtype.UUID) (UnlinkedBooks, error) {
row := q.db.QueryRow(ctx, GetUnlinkedBookByID, id)
var i UnlinkedBooks
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
)
return i, err
}
const GetUnlinkedBooksByDevice = `-- name: GetUnlinkedBooksByDevice :many
SELECT ub.id, ub.device_id, ub.content_id, ub.file_path, ub.title, ub.author, ub.confidence_score, ub.resolved, ub.media_item_id, ub.resolved_at, ub.resolution_method, ub.last_seen_at, ub.created_at, d.device_name, d.device_type
FROM unlinked_books ub
JOIN devices d ON ub.device_id = d.id
WHERE ub.device_id = $1 AND ub.resolved = false
ORDER BY ub.last_seen_at DESC
`
type GetUnlinkedBooksByDeviceRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ContentID string `db:"content_id" json:"content_id"`
FilePath pgtype.Text `db:"file_path" json:"file_path"`
Title pgtype.Text `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
Resolved pgtype.Bool `db:"resolved" json:"resolved"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"`
LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
DeviceName string `db:"device_name" json:"device_name"`
DeviceType string `db:"device_type" json:"device_type"`
}
// Get unlinked books for a device
func (q *Queries) GetUnlinkedBooksByDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetUnlinkedBooksByDeviceRow, error) {
rows, err := q.db.Query(ctx, GetUnlinkedBooksByDevice, deviceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUnlinkedBooksByDeviceRow{}
for rows.Next() {
var i GetUnlinkedBooksByDeviceRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
&i.DeviceName,
&i.DeviceType,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUser = `-- name: GetUser :one
SELECT
u.id,
u.email,
u.username,
u.theme,
u.first_name,
u.last_name,
u.role,
u.max_devices,
u.created_at,
u.updated_at,
u.timezone,
(SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
FROM users u
WHERE u.id = $1
`
type GetUserRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
Timezone pgtype.Text `db:"timezone" json:"timezone"`
DeviceCount int64 `db:"device_count" json:"device_count"`
}
func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, error) {
row := q.db.QueryRow(ctx, GetUser, id)
var i GetUserRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.MaxDevices,
&i.CreatedAt,
&i.UpdatedAt,
&i.Timezone,
&i.DeviceCount,
)
return i, err
}
const GetUserByEmail = `-- name: GetUserByEmail :one
SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1
`
type GetUserByEmailRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetUserByEmail(ctx context.Context, email string) (GetUserByEmailRow, error) {
row := q.db.QueryRow(ctx, GetUserByEmail, email)
var i GetUserByEmailRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one
SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1
`
type GetUserByEmailOrUsernameRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (GetUserByEmailOrUsernameRow, error) {
row := q.db.QueryRow(ctx, GetUserByEmailOrUsername, email)
var i GetUserByEmailOrUsernameRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetUserByUsername = `-- name: GetUserByUsername :one
SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE username = $1
`
type GetUserByUsernameRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetUserByUsername(ctx context.Context, username string) (GetUserByUsernameRow, error) {
row := q.db.QueryRow(ctx, GetUserByUsername, username)
var i GetUserByUsernameRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetUserCollectionsForDashboard = `-- name: GetUserCollectionsForDashboard :many
SELECT c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at FROM collections c
WHERE c.user_id = $1
AND c.show_on_dashboard = true
AND c.is_system_collection = false
ORDER BY priority ASC
`
func (q *Queries) GetUserCollectionsForDashboard(ctx context.Context, userID pgtype.UUID) ([]Collections, error) {
rows, err := q.db.Query(ctx, GetUserCollectionsForDashboard, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Collections{}
for rows.Next() {
var i Collections
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserDeviceUsage = `-- name: GetUserDeviceUsage :many
SELECT
d.id,
d.device_name,
d.device_type,
COUNT(*) as sync_count,
MAX(rh.created_at) as last_sync,
SUM(rh.time_spent_seconds) as total_time_seconds
FROM devices d
JOIN reading_history rh ON rh.device_id = d.id
WHERE d.user_id = $1
GROUP BY d.id, d.device_name, d.device_type
ORDER BY sync_count DESC
`
type GetUserDeviceUsageRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceName string `db:"device_name" json:"device_name"`
DeviceType string `db:"device_type" json:"device_type"`
SyncCount int64 `db:"sync_count" json:"sync_count"`
LastSync interface{} `db:"last_sync" json:"last_sync"`
TotalTimeSeconds int64 `db:"total_time_seconds" json:"total_time_seconds"`
}
// Get user device usage statistics
func (q *Queries) GetUserDeviceUsage(ctx context.Context, userID pgtype.UUID) ([]GetUserDeviceUsageRow, error) {
rows, err := q.db.Query(ctx, GetUserDeviceUsage, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserDeviceUsageRow{}
for rows.Next() {
var i GetUserDeviceUsageRow
if err := rows.Scan(
&i.ID,
&i.DeviceName,
&i.DeviceType,
&i.SyncCount,
&i.LastSync,
&i.TotalTimeSeconds,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserForLogin = `-- name: GetUserForLogin :one
SELECT id, email, username, password_hash, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1
`
type GetUserForLoginRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
PasswordHash string `db:"password_hash" json:"password_hash"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
func (q *Queries) GetUserForLogin(ctx context.Context, email string) (GetUserForLoginRow, error) {
row := q.db.QueryRow(ctx, GetUserForLogin, email)
var i GetUserForLoginRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.PasswordHash,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetUserMediaItemsForSync = `-- name: GetUserMediaItemsForSync :many
SELECT
mi.id,
mi.title,
mi.author,
mi.file_path,
mi.mime_type,
mi.page_count,
mi.format_group,
mi.total_characters,
mi.chapter_count,
mi.entitlement_id,
mi.revision_number,
mi.file_size,
mi.file_sha256
FROM media_items mi
JOIN library_visibility lv ON mi.library_id = lv.library_id
WHERE lv.user_id = $1
AND lv.is_visible = true
ORDER BY mi.title ASC
LIMIT 1000
`
type GetUserMediaItemsForSyncRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
FormatGroup string `db:"format_group" json:"format_group"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
}
func (q *Queries) GetUserMediaItemsForSync(ctx context.Context, userID pgtype.UUID) ([]GetUserMediaItemsForSyncRow, error) {
rows, err := q.db.Query(ctx, GetUserMediaItemsForSync, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserMediaItemsForSyncRow{}
for rows.Next() {
var i GetUserMediaItemsForSyncRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.Author,
&i.FilePath,
&i.MimeType,
&i.PageCount,
&i.FormatGroup,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.FileSize,
&i.FileSha256,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserPasswordHash = `-- name: GetUserPasswordHash :one
SELECT password_hash FROM users WHERE id = $1
`
func (q *Queries) GetUserPasswordHash(ctx context.Context, id pgtype.UUID) (string, error) {
row := q.db.QueryRow(ctx, GetUserPasswordHash, id)
var password_hash string
err := row.Scan(&password_hash)
return password_hash, err
}
const GetUserProgressForBooks = `-- name: GetUserProgressForBooks :many
SELECT
rp.media_item_id,
rp.user_id,
rp.percentage,
rp.character_offset,
rp.epubcfi,
rp.chapter,
rp.chapter_progress,
rp.current_page,
rp.total_pages,
rp.last_read_at,
rp.last_sync_device,
rp.last_sync_source,
mi.title,
mi.author,
mi.file_path
FROM reading_progress rp
JOIN media_items mi ON rp.media_item_id = mi.id
WHERE rp.user_id = $1
AND rp.media_item_id = ANY($2::uuid[])
ORDER BY rp.last_read_at DESC
`
type GetUserProgressForBooksParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Column2 []pgtype.UUID `db:"column_2" json:"column_2"`
}
type GetUserProgressForBooksRow struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Percentage pgtype.Float8 `db:"percentage" json:"percentage"`
CharacterOffset pgtype.Int8 `db:"character_offset" json:"character_offset"`
Epubcfi pgtype.Text `db:"epubcfi" json:"epubcfi"`
Chapter pgtype.Int4 `db:"chapter" json:"chapter"`
ChapterProgress pgtype.Float8 `db:"chapter_progress" json:"chapter_progress"`
CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"`
TotalPages pgtype.Int4 `db:"total_pages" json:"total_pages"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
LastSyncDevice pgtype.Text `db:"last_sync_device" json:"last_sync_device"`
LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FilePath string `db:"file_path" json:"file_path"`
}
func (q *Queries) GetUserProgressForBooks(ctx context.Context, arg GetUserProgressForBooksParams) ([]GetUserProgressForBooksRow, error) {
rows, err := q.db.Query(ctx, GetUserProgressForBooks, arg.UserID, arg.Column2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserProgressForBooksRow{}
for rows.Next() {
var i GetUserProgressForBooksRow
if err := rows.Scan(
&i.MediaItemID,
&i.UserID,
&i.Percentage,
&i.CharacterOffset,
&i.Epubcfi,
&i.Chapter,
&i.ChapterProgress,
&i.CurrentPage,
&i.TotalPages,
&i.LastReadAt,
&i.LastSyncDevice,
&i.LastSyncSource,
&i.Title,
&i.Author,
&i.FilePath,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserReadingHistory = `-- name: GetUserReadingHistory :many
SELECT
rh.id,
rh.user_id,
rh.media_item_id,
rh.device_id,
rh.progress_percentage,
rh.reading_session_start,
rh.reading_session_end,
rh.pages_read,
rh.time_spent_seconds,
rh.device_metadata,
rh.created_at,
mi.title,
mi.author,
d.device_name,
d.device_type
FROM reading_history rh
JOIN media_items mi ON rh.media_item_id = mi.id
LEFT JOIN devices d ON rh.device_id = d.id
WHERE rh.user_id = $1
AND rh.created_at >= $2
AND rh.created_at <= $3
ORDER BY rh.created_at DESC
`
type GetUserReadingHistoryParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
CreatedAt_2 pgtype.Timestamptz `db:"created_at_2" json:"created_at_2"`
}
type GetUserReadingHistoryRow struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ProgressPercentage pgtype.Float8 `db:"progress_percentage" json:"progress_percentage"`
ReadingSessionStart pgtype.Timestamptz `db:"reading_session_start" json:"reading_session_start"`
ReadingSessionEnd pgtype.Timestamptz `db:"reading_session_end" json:"reading_session_end"`
PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"`
TimeSpentSeconds pgtype.Int4 `db:"time_spent_seconds" json:"time_spent_seconds"`
DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
DeviceName pgtype.Text `db:"device_name" json:"device_name"`
DeviceType pgtype.Text `db:"device_type" json:"device_type"`
}
// Analytics queries
// Get user reading history for analytics
func (q *Queries) GetUserReadingHistory(ctx context.Context, arg GetUserReadingHistoryParams) ([]GetUserReadingHistoryRow, error) {
rows, err := q.db.Query(ctx, GetUserReadingHistory, arg.UserID, arg.CreatedAt, arg.CreatedAt_2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserReadingHistoryRow{}
for rows.Next() {
var i GetUserReadingHistoryRow
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.DeviceID,
&i.ProgressPercentage,
&i.ReadingSessionStart,
&i.ReadingSessionEnd,
&i.PagesRead,
&i.TimeSpentSeconds,
&i.DeviceMetadata,
&i.CreatedAt,
&i.Title,
&i.Author,
&i.DeviceName,
&i.DeviceType,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserVisibleLibraries = `-- name: GetUserVisibleLibraries :many
SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description,
COALESCE(lv.is_visible, true) as is_visible
FROM libraries l
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
WHERE COALESCE(lv.is_visible, true) = true
ORDER BY l.created_at ASC
`
type GetUserVisibleLibrariesRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
LibraryTypeID pgtype.UUID `db:"library_type_id" json:"library_type_id"`
CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
TypeName string `db:"type_name" json:"type_name"`
TypeDescription pgtype.Text `db:"type_description" json:"type_description"`
IsVisible bool `db:"is_visible" json:"is_visible"`
}
func (q *Queries) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]GetUserVisibleLibrariesRow, error) {
rows, err := q.db.Query(ctx, GetUserVisibleLibraries, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetUserVisibleLibrariesRow{}
for rows.Next() {
var i GetUserVisibleLibrariesRow
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.LibraryTypeID,
&i.CreatedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
&i.TypeName,
&i.TypeDescription,
&i.IsVisible,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetVisibleLibraryMediaCounts = `-- name: GetVisibleLibraryMediaCounts :many
SELECT l.id, COUNT(mi.id) as media_count
FROM libraries l
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
LEFT JOIN media_items mi ON mi.library_id = l.id
WHERE COALESCE(lv.is_visible, true) = true
GROUP BY l.id
`
type GetVisibleLibraryMediaCountsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaCount int64 `db:"media_count" json:"media_count"`
}
func (q *Queries) GetVisibleLibraryMediaCounts(ctx context.Context, userID pgtype.UUID) ([]GetVisibleLibraryMediaCountsRow, error) {
rows, err := q.db.Query(ctx, GetVisibleLibraryMediaCounts, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetVisibleLibraryMediaCountsRow{}
for rows.Next() {
var i GetVisibleLibraryMediaCountsRow
if err := rows.Scan(&i.ID, &i.MediaCount); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const HasRecentConflictResolution = `-- name: HasRecentConflictResolution :one
SELECT EXISTS(
SELECT 1 FROM sync_conflicts
WHERE media_item_id = $1
AND user_id = $2
AND resolution_status != 'unresolved'
AND resolved_at > NOW() - INTERVAL '10 minutes'
)
`
type HasRecentConflictResolutionParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) HasRecentConflictResolution(ctx context.Context, arg HasRecentConflictResolutionParams) (bool, error) {
row := q.db.QueryRow(ctx, HasRecentConflictResolution, arg.MediaItemID, arg.UserID)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const IncrementSyncQueueAttempts = `-- name: IncrementSyncQueueAttempts :one
UPDATE sync_queue
SET
attempts = attempts + 1,
status = CASE
WHEN attempts + 1 >= max_attempts THEN 'failed'
ELSE 'pending'
END,
error_message = $2
WHERE id = $1
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`
type IncrementSyncQueueAttemptsParams struct {
ID pgtype.UUID `db:"id" json:"id"`
ErrorMessage pgtype.Text `db:"error_message" json:"error_message"`
}
func (q *Queries) IncrementSyncQueueAttempts(ctx context.Context, arg IncrementSyncQueueAttemptsParams) (SyncQueue, error) {
row := q.db.QueryRow(ctx, IncrementSyncQueueAttempts, arg.ID, arg.ErrorMessage)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const IsBookInCollection = `-- name: IsBookInCollection :one
SELECT EXISTS(
SELECT 1 FROM collection_items
WHERE collection_id = $1 AND media_item_id = $2
) as in_collection
`
type IsBookInCollectionParams struct {
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
// Check if book is in collection
func (q *Queries) IsBookInCollection(ctx context.Context, arg IsBookInCollectionParams) (bool, error) {
row := q.db.QueryRow(ctx, IsBookInCollection, arg.CollectionID, arg.MediaItemID)
var in_collection bool
err := row.Scan(&in_collection)
return in_collection, err
}
const IsBookOnKoboShelf = `-- name: IsBookOnKoboShelf :one
SELECT EXISTS(
SELECT 1 FROM kobo_shelves
WHERE device_id = $1 AND media_item_id = $2
) as on_shelf
`
type IsBookOnKoboShelfParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
func (q *Queries) IsBookOnKoboShelf(ctx context.Context, arg IsBookOnKoboShelfParams) (bool, error) {
row := q.db.QueryRow(ctx, IsBookOnKoboShelf, arg.DeviceID, arg.MediaItemID)
var on_shelf bool
err := row.Scan(&on_shelf)
return on_shelf, err
}
const LinkUnlinkedBook = `-- name: LinkUnlinkedBook :one
UPDATE unlinked_books
SET
media_item_id = $2,
confidence_score = $3,
resolved = true,
resolved_at = NOW(),
resolution_method = 'manual_link'
WHERE id = $1
RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at
`
type LinkUnlinkedBookParams struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}
// Link unlinked book to media item
func (q *Queries) LinkUnlinkedBook(ctx context.Context, arg LinkUnlinkedBookParams) (UnlinkedBooks, error) {
row := q.db.QueryRow(ctx, LinkUnlinkedBook, arg.ID, arg.MediaItemID, arg.ConfidenceScore)
var i UnlinkedBooks
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
)
return i, err
}
const ListAllConflictsByUserAndStatus = `-- name: ListAllConflictsByUserAndStatus :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 = $2
ORDER BY sc.created_at DESC
`
type ListAllConflictsByUserAndStatusParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
}
type ListAllConflictsByUserAndStatusRow 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) ListAllConflictsByUserAndStatus(ctx context.Context, arg ListAllConflictsByUserAndStatusParams) ([]ListAllConflictsByUserAndStatusRow, error) {
rows, err := q.db.Query(ctx, ListAllConflictsByUserAndStatus, arg.UserID, arg.ResolutionStatus)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListAllConflictsByUserAndStatusRow{}
for rows.Next() {
var i ListAllConflictsByUserAndStatusRow
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 ListAllSyncQueueItems = `-- name: ListAllSyncQueueItems :many
SELECT
sq.id, sq.device_id, sq.media_item_id, sq.sync_type, sq.sync_data, sq.priority, sq.attempts, sq.max_attempts, sq.status, sq.error_message, sq.created_at, sq.processed_at,
d.device_name,
d.device_type,
u.email as user_email,
mi.title as media_title
FROM sync_queue sq
JOIN devices d ON sq.device_id = d.id
JOIN users u ON d.user_id = u.id
LEFT JOIN media_items mi ON sq.media_item_id = mi.id
ORDER BY sq.priority ASC, sq.created_at DESC
LIMIT $1 OFFSET $2
`
type ListAllSyncQueueItemsParams struct {
Limit int32 `db:"limit" json:"limit"`
Offset int32 `db:"offset" json:"offset"`
}
type ListAllSyncQueueItemsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
SyncType string `db:"sync_type" json:"sync_type"`
SyncData []byte `db:"sync_data" json:"sync_data"`
Priority pgtype.Int4 `db:"priority" json:"priority"`
Attempts pgtype.Int4 `db:"attempts" json:"attempts"`
MaxAttempts pgtype.Int4 `db:"max_attempts" json:"max_attempts"`
Status pgtype.Text `db:"status" json:"status"`
ErrorMessage pgtype.Text `db:"error_message" json:"error_message"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ProcessedAt pgtype.Timestamptz `db:"processed_at" json:"processed_at"`
DeviceName string `db:"device_name" json:"device_name"`
DeviceType string `db:"device_type" json:"device_type"`
UserEmail string `db:"user_email" json:"user_email"`
MediaTitle pgtype.Text `db:"media_title" json:"media_title"`
}
func (q *Queries) ListAllSyncQueueItems(ctx context.Context, arg ListAllSyncQueueItemsParams) ([]ListAllSyncQueueItemsRow, error) {
rows, err := q.db.Query(ctx, ListAllSyncQueueItems, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListAllSyncQueueItemsRow{}
for rows.Next() {
var i ListAllSyncQueueItemsRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
&i.DeviceName,
&i.DeviceType,
&i.UserEmail,
&i.MediaTitle,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ListConflictsByUser = `-- name: ListConflictsByUser :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
ORDER BY sc.created_at DESC
`
type ListConflictsByUserRow 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) ListConflictsByUser(ctx context.Context, userID pgtype.UUID) ([]ListConflictsByUserRow, error) {
rows, err := q.db.Query(ctx, ListConflictsByUser, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListConflictsByUserRow{}
for rows.Next() {
var i ListConflictsByUserRow
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 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.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
ORDER BY mi.created_at DESC LIMIT $1 OFFSET $2
`
type ListMediaItemsParams struct {
Limit int32 `db:"limit" json:"limit"`
Offset int32 `db:"offset" json:"offset"`
}
type ListMediaItemsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
LibraryName string `db:"library_name" json:"library_name"`
LibraryTypeName_2 string `db:"library_type_name_2" json:"library_type_name_2"`
}
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.LibraryName,
&i.LibraryTypeName_2,
); 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.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
WHERE mi.library_id = $1
ORDER BY mi.created_at DESC
`
type ListMediaItemsByLibraryRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
LibraryName string `db:"library_name" json:"library_name"`
LibraryTypeName_2 string `db:"library_type_name_2" json:"library_type_name_2"`
}
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.LibraryName,
&i.LibraryTypeName_2,
); 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.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
WHERE mi.library_id = $1
ORDER BY
CASE
WHEN $2 = 'title ASC' THEN mi.title
ELSE ''
END ASC,
CASE
WHEN $2 = 'title DESC' THEN mi.title
ELSE ''
END DESC,
CASE
WHEN $2 = 'author ASC' THEN COALESCE(mi.author, '')
ELSE ''
END ASC,
CASE
WHEN $2 = 'author DESC' THEN COALESCE(mi.author, '')
ELSE ''
END DESC,
CASE
WHEN $2 = 'created_at ASC' THEN mi.created_at
ELSE '1970-01-01'::timestamp
END ASC,
CASE
WHEN $2 = 'created_at DESC' THEN mi.created_at
ELSE '1970-01-01'::timestamp
END DESC,
CASE
WHEN $2 = 'series ASC' THEN COALESCE(mi.series, '')
ELSE ''
END ASC,
CASE
WHEN $2 = 'series DESC' THEN COALESCE(mi.series, '')
ELSE ''
END DESC,
CASE
WHEN $2 = 'date_published ASC' THEN COALESCE(mi.date_published::text, '')
ELSE ''
END ASC,
CASE
WHEN $2 = 'date_published DESC' THEN COALESCE(mi.date_published::text, '')
ELSE ''
END DESC,
CASE
WHEN $2 = 'copyright_year ASC' THEN COALESCE(mi.copyright_year::text, '0')
ELSE ''
END ASC,
CASE
WHEN $2 = 'copyright_year DESC' THEN COALESCE(mi.copyright_year::text, '0')
ELSE ''
END DESC,
CASE
WHEN $2 = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0')
ELSE ''
END ASC,
CASE
WHEN $2 = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0')
ELSE ''
END DESC,
CASE
WHEN $2 = 'genre ASC' THEN COALESCE(mi.genre, '')
ELSE ''
END ASC,
CASE
WHEN $2 = 'genre DESC' THEN COALESCE(mi.genre, '')
ELSE ''
END DESC,
mi.created_at DESC
LIMIT $4 OFFSET $3
`
type ListMediaItemsSortedParams struct {
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Sort interface{} `db:"sort" json:"sort"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type ListMediaItemsSortedRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
LibraryName string `db:"library_name" json:"library_name"`
LibraryTypeName_2 string `db:"library_type_name_2" json:"library_type_name_2"`
}
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.LibraryName,
&i.LibraryTypeName_2,
); 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 ListProcessingIssuesByLibrary = `-- name: ListProcessingIssuesByLibrary :many
SELECT
pi.id,
pi.media_item_id,
pi.issue_type,
pi.issue_description,
pi.severity,
pi.resolved,
pi.resolved_at,
pi.created_at,
mi.title,
mi.file_path,
mi.format_group,
lt.name as library_type_name
FROM processing_issues pi
JOIN media_items mi ON pi.media_item_id = mi.id
JOIN libraries l ON pi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
WHERE pi.library_id = $1
AND pi.resolved = false
ORDER BY
CASE pi.severity
WHEN 'error' THEN 1
WHEN 'warning' THEN 2
WHEN 'info' THEN 3
END,
pi.created_at DESC
`
type ListProcessingIssuesByLibraryRow struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
IssueType string `db:"issue_type" json:"issue_type"`
IssueDescription string `db:"issue_description" json:"issue_description"`
Severity string `db:"severity" json:"severity"`
Resolved pgtype.Bool `db:"resolved" json:"resolved"`
ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
Title string `db:"title" json:"title"`
FilePath string `db:"file_path" json:"file_path"`
FormatGroup string `db:"format_group" json:"format_group"`
LibraryTypeName string `db:"library_type_name" json:"library_type_name"`
}
func (q *Queries) ListProcessingIssuesByLibrary(ctx context.Context, libraryID pgtype.UUID) ([]ListProcessingIssuesByLibraryRow, error) {
rows, err := q.db.Query(ctx, ListProcessingIssuesByLibrary, libraryID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListProcessingIssuesByLibraryRow{}
for rows.Next() {
var i ListProcessingIssuesByLibraryRow
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.IssueType,
&i.IssueDescription,
&i.Severity,
&i.Resolved,
&i.ResolvedAt,
&i.CreatedAt,
&i.Title,
&i.FilePath,
&i.FormatGroup,
&i.LibraryTypeName,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ListSyncConflictsByMediaItem = `-- name: ListSyncConflictsByMediaItem :many
SELECT id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at FROM sync_conflicts
WHERE media_item_id = $1 AND user_id = $2
ORDER BY created_at DESC
`
type ListSyncConflictsByMediaItemParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) ListSyncConflictsByMediaItem(ctx context.Context, arg ListSyncConflictsByMediaItemParams) ([]SyncConflicts, error) {
rows, err := q.db.Query(ctx, ListSyncConflictsByMediaItem, arg.MediaItemID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SyncConflicts{}
for rows.Next() {
var i SyncConflicts
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.ConflictType,
&i.ConflictData,
&i.ResolutionStatus,
&i.ResolutionData,
&i.ResolvedBy,
&i.ResolvedAt,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ListSyncConflictsByUser = `-- name: ListSyncConflictsByUser :many
SELECT sc.id, sc.media_item_id, sc.user_id, sc.conflict_type, sc.conflict_data, sc.resolution_status, sc.resolution_data, sc.resolved_by, sc.resolved_at, sc.created_at, mi.title, mi.author
FROM sync_conflicts sc
JOIN media_items mi ON sc.media_item_id = mi.id
WHERE sc.user_id = $1 AND sc.resolution_status = 'unresolved'
ORDER BY sc.created_at DESC
`
type ListSyncConflictsByUserRow struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
ConflictType string `db:"conflict_type" json:"conflict_type"`
ConflictData []byte `db:"conflict_data" json:"conflict_data"`
ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
ResolutionData []byte `db:"resolution_data" json:"resolution_data"`
ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"`
ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
}
func (q *Queries) ListSyncConflictsByUser(ctx context.Context, userID pgtype.UUID) ([]ListSyncConflictsByUserRow, error) {
rows, err := q.db.Query(ctx, ListSyncConflictsByUser, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListSyncConflictsByUserRow{}
for rows.Next() {
var i ListSyncConflictsByUserRow
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.ConflictType,
&i.ConflictData,
&i.ResolutionStatus,
&i.ResolutionData,
&i.ResolvedBy,
&i.ResolvedAt,
&i.CreatedAt,
&i.Title,
&i.Author,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ListUnresolvedUnlinkedBooks = `-- name: ListUnresolvedUnlinkedBooks :many
SELECT ub.id, ub.device_id, ub.content_id, ub.file_path, ub.title, ub.author, ub.confidence_score, ub.resolved, ub.media_item_id, ub.resolved_at, ub.resolution_method, ub.last_seen_at, ub.created_at, d.device_name, d.device_type
FROM unlinked_books ub
JOIN devices d ON ub.device_id = d.id
WHERE ub.resolved = false
ORDER BY ub.last_seen_at DESC
LIMIT $1 OFFSET $2
`
type ListUnresolvedUnlinkedBooksParams struct {
Limit int32 `db:"limit" json:"limit"`
Offset int32 `db:"offset" json:"offset"`
}
type ListUnresolvedUnlinkedBooksRow struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
ContentID string `db:"content_id" json:"content_id"`
FilePath pgtype.Text `db:"file_path" json:"file_path"`
Title pgtype.Text `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
Resolved pgtype.Bool `db:"resolved" json:"resolved"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"`
LastSeenAt pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
DeviceName string `db:"device_name" json:"device_name"`
DeviceType string `db:"device_type" json:"device_type"`
}
// List unresolved unlinked books with pagination
func (q *Queries) ListUnresolvedUnlinkedBooks(ctx context.Context, arg ListUnresolvedUnlinkedBooksParams) ([]ListUnresolvedUnlinkedBooksRow, error) {
rows, err := q.db.Query(ctx, ListUnresolvedUnlinkedBooks, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListUnresolvedUnlinkedBooksRow{}
for rows.Next() {
var i ListUnresolvedUnlinkedBooksRow
if err := rows.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
&i.DeviceName,
&i.DeviceType,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ListUsers = `-- name: ListUsers :many
SELECT
u.id,
u.email,
u.username,
u.theme,
u.first_name,
u.last_name,
u.role,
u.max_devices,
u.created_at,
u.updated_at,
(SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
FROM users u
ORDER BY u.created_at DESC
`
type ListUsersRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Theme pgtype.Text `db:"theme" json:"theme"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
Role string `db:"role" json:"role"`
MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
DeviceCount int64 `db:"device_count" json:"device_count"`
}
func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) {
rows, err := q.db.Query(ctx, ListUsers)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListUsersRow{}
for rows.Next() {
var i ListUsersRow
if err := rows.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Theme,
&i.FirstName,
&i.LastName,
&i.Role,
&i.MaxDevices,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeviceCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const PurgeExpiredBookmarkTombstones = `-- name: PurgeExpiredBookmarkTombstones :exec
DELETE FROM media_bookmarks WHERE deleted = TRUE AND deleted_at < $1
`
func (q *Queries) PurgeExpiredBookmarkTombstones(ctx context.Context, deletedAt pgtype.Timestamptz) error {
_, err := q.db.Exec(ctx, PurgeExpiredBookmarkTombstones, deletedAt)
return err
}
const PurgeExpiredHighlightTombstones = `-- name: PurgeExpiredHighlightTombstones :exec
DELETE FROM media_highlights WHERE deleted = TRUE AND deleted_at < $1
`
func (q *Queries) PurgeExpiredHighlightTombstones(ctx context.Context, deletedAt pgtype.Timestamptz) error {
_, err := q.db.Exec(ctx, PurgeExpiredHighlightTombstones, deletedAt)
return err
}
const PurgeExpiredNoteTombstones = `-- name: PurgeExpiredNoteTombstones :exec
DELETE FROM media_notes WHERE deleted = TRUE AND deleted_at < $1
`
func (q *Queries) PurgeExpiredNoteTombstones(ctx context.Context, deletedAt pgtype.Timestamptz) error {
_, err := q.db.Exec(ctx, PurgeExpiredNoteTombstones, deletedAt)
return err
}
const QueryMediaItemsByIdentifiers = `-- name: QueryMediaItemsByIdentifiers :many
SELECT
mi.id,
mi.file_sha256,
mi.opf_identifier,
mi.opf_uuid,
mi.isbn,
mi.asin,
mi.title,
mi.author,
mi.file_size,
mi.hash_confidence,
CASE
WHEN $1::uuid IS NOT NULL AND mi.id = $1::uuid THEN 1.0
WHEN mi.opf_uuid IS NOT NULL AND mi.opf_uuid = $2::text THEN 0.95
WHEN mi.file_sha256 IS NOT NULL AND mi.file_sha256 = $3::text THEN 0.9
WHEN mi.opf_identifier IS NOT NULL AND mi.opf_identifier = $4::text THEN 0.85
WHEN mi.isbn IS NOT NULL AND mi.isbn = $5::text THEN 0.8
WHEN mi.asin IS NOT NULL AND mi.asin = $6::text THEN 0.8
ELSE 0.5
END as confidence_score
FROM media_items mi
WHERE
($1::uuid IS NULL OR mi.id = $1::uuid)
OR ($2::text IS NULL OR mi.opf_uuid = $2::text)
OR ($3::text IS NULL OR mi.file_sha256 = $3::text)
OR ($4::text IS NULL OR mi.opf_identifier = $4::text)
OR ($5::text IS NULL OR mi.isbn = $5::text)
OR ($6::text IS NULL OR mi.asin = $6::text)
OR ($7::text IS NULL OR mi.title ILIKE '%' || $7::text || '%')
ORDER BY confidence_score DESC
`
type QueryMediaItemsByIdentifiersParams struct {
Column1 pgtype.UUID `db:"column_1" json:"column_1"`
Column2 string `db:"column_2" json:"column_2"`
Column3 string `db:"column_3" json:"column_3"`
Column4 string `db:"column_4" json:"column_4"`
Column5 string `db:"column_5" json:"column_5"`
Column6 string `db:"column_6" json:"column_6"`
Column7 string `db:"column_7" json:"column_7"`
}
type QueryMediaItemsByIdentifiersRow struct {
ID pgtype.UUID `db:"id" json:"id"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Asin pgtype.Text `db:"asin" json:"asin"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
ConfidenceScore float64 `db:"confidence_score" json:"confidence_score"`
}
// Query media items by multiple identifiers with confidence scoring
func (q *Queries) QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMediaItemsByIdentifiersParams) ([]QueryMediaItemsByIdentifiersRow, error) {
rows, err := q.db.Query(ctx, QueryMediaItemsByIdentifiers,
arg.Column1,
arg.Column2,
arg.Column3,
arg.Column4,
arg.Column5,
arg.Column6,
arg.Column7,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []QueryMediaItemsByIdentifiersRow{}
for rows.Next() {
var i QueryMediaItemsByIdentifiersRow
if err := rows.Scan(
&i.ID,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.Isbn,
&i.Asin,
&i.Title,
&i.Author,
&i.FileSize,
&i.HashConfidence,
&i.ConfidenceScore,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ReassignLibraries = `-- name: ReassignLibraries :exec
UPDATE libraries SET created_by_admin_id = $2, updated_at = NOW() WHERE created_by_admin_id = $1
`
type ReassignLibrariesParams struct {
CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"`
CreatedByAdminID_2 pgtype.UUID `db:"created_by_admin_id_2" json:"created_by_admin_id_2"`
}
func (q *Queries) ReassignLibraries(ctx context.Context, arg ReassignLibrariesParams) error {
_, err := q.db.Exec(ctx, ReassignLibraries, arg.CreatedByAdminID, arg.CreatedByAdminID_2)
return err
}
const ReassignMediaItems = `-- name: ReassignMediaItems :exec
UPDATE media_items SET added_by_admin_id = $2 WHERE added_by_admin_id = $1
`
type ReassignMediaItemsParams struct {
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
AddedByAdminID_2 pgtype.UUID `db:"added_by_admin_id_2" json:"added_by_admin_id_2"`
}
func (q *Queries) ReassignMediaItems(ctx context.Context, arg ReassignMediaItemsParams) error {
_, err := q.db.Exec(ctx, ReassignMediaItems, arg.AddedByAdminID, arg.AddedByAdminID_2)
return err
}
const RemoveBookFromCollection = `-- name: RemoveBookFromCollection :exec
DELETE FROM collection_items WHERE collection_id = $1 AND media_item_id = $2
`
type RemoveBookFromCollectionParams struct {
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
// Remove book from collection
func (q *Queries) RemoveBookFromCollection(ctx context.Context, arg RemoveBookFromCollectionParams) error {
_, err := q.db.Exec(ctx, RemoveBookFromCollection, arg.CollectionID, arg.MediaItemID)
return err
}
const RemoveBookFromKoboShelf = `-- name: RemoveBookFromKoboShelf :exec
DELETE FROM kobo_shelves WHERE device_id = $1 AND media_item_id = $2
`
type RemoveBookFromKoboShelfParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
func (q *Queries) RemoveBookFromKoboShelf(ctx context.Context, arg RemoveBookFromKoboShelfParams) error {
_, err := q.db.Exec(ctx, RemoveBookFromKoboShelf, arg.DeviceID, arg.MediaItemID)
return err
}
const ResetSystemCollectionMetadata = `-- name: ResetSystemCollectionMetadata :exec
UPDATE collections
SET description = $3,
icon = $4,
color = $5,
priority = $6
WHERE user_id = $1
AND name = $2
AND is_system_collection = true
`
type ResetSystemCollectionMetadataParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
Icon pgtype.Text `db:"icon" json:"icon"`
Color pgtype.Text `db:"color" json:"color"`
Priority pgtype.Int4 `db:"priority" json:"priority"`
}
func (q *Queries) ResetSystemCollectionMetadata(ctx context.Context, arg ResetSystemCollectionMetadataParams) error {
_, err := q.db.Exec(ctx, ResetSystemCollectionMetadata,
arg.UserID,
arg.Name,
arg.Description,
arg.Icon,
arg.Color,
arg.Priority,
)
return err
}
const ResolveProcessingIssue = `-- name: ResolveProcessingIssue :one
UPDATE processing_issues
SET resolved = true,
resolved_at = NOW()
WHERE id = $1
AND media_item_id = $2
RETURNING id, media_item_id, library_id, issue_type, issue_description, severity, resolved, resolved_at, created_at
`
type ResolveProcessingIssueParams struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
func (q *Queries) ResolveProcessingIssue(ctx context.Context, arg ResolveProcessingIssueParams) (ProcessingIssues, error) {
row := q.db.QueryRow(ctx, ResolveProcessingIssue, arg.ID, arg.MediaItemID)
var i ProcessingIssues
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.LibraryID,
&i.IssueType,
&i.IssueDescription,
&i.Severity,
&i.Resolved,
&i.ResolvedAt,
&i.CreatedAt,
)
return i, err
}
const ResolveSyncConflict = `-- name: ResolveSyncConflict :one
UPDATE sync_conflicts
SET
resolution_status = $2,
resolution_data = $3,
resolved_by = $4,
resolved_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at
`
type ResolveSyncConflictParams struct {
ID pgtype.UUID `db:"id" json:"id"`
ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
ResolutionData []byte `db:"resolution_data" json:"resolution_data"`
ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"`
}
func (q *Queries) ResolveSyncConflict(ctx context.Context, arg ResolveSyncConflictParams) (SyncConflicts, error) {
row := q.db.QueryRow(ctx, ResolveSyncConflict,
arg.ID,
arg.ResolutionStatus,
arg.ResolutionData,
arg.ResolvedBy,
)
var i SyncConflicts
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.ConflictType,
&i.ConflictData,
&i.ResolutionStatus,
&i.ResolutionData,
&i.ResolvedBy,
&i.ResolvedAt,
&i.CreatedAt,
)
return i, err
}
const ResolveUnlinkedBook = `-- name: ResolveUnlinkedBook :one
UPDATE unlinked_books
SET
resolved = true,
media_item_id = $2,
resolved_at = NOW(),
resolution_method = $3
WHERE id = $1
RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at
`
type ResolveUnlinkedBookParams struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"`
}
// Resolve unlinked book
func (q *Queries) ResolveUnlinkedBook(ctx context.Context, arg ResolveUnlinkedBookParams) (UnlinkedBooks, error) {
row := q.db.QueryRow(ctx, ResolveUnlinkedBook, arg.ID, arg.MediaItemID, arg.ResolutionMethod)
var i UnlinkedBooks
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.ContentID,
&i.FilePath,
&i.Title,
&i.Author,
&i.ConfidenceScore,
&i.Resolved,
&i.MediaItemID,
&i.ResolvedAt,
&i.ResolutionMethod,
&i.LastSeenAt,
&i.CreatedAt,
)
return i, err
}
const RevokeAllUserRefreshTokens = `-- name: RevokeAllUserRefreshTokens :exec
UPDATE refresh_tokens SET revoked_at = NOW() WHERE user_id = $1 AND revoked_at IS NULL
`
func (q *Queries) RevokeAllUserRefreshTokens(ctx context.Context, userID pgtype.UUID) error {
_, err := q.db.Exec(ctx, RevokeAllUserRefreshTokens, userID)
return err
}
const RevokeDevice = `-- name: RevokeDevice :exec
UPDATE devices
SET
auth_token = NULL,
sync_enabled = false,
updated_at = NOW()
WHERE id = $1
`
func (q *Queries) RevokeDevice(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, RevokeDevice, id)
return err
}
const RevokeOpdsToken = `-- name: RevokeOpdsToken :exec
DELETE FROM opds_tokens WHERE token = $1
`
// Revoke OPDS token
func (q *Queries) RevokeOpdsToken(ctx context.Context, token string) error {
_, err := q.db.Exec(ctx, RevokeOpdsToken, token)
return err
}
const RevokeRefreshToken = `-- name: RevokeRefreshToken :exec
UPDATE refresh_tokens SET revoked_at = NOW() WHERE token = $1
`
func (q *Queries) RevokeRefreshToken(ctx context.Context, token pgtype.UUID) error {
_, err := q.db.Exec(ctx, RevokeRefreshToken, token)
return err
}
const SearchAuthorValues = `-- name: SearchAuthorValues :many
SELECT
mi.author as value,
COUNT(*) as count,
word_similarity($1, COALESCE(mi.author, ''))::float8 as score
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $2
WHERE COALESCE(lv.is_visible, true) = true
AND mi.library_id = $3
AND word_similarity($1, COALESCE(mi.author, '')) > 0.3
AND mi.author IS NOT NULL
AND mi.author != ''
GROUP BY mi.author, word_similarity($1, COALESCE(mi.author, ''))::float8
ORDER BY score DESC, count DESC
LIMIT $5 OFFSET $4
`
type SearchAuthorValuesParams struct {
SearchQuery pgtype.Text `db:"search_query" json:"search_query"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchAuthorValuesRow struct {
Value pgtype.Text `db:"value" json:"value"`
Count int64 `db:"count" json:"count"`
Score float64 `db:"score" json:"score"`
}
func (q *Queries) SearchAuthorValues(ctx context.Context, arg SearchAuthorValuesParams) ([]SearchAuthorValuesRow, error) {
rows, err := q.db.Query(ctx, SearchAuthorValues,
arg.SearchQuery,
arg.UserID,
arg.LibraryID,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchAuthorValuesRow{}
for rows.Next() {
var i SearchAuthorValuesRow
if err := rows.Scan(&i.Value, &i.Count, &i.Score); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchGenreValues = `-- name: SearchGenreValues :many
SELECT
mi.genre as value,
COUNT(*) as count,
word_similarity($1, COALESCE(mi.genre, ''))::float8 as score
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $2
WHERE COALESCE(lv.is_visible, true) = true
AND mi.library_id = $3
AND word_similarity($1, COALESCE(mi.genre, '')) > 0.3
AND mi.genre IS NOT NULL
AND mi.genre != ''
GROUP BY mi.genre, word_similarity($1, COALESCE(mi.genre, ''))::float8
ORDER BY score DESC, count DESC
LIMIT $5 OFFSET $4
`
type SearchGenreValuesParams struct {
SearchQuery pgtype.Text `db:"search_query" json:"search_query"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchGenreValuesRow struct {
Value pgtype.Text `db:"value" json:"value"`
Count int64 `db:"count" json:"count"`
Score float64 `db:"score" json:"score"`
}
func (q *Queries) SearchGenreValues(ctx context.Context, arg SearchGenreValuesParams) ([]SearchGenreValuesRow, error) {
rows, err := q.db.Query(ctx, SearchGenreValues,
arg.SearchQuery,
arg.UserID,
arg.LibraryID,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchGenreValuesRow{}
for rows.Next() {
var i SearchGenreValuesRow
if err := rows.Scan(&i.Value, &i.Count, &i.Score); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchLanguageValues = `-- name: SearchLanguageValues :many
SELECT
mi.language as value,
COUNT(*) as count,
word_similarity($1, COALESCE(mi.language, ''))::float8 as score
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $2
WHERE COALESCE(lv.is_visible, true) = true
AND mi.library_id = $3
AND word_similarity($1, COALESCE(mi.language, '')) > 0.3
AND mi.language IS NOT NULL
AND mi.language != ''
GROUP BY mi.language, word_similarity($1, COALESCE(mi.language, ''))::float8
ORDER BY score DESC, count DESC
LIMIT $5 OFFSET $4
`
type SearchLanguageValuesParams struct {
SearchQuery pgtype.Text `db:"search_query" json:"search_query"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchLanguageValuesRow struct {
Value pgtype.Text `db:"value" json:"value"`
Count int64 `db:"count" json:"count"`
Score float64 `db:"score" json:"score"`
}
func (q *Queries) SearchLanguageValues(ctx context.Context, arg SearchLanguageValuesParams) ([]SearchLanguageValuesRow, error) {
rows, err := q.db.Query(ctx, SearchLanguageValues,
arg.SearchQuery,
arg.UserID,
arg.LibraryID,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchLanguageValuesRow{}
for rows.Next() {
var i SearchLanguageValuesRow
if err := rows.Scan(&i.Value, &i.Count, &i.Score); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
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.imported_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.library_type_name, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
WHERE COALESCE(lv.is_visible, true) = true
AND ($2::uuid IS NULL OR mi.library_id = $2::uuid)
AND (
mi.title ILIKE $3 OR
mi.author ILIKE $3 OR
mi.series ILIKE $3 OR
$3 = ANY(mi.tags_search) OR
$3 = ANY(mi.contributors_search)
)
ORDER BY
CASE
WHEN mi.title ILIKE $3 THEN 1
WHEN mi.author ILIKE $3 THEN 2
WHEN mi.series ILIKE $3 THEN 3
WHEN $3 = ANY(mi.tags_search) THEN 4
ELSE 5
END,
mi.title ASC
LIMIT $5 OFFSET $4
`
type SearchMediaItemsParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
SearchPattern pgtype.Text `db:"search_pattern" json:"search_pattern"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchMediaItemsRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
ImportedAt pgtype.Timestamptz `db:"imported_at" json:"imported_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
LibraryTypeName pgtype.Text `db:"library_type_name" json:"library_type_name"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
LibraryName string `db:"library_name" json:"library_name"`
LibraryTypeName_2 string `db:"library_type_name_2" json:"library_type_name_2"`
}
// Search Media Items queries
func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsParams) ([]SearchMediaItemsRow, error) {
rows, err := q.db.Query(ctx, SearchMediaItems,
arg.UserID,
arg.LibraryID,
arg.SearchPattern,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchMediaItemsRow{}
for rows.Next() {
var i SearchMediaItemsRow
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.LibraryName,
&i.LibraryTypeName_2,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchMediaItemsUnified = `-- name: SearchMediaItemsUnified :many
SELECT
mi.id,
mi.library_id,
mi.title,
mi.author,
mi.isbn,
mi.description,
mi.file_path,
mi.file_size,
mi.mime_type,
mi.cover_image_path,
mi.series,
mi.series_number,
mi.tags,
mi.asin,
mi.date_published,
mi.publisher,
mi.contributors,
mi.language,
mi.edition,
mi.page_count,
mi.genre,
mi.copyright_year,
mi.goodreads_id,
mi.openlibrary_id,
mi.google_books_id,
mi.added_by_admin_id,
mi.created_at,
mi.updated_at,
mi.format_group,
mi.format_mimetype,
mi.is_reflowable,
mi.has_fixed_layout,
mi.total_characters,
mi.chapter_count,
mi.entitlement_id,
mi.revision_number,
mi.kobo_content_id,
mi.kobo_metadata,
mi.tags_search,
mi.contributors_search,
mi.file_sha256,
mi.opf_identifier,
mi.opf_uuid,
mi.hash_confidence,
l.name as library_name,
lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
WHERE COALESCE(lv.is_visible, true) = true
AND ($2::uuid IS NULL
OR mi.library_id = $2::uuid)
-- Fuzzy author filter
AND ($3 = '' OR word_similarity($3, COALESCE(mi.author, '')) > 0.3)
-- Fuzzy series filter
AND ($4 = '' OR word_similarity($4, COALESCE(mi.series, '')) > 0.3)
-- Fuzzy genre filter
AND ($5 = '' OR word_similarity($5, COALESCE(mi.genre, '')) > 0.3)
-- Fuzzy language filter
AND ($6 = '' OR word_similarity($6, COALESCE(mi.language, '')) > 0.3)
-- Tags filter (NEW - fuzzy match against tags array)
AND ($7 = '' OR EXISTS (
SELECT 1 FROM unnest(mi.tags_search) AS tag
WHERE word_similarity($7, tag) > 0.3
))
-- Year range (exact) - prioritize date_published, fallback to copyright_year
AND (
$8 = 0 OR
EXTRACT(YEAR FROM mi.date_published) >= $8 OR
(mi.date_published IS NULL AND mi.copyright_year >= $8)
)
AND (
$9 = 0 OR
EXTRACT(YEAR FROM mi.date_published) <= $9 OR
(mi.date_published IS NULL AND mi.copyright_year <= $9)
)
-- Boolean (exact)
AND (
$10::bool IS NULL OR -- Not specified = show all
($10::bool IS TRUE AND mi.cover_image_path IS NOT NULL) OR
($10::bool IS FALSE AND mi.cover_image_path IS NULL)
)
-- Search query (fuzzy or exact based on quotes)
AND (
$11 = '' OR
-- Fuzzy search (default)
$12 = false AND (
word_similarity($11, mi.title) > 0.3 OR
word_similarity($11, COALESCE(mi.author, '')) > 0.3 OR
word_similarity($11, COALESCE(mi.series, '')) > 0.3 OR
EXISTS (
SELECT 1 FROM unnest(mi.tags_search) AS tag
WHERE word_similarity($11, tag) > 0.3
LIMIT 1
) OR
EXISTS (
SELECT 1 FROM unnest(mi.contributors_search) AS contributor
WHERE word_similarity($11, contributor) > 0.3
LIMIT 1
)
) OR
-- Exact search (with quotes)
-- Keeping old pattern commented out in case we want wildcard exact back. See search.go line 62
-- sqlc.narg('is_exact_search') = true AND (
-- mi.title ILIKE sqlc.narg('search_pattern') OR
-- mi.author ILIKE sqlc.narg('search_pattern') OR
-- mi.series ILIKE sqlc.narg('search_pattern') OR
-- sqlc.narg('search_pattern') = ANY(mi.tags_search) OR
-- sqlc.narg('search_pattern') = ANY(mi.contributors_search)
-- )
-- Exact search (with quotes) - true exact match, not substring
$12 = true AND (
mi.title = $11 OR
COALESCE(mi.author, '') = $11 OR
COALESCE(mi.series, '') = $11 OR
$11 = ANY(mi.tags_search) OR
$11 = ANY(mi.contributors_search)
)
)
ORDER BY
-- Primary sort: relevance score when searching
CASE
WHEN $11 != '' THEN
GREATEST(
CASE WHEN $12 = false THEN
word_similarity($11, mi.title)
ELSE 0 END,
CASE WHEN $12 = false THEN
word_similarity($11, COALESCE(mi.author, ''))
ELSE 0 END,
word_similarity($3, COALESCE(mi.author, '')),
word_similarity($5, COALESCE(mi.genre, '')),
(SELECT MAX(word_similarity($7, tag))
FROM unnest(mi.tags_search) AS tag)
)
ELSE 0
END DESC,
-- Secondary sort: user-specified sort parameter
CASE
WHEN $13 = 'title ASC' THEN mi.title
ELSE ''
END ASC,
CASE
WHEN $13 = 'title DESC' THEN mi.title
ELSE ''
END DESC,
CASE
WHEN $13 = 'author ASC' THEN COALESCE(mi.author, '')
ELSE ''
END ASC,
CASE
WHEN $13 = 'author DESC' THEN COALESCE(mi.author, '')
ELSE ''
END DESC,
CASE
WHEN $13 = 'created_at ASC' THEN mi.created_at
ELSE '1970-01-01'::timestamp
END ASC,
CASE
WHEN $13 = 'created_at DESC' THEN mi.created_at
ELSE '1970-01-01'::timestamp
END DESC,
CASE
WHEN $13 = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0')
ELSE ''
END ASC,
CASE
WHEN $13 = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0')
ELSE ''
END DESC,
-- Tertiary sort: title (default fallback)
mi.title ASC
LIMIT $15 OFFSET $14
`
type SearchMediaItemsUnifiedParams 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"`
TagsFilter interface{} `db:"tags_filter" json:"tags_filter"`
YearMin interface{} `db:"year_min" json:"year_min"`
YearMax interface{} `db:"year_max" json:"year_max"`
HasCover pgtype.Bool `db:"has_cover" json:"has_cover"`
SearchQuery interface{} `db:"search_query" json:"search_query"`
IsExactSearch interface{} `db:"is_exact_search" json:"is_exact_search"`
Sort interface{} `db:"sort" json:"sort"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchMediaItemsUnifiedRow struct {
ID pgtype.UUID `db:"id" json:"id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
FilePath string `db:"file_path" json:"file_path"`
FileSize pgtype.Int8 `db:"file_size" json:"file_size"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
AddedByAdminID pgtype.UUID `db:"added_by_admin_id" json:"added_by_admin_id"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
LibraryName string `db:"library_name" json:"library_name"`
LibraryTypeName string `db:"library_type_name" json:"library_type_name"`
}
func (q *Queries) SearchMediaItemsUnified(ctx context.Context, arg SearchMediaItemsUnifiedParams) ([]SearchMediaItemsUnifiedRow, error) {
rows, err := q.db.Query(ctx, SearchMediaItemsUnified,
arg.UserID,
arg.LibraryID,
arg.AuthorFilter,
arg.SeriesFilter,
arg.GenreFilter,
arg.LanguageFilter,
arg.TagsFilter,
arg.YearMin,
arg.YearMax,
arg.HasCover,
arg.SearchQuery,
arg.IsExactSearch,
arg.Sort,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchMediaItemsUnifiedRow{}
for rows.Next() {
var i SearchMediaItemsUnifiedRow
if err := rows.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
&i.LibraryName,
&i.LibraryTypeName,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchSeriesValues = `-- name: SearchSeriesValues :many
SELECT
mi.series as value,
COUNT(*) as count,
word_similarity($1, COALESCE(mi.series, ''))::float8 as score
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $2
WHERE COALESCE(lv.is_visible, true) = true
AND mi.library_id = $3
AND word_similarity($1, COALESCE(mi.series, '')) > 0.3
AND mi.series IS NOT NULL
AND mi.series != ''
GROUP BY mi.series, word_similarity($1, COALESCE(mi.series, ''))::float8
ORDER BY score DESC, count DESC
LIMIT $5 OFFSET $4
`
type SearchSeriesValuesParams struct {
SearchQuery pgtype.Text `db:"search_query" json:"search_query"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchSeriesValuesRow struct {
Value pgtype.Text `db:"value" json:"value"`
Count int64 `db:"count" json:"count"`
Score float64 `db:"score" json:"score"`
}
func (q *Queries) SearchSeriesValues(ctx context.Context, arg SearchSeriesValuesParams) ([]SearchSeriesValuesRow, error) {
rows, err := q.db.Query(ctx, SearchSeriesValues,
arg.SearchQuery,
arg.UserID,
arg.LibraryID,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchSeriesValuesRow{}
for rows.Next() {
var i SearchSeriesValuesRow
if err := rows.Scan(&i.Value, &i.Count, &i.Score); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchTagsValues = `-- name: SearchTagsValues :many
SELECT
tag::TEXT as value,
COUNT(*) as count,
word_similarity($1, tag)::float8 as score
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $2
CROSS JOIN LATERAL unnest(mi.tags_search) AS tag
WHERE COALESCE(lv.is_visible, true) = true
AND ($3::uuid IS NULL OR mi.library_id = $3::uuid)
AND tag IS NOT NULL
AND word_similarity($1, tag) > 0.3
GROUP BY tag, word_similarity($1, tag)::float8
ORDER BY word_similarity($1, tag)::float8 DESC, COUNT DESC
LIMIT $5 OFFSET $4
`
type SearchTagsValuesParams struct {
SearchQuery pgtype.Text `db:"search_query" json:"search_query"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
Offset pgtype.Int4 `db:"offset" json:"offset"`
Limit pgtype.Int4 `db:"limit" json:"limit"`
}
type SearchTagsValuesRow struct {
Value string `db:"value" json:"value"`
Count int64 `db:"count" json:"count"`
Score float64 `db:"score" json:"score"`
}
func (q *Queries) SearchTagsValues(ctx context.Context, arg SearchTagsValuesParams) ([]SearchTagsValuesRow, error) {
rows, err := q.db.Query(ctx, SearchTagsValues,
arg.SearchQuery,
arg.UserID,
arg.LibraryID,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchTagsValuesRow{}
for rows.Next() {
var i SearchTagsValuesRow
if err := rows.Scan(&i.Value, &i.Count, &i.Score); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SetLibraryVisibility = `-- name: SetLibraryVisibility :one
INSERT INTO library_visibility (user_id, library_id, is_visible)
VALUES ($1, $2, $3)
ON CONFLICT (user_id, library_id)
DO UPDATE SET
is_visible = EXCLUDED.is_visible,
updated_at = NOW()
RETURNING id, user_id, library_id, is_visible, created_at, updated_at
`
type SetLibraryVisibilityParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
IsVisible bool `db:"is_visible" json:"is_visible"`
}
// Library Visibility queries
func (q *Queries) SetLibraryVisibility(ctx context.Context, arg SetLibraryVisibilityParams) (LibraryVisibility, error) {
row := q.db.QueryRow(ctx, SetLibraryVisibility, arg.UserID, arg.LibraryID, arg.IsVisible)
var i LibraryVisibility
err := row.Scan(
&i.ID,
&i.UserID,
&i.LibraryID,
&i.IsVisible,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const SetSystemConfig = `-- name: SetSystemConfig :one
INSERT INTO system_config (key, value, updated_by)
VALUES ($1, $2, $3)
ON CONFLICT (key)
DO UPDATE SET
value = EXCLUDED.value,
updated_by = EXCLUDED.updated_by,
updated_at = NOW()
RETURNING key, value, updated_at, updated_by
`
type SetSystemConfigParams struct {
Key string `db:"key" json:"key"`
Value string `db:"value" json:"value"`
UpdatedBy pgtype.UUID `db:"updated_by" json:"updated_by"`
}
// Set system config
func (q *Queries) SetSystemConfig(ctx context.Context, arg SetSystemConfigParams) (SystemConfig, error) {
row := q.db.QueryRow(ctx, SetSystemConfig, arg.Key, arg.Value, arg.UpdatedBy)
var i SystemConfig
err := row.Scan(
&i.Key,
&i.Value,
&i.UpdatedAt,
&i.UpdatedBy,
)
return i, err
}
const SyncLibraryTypeExtensions = `-- name: SyncLibraryTypeExtensions :exec
UPDATE library_types SET allowed_extensions = $2 WHERE name = $1
`
type SyncLibraryTypeExtensionsParams struct {
Name string `db:"name" json:"name"`
AllowedExtensions []string `db:"allowed_extensions" json:"allowed_extensions"`
}
func (q *Queries) SyncLibraryTypeExtensions(ctx context.Context, arg SyncLibraryTypeExtensionsParams) error {
_, err := q.db.Exec(ctx, SyncLibraryTypeExtensions, arg.Name, arg.AllowedExtensions)
return err
}
const TombstoneMediaBookmarkByDedupKey = `-- name: TombstoneMediaBookmarkByDedupKey :exec
UPDATE media_bookmarks SET
deleted = TRUE,
deleted_at = NOW(),
last_modified_at = NOW()
WHERE user_id = $1 AND media_item_id = $2 AND dedup_key = $3 AND deleted = FALSE
`
type TombstoneMediaBookmarkByDedupKeyParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
}
func (q *Queries) TombstoneMediaBookmarkByDedupKey(ctx context.Context, arg TombstoneMediaBookmarkByDedupKeyParams) error {
_, err := q.db.Exec(ctx, TombstoneMediaBookmarkByDedupKey, arg.UserID, arg.MediaItemID, arg.DedupKey)
return err
}
const TombstoneMediaBookmarkByID = `-- name: TombstoneMediaBookmarkByID :exec
UPDATE media_bookmarks SET
deleted = TRUE,
deleted_at = NOW(),
last_modified_at = NOW()
WHERE id = $1
`
func (q *Queries) TombstoneMediaBookmarkByID(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, TombstoneMediaBookmarkByID, id)
return err
}
const TombstoneMediaHighlightByDedupKey = `-- name: TombstoneMediaHighlightByDedupKey :exec
UPDATE media_highlights SET
deleted = TRUE,
deleted_at = NOW(),
last_modified_at = NOW()
WHERE user_id = $1 AND media_item_id = $2 AND dedup_key = $3 AND deleted = FALSE
`
type TombstoneMediaHighlightByDedupKeyParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
}
func (q *Queries) TombstoneMediaHighlightByDedupKey(ctx context.Context, arg TombstoneMediaHighlightByDedupKeyParams) error {
_, err := q.db.Exec(ctx, TombstoneMediaHighlightByDedupKey, arg.UserID, arg.MediaItemID, arg.DedupKey)
return err
}
const TombstoneMediaHighlightByID = `-- name: TombstoneMediaHighlightByID :exec
UPDATE media_highlights SET
deleted = TRUE,
deleted_at = NOW(),
last_modified_at = NOW()
WHERE id = $1
`
func (q *Queries) TombstoneMediaHighlightByID(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, TombstoneMediaHighlightByID, id)
return err
}
const TombstoneMediaNoteByDedupKey = `-- name: TombstoneMediaNoteByDedupKey :exec
UPDATE media_notes SET
deleted = TRUE,
deleted_at = NOW(),
last_modified_at = NOW()
WHERE user_id = $1 AND media_item_id = $2 AND dedup_key = $3 AND deleted = FALSE
`
type TombstoneMediaNoteByDedupKeyParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
DedupKey pgtype.Text `db:"dedup_key" json:"dedup_key"`
}
func (q *Queries) TombstoneMediaNoteByDedupKey(ctx context.Context, arg TombstoneMediaNoteByDedupKeyParams) error {
_, err := q.db.Exec(ctx, TombstoneMediaNoteByDedupKey, arg.UserID, arg.MediaItemID, arg.DedupKey)
return err
}
const TombstoneMediaNoteByID = `-- name: TombstoneMediaNoteByID :exec
UPDATE media_notes SET
deleted = TRUE,
deleted_at = NOW(),
last_modified_at = NOW()
WHERE id = $1
`
func (q *Queries) TombstoneMediaNoteByID(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, TombstoneMediaNoteByID, id)
return err
}
const UpdateCollection = `-- name: UpdateCollection :one
UPDATE collections
SET
name = $2,
description = $3,
color = $4,
icon = $5,
auto_assign_rules = $6,
view_settings = $7
WHERE id = $1
RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at
`
type UpdateCollectionParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
Color pgtype.Text `db:"color" json:"color"`
Icon pgtype.Text `db:"icon" json:"icon"`
AutoAssignRules []byte `db:"auto_assign_rules" json:"auto_assign_rules"`
ViewSettings []byte `db:"view_settings" json:"view_settings"`
}
// Update collection
func (q *Queries) UpdateCollection(ctx context.Context, arg UpdateCollectionParams) (Collections, error) {
row := q.db.QueryRow(ctx, UpdateCollection,
arg.ID,
arg.Name,
arg.Description,
arg.Color,
arg.Icon,
arg.AutoAssignRules,
arg.ViewSettings,
)
var i Collections
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Description,
&i.Color,
&i.Icon,
&i.AutoAssignRules,
&i.ViewSettings,
&i.ShowOnDashboard,
&i.QueryType,
&i.Priority,
&i.IsSystemCollection,
&i.CreatedAt,
)
return i, err
}
const UpdateDashboardPreferences = `-- name: UpdateDashboardPreferences :one
UPDATE user_dashboard_preferences
SET hidden_collections = $2,
collection_order = $3,
items_per_section = $4,
updated_at = NOW()
WHERE user_id = $1 AND library_id = $5
RETURNING id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at
`
type UpdateDashboardPreferencesParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
HiddenCollections []string `db:"hidden_collections" json:"hidden_collections"`
CollectionOrder []string `db:"collection_order" json:"collection_order"`
ItemsPerSection pgtype.Int4 `db:"items_per_section" json:"items_per_section"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}
func (q *Queries) UpdateDashboardPreferences(ctx context.Context, arg UpdateDashboardPreferencesParams) (UserDashboardPreferences, error) {
row := q.db.QueryRow(ctx, UpdateDashboardPreferences,
arg.UserID,
arg.HiddenCollections,
arg.CollectionOrder,
arg.ItemsPerSection,
arg.LibraryID,
)
var i UserDashboardPreferences
err := row.Scan(
&i.ID,
&i.UserID,
&i.LibraryID,
&i.HiddenCollections,
&i.CollectionOrder,
&i.ItemsPerSection,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateDevice = `-- name: UpdateDevice :one
UPDATE devices
SET
device_name = $2,
sync_enabled = $3,
auto_sync = $4,
sync_frequency_minutes = $5,
device_metadata = $6,
updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
type UpdateDeviceParams struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceName string `db:"device_name" json:"device_name"`
SyncEnabled pgtype.Bool `db:"sync_enabled" json:"sync_enabled"`
AutoSync pgtype.Bool `db:"auto_sync" json:"auto_sync"`
SyncFrequencyMinutes pgtype.Int4 `db:"sync_frequency_minutes" json:"sync_frequency_minutes"`
DeviceMetadata []byte `db:"device_metadata" json:"device_metadata"`
}
func (q *Queries) UpdateDevice(ctx context.Context, arg UpdateDeviceParams) (Devices, error) {
row := q.db.QueryRow(ctx, UpdateDevice,
arg.ID,
arg.DeviceName,
arg.SyncEnabled,
arg.AutoSync,
arg.SyncFrequencyMinutes,
arg.DeviceMetadata,
)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateDeviceAuthToken = `-- name: UpdateDeviceAuthToken :one
UPDATE devices
SET
auth_token = $2,
updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
type UpdateDeviceAuthTokenParams struct {
ID pgtype.UUID `db:"id" json:"id"`
AuthToken string `db:"auth_token" json:"auth_token"`
}
func (q *Queries) UpdateDeviceAuthToken(ctx context.Context, arg UpdateDeviceAuthTokenParams) (Devices, error) {
row := q.db.QueryRow(ctx, UpdateDeviceAuthToken, arg.ID, arg.AuthToken)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateDeviceCatalogAvailability = `-- name: UpdateDeviceCatalogAvailability :exec
UPDATE device_catalogs
SET available = $2
WHERE id = $1
`
type UpdateDeviceCatalogAvailabilityParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Available pgtype.Bool `db:"available" json:"available"`
}
// Update device catalog availability
func (q *Queries) UpdateDeviceCatalogAvailability(ctx context.Context, arg UpdateDeviceCatalogAvailabilityParams) error {
_, err := q.db.Exec(ctx, UpdateDeviceCatalogAvailability, arg.ID, arg.Available)
return err
}
const UpdateDeviceFileAlias = `-- name: UpdateDeviceFileAlias :one
UPDATE device_file_aliases
SET
media_item_id = $2,
file_sha256 = $3,
confidence_score = $4,
last_seen_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at
`
type UpdateDeviceFileAliasParams struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}
// Update device file alias
func (q *Queries) UpdateDeviceFileAlias(ctx context.Context, arg UpdateDeviceFileAliasParams) (DeviceFileAliases, error) {
row := q.db.QueryRow(ctx, UpdateDeviceFileAlias,
arg.ID,
arg.MediaItemID,
arg.FileSha256,
arg.ConfidenceScore,
)
var i DeviceFileAliases
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.DeviceID,
&i.FilePath,
&i.FileSha256,
&i.ConfidenceScore,
&i.LastSeenAt,
)
return i, err
}
const UpdateDeviceLastSeen = `-- name: UpdateDeviceLastSeen :one
UPDATE devices
SET
last_seen = NOW(),
updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
func (q *Queries) UpdateDeviceLastSeen(ctx context.Context, id pgtype.UUID) (Devices, error) {
row := q.db.QueryRow(ctx, UpdateDeviceLastSeen, id)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateDeviceLastSync = `-- name: UpdateDeviceLastSync :one
UPDATE devices
SET
last_sync = NOW(),
last_seen = NOW(),
updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
func (q *Queries) UpdateDeviceLastSync(ctx context.Context, id pgtype.UUID) (Devices, error) {
row := q.db.QueryRow(ctx, UpdateDeviceLastSync, id)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateDeviceShelfMapping = `-- name: UpdateDeviceShelfMapping :one
UPDATE device_shelf_mappings
SET
device_shelf_name = $2,
sync_direction = $3
WHERE id = $1
RETURNING id, collection_id, device_id, device_shelf_name, sync_direction, created_at
`
type UpdateDeviceShelfMappingParams struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"`
SyncDirection pgtype.Text `db:"sync_direction" json:"sync_direction"`
}
// Update device shelf mapping
func (q *Queries) UpdateDeviceShelfMapping(ctx context.Context, arg UpdateDeviceShelfMappingParams) (DeviceShelfMappings, error) {
row := q.db.QueryRow(ctx, UpdateDeviceShelfMapping, arg.ID, arg.DeviceShelfName, arg.SyncDirection)
var i DeviceShelfMappings
err := row.Scan(
&i.ID,
&i.CollectionID,
&i.DeviceID,
&i.DeviceShelfName,
&i.SyncDirection,
&i.CreatedAt,
)
return i, err
}
const UpdateDeviceSyncTimestamp = `-- name: UpdateDeviceSyncTimestamp :one
UPDATE devices
SET
last_sync = NOW(),
last_seen = NOW(),
updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`
func (q *Queries) UpdateDeviceSyncTimestamp(ctx context.Context, id pgtype.UUID) (Devices, error) {
row := q.db.QueryRow(ctx, UpdateDeviceSyncTimestamp, id)
var i Devices
err := row.Scan(
&i.ID,
&i.UserID,
&i.DeviceName,
&i.DeviceType,
&i.DeviceIdentifier,
&i.AuthToken,
&i.LastSync,
&i.LastSeen,
&i.SyncEnabled,
&i.AutoSync,
&i.SyncFrequencyMinutes,
&i.DeviceMetadata,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateDictionaryAccessed = `-- name: UpdateDictionaryAccessed :one
UPDATE dictionary_cache
SET accessed_at = NOW()
WHERE word = $1
RETURNING id, word, definition, part_of_speech, example, etymology, created_at, accessed_at
`
func (q *Queries) UpdateDictionaryAccessed(ctx context.Context, word string) (DictionaryCache, error) {
row := q.db.QueryRow(ctx, UpdateDictionaryAccessed, word)
var i DictionaryCache
err := row.Scan(
&i.ID,
&i.Word,
&i.Definition,
&i.PartOfSpeech,
&i.Example,
&i.Etymology,
&i.CreatedAt,
&i.AccessedAt,
)
return i, err
}
const UpdateEmail = `-- name: UpdateEmail :exec
UPDATE users SET email = $2, updated_at = NOW() WHERE id = $1
`
type UpdateEmailParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
}
func (q *Queries) UpdateEmail(ctx context.Context, arg UpdateEmailParams) error {
_, err := q.db.Exec(ctx, UpdateEmail, arg.ID, arg.Email)
return err
}
const UpdateKoboEntitlementRevision = `-- name: UpdateKoboEntitlementRevision :exec
UPDATE kobo_entitlements
SET revision_number = $3, updated_at = NOW()
WHERE device_id = $1 AND entitlement_id = $2
`
type UpdateKoboEntitlementRevisionParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
}
func (q *Queries) UpdateKoboEntitlementRevision(ctx context.Context, arg UpdateKoboEntitlementRevisionParams) error {
_, err := q.db.Exec(ctx, UpdateKoboEntitlementRevision, arg.DeviceID, arg.EntitlementID, arg.RevisionNumber)
return err
}
const UpdateKoboEntitlementStatus = `-- name: UpdateKoboEntitlementStatus :exec
UPDATE kobo_entitlements
SET book_status = $3, sync_status = 'synced', updated_at = NOW()
WHERE device_id = $1 AND entitlement_id = $2
`
type UpdateKoboEntitlementStatusParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
EntitlementID string `db:"entitlement_id" json:"entitlement_id"`
BookStatus pgtype.Text `db:"book_status" json:"book_status"`
}
func (q *Queries) UpdateKoboEntitlementStatus(ctx context.Context, arg UpdateKoboEntitlementStatusParams) error {
_, err := q.db.Exec(ctx, UpdateKoboEntitlementStatus, arg.DeviceID, arg.EntitlementID, arg.BookStatus)
return err
}
const UpdateKoboShelfBookPosition = `-- name: UpdateKoboShelfBookPosition :exec
UPDATE kobo_shelves
SET shelf_position = $3, last_synced_at = NOW()
WHERE device_id = $1 AND media_item_id = $2
`
type UpdateKoboShelfBookPositionParams struct {
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
}
func (q *Queries) UpdateKoboShelfBookPosition(ctx context.Context, arg UpdateKoboShelfBookPositionParams) error {
_, err := q.db.Exec(ctx, UpdateKoboShelfBookPosition, arg.DeviceID, arg.MediaItemID, arg.ShelfPosition)
return err
}
const UpdateKoboShelfCollection = `-- name: UpdateKoboShelfCollection :one
UPDATE kobo_shelves
SET
collection_id = $2,
position_in_collection = $3,
last_synced_at = NOW()
WHERE id = $1
RETURNING id, device_id, media_item_id, shelf_name, shelf_position, added_at, last_synced_at, collection_id, position_in_collection
`
type UpdateKoboShelfCollectionParams struct {
ID pgtype.UUID `db:"id" json:"id"`
CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"`
}
// Update Kobo shelves to support collections
func (q *Queries) UpdateKoboShelfCollection(ctx context.Context, arg UpdateKoboShelfCollectionParams) (KoboShelves, error) {
row := q.db.QueryRow(ctx, UpdateKoboShelfCollection, arg.ID, arg.CollectionID, arg.PositionInCollection)
var i KoboShelves
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.ShelfName,
&i.ShelfPosition,
&i.AddedAt,
&i.LastSyncedAt,
&i.CollectionID,
&i.PositionInCollection,
)
return i, err
}
const UpdateLibrary = `-- name: UpdateLibrary :one
UPDATE libraries SET
name = $2,
description = $3,
updated_at = NOW()
WHERE id = $1
RETURNING id, name, description, library_type_id, created_by_admin_id, created_at, updated_at
`
type UpdateLibraryParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description pgtype.Text `db:"description" json:"description"`
}
func (q *Queries) UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (Libraries, error) {
row := q.db.QueryRow(ctx, UpdateLibrary, arg.ID, arg.Name, arg.Description)
var i Libraries
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.LibraryTypeID,
&i.CreatedByAdminID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateMediaBookmark = `-- name: UpdateMediaBookmark :one
UPDATE media_bookmarks
SET
title = $2,
notes = $3,
position = $4,
updated_at = NOW()
WHERE id = $1 AND user_id = $5
RETURNING id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at
`
type UpdateMediaBookmarkParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Title string `db:"title" json:"title"`
Notes pgtype.Text `db:"notes" json:"notes"`
Position pgtype.Text `db:"position" json:"position"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) UpdateMediaBookmark(ctx context.Context, arg UpdateMediaBookmarkParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, UpdateMediaBookmark,
arg.ID,
arg.Title,
arg.Notes,
arg.Position,
arg.UserID,
)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const UpdateMediaBookmarkForSync = `-- name: UpdateMediaBookmarkForSync :one
UPDATE media_bookmarks SET
page_number = $2,
chapter_number = $3,
cfi_position = $4,
title = $5,
position = $6,
notes = $7,
percentage_location = $8,
epubcfi_location = $9,
chapter_reference = $10,
last_modified_at = $11,
last_modified_source = $12,
device_sync_data = $13,
created_at = created_at
WHERE id = $1
RETURNING id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at, dedup_key, last_modified_at, last_modified_source, device_sync_data, percentage_location, epubcfi_location, chapter_reference, deleted, deleted_at
`
type UpdateMediaBookmarkForSyncParams struct {
ID pgtype.UUID `db:"id" json:"id"`
PageNumber pgtype.Int4 `db:"page_number" json:"page_number"`
ChapterNumber pgtype.Int4 `db:"chapter_number" json:"chapter_number"`
CfiPosition pgtype.Text `db:"cfi_position" json:"cfi_position"`
Title string `db:"title" json:"title"`
Position pgtype.Text `db:"position" json:"position"`
Notes pgtype.Text `db:"notes" json:"notes"`
PercentageLocation pgtype.Float8 `db:"percentage_location" json:"percentage_location"`
EpubcfiLocation pgtype.Text `db:"epubcfi_location" json:"epubcfi_location"`
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
}
func (q *Queries) UpdateMediaBookmarkForSync(ctx context.Context, arg UpdateMediaBookmarkForSyncParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, UpdateMediaBookmarkForSync,
arg.ID,
arg.PageNumber,
arg.ChapterNumber,
arg.CfiPosition,
arg.Title,
arg.Position,
arg.Notes,
arg.PercentageLocation,
arg.EpubcfiLocation,
arg.ChapterReference,
arg.LastModifiedAt,
arg.LastModifiedSource,
arg.DeviceSyncData,
)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.DeviceSyncData,
&i.PercentageLocation,
&i.EpubcfiLocation,
&i.ChapterReference,
&i.Deleted,
&i.DeletedAt,
)
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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at
`
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const UpdateMediaHighlightForSync = `-- name: UpdateMediaHighlightForSync :one
UPDATE media_highlights SET
selection_text = $2,
start_position = $3,
end_position = $4,
color = $5,
note_text = $6,
percentage_start = $7,
percentage_end = $8,
epubcfi_start = $9,
epubcfi_end = $10,
chapter_reference = $11,
last_modified_at = $12,
last_modified_source = $13,
device_sync_data = $14,
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, dedup_key, last_modified_at, last_modified_source, note_text, deleted, deleted_at
`
type UpdateMediaHighlightForSyncParams 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"`
NoteText pgtype.Text `db:"note_text" json:"note_text"`
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"`
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
}
func (q *Queries) UpdateMediaHighlightForSync(ctx context.Context, arg UpdateMediaHighlightForSyncParams) (MediaHighlights, error) {
row := q.db.QueryRow(ctx, UpdateMediaHighlightForSync,
arg.ID,
arg.SelectionText,
arg.StartPosition,
arg.EndPosition,
arg.Color,
arg.NoteText,
arg.PercentageStart,
arg.PercentageEnd,
arg.EpubcfiStart,
arg.EpubcfiEnd,
arg.ChapterReference,
arg.LastModifiedAt,
arg.LastModifiedSource,
arg.DeviceSyncData,
)
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.NoteText,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const UpdateMediaItem = `-- name: UpdateMediaItem :one
UPDATE media_items SET
title = $2,
author = $3,
isbn = $4,
description = $5,
cover_image_path = $6,
series = $7,
series_number = $8,
tags = $9,
tags_search = $10,
asin = $11,
date_published = $12,
publisher = $13,
contributors = $14,
contributors_search = $15,
language = $16,
edition = $17,
page_count = $18,
genre = $19,
copyright_year = $20,
goodreads_id = $21,
openlibrary_id = $22,
google_books_id = $23,
manga_type = $24,
reading_direction = $25,
series_count = $26,
volume = $27,
imprint = $28,
age_rating = $29,
web_url = $30,
metadata_notes = $31,
community_rating = $32,
story_arc = $33,
is_black_and_white = $34,
alternate_info = $35,
scan_information = $36,
summary = $37,
updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Title string `db:"title" json:"title"`
Author pgtype.Text `db:"author" json:"author"`
Isbn pgtype.Text `db:"isbn" json:"isbn"`
Description pgtype.Text `db:"description" json:"description"`
CoverImagePath pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
Series pgtype.Text `db:"series" json:"series"`
SeriesNumber pgtype.Int4 `db:"series_number" json:"series_number"`
Tags []string `db:"tags" json:"tags"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
Asin pgtype.Text `db:"asin" json:"asin"`
DatePublished pgtype.Date `db:"date_published" json:"date_published"`
Publisher pgtype.Text `db:"publisher" json:"publisher"`
Contributors []string `db:"contributors" json:"contributors"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
Language pgtype.Text `db:"language" json:"language"`
Edition pgtype.Text `db:"edition" json:"edition"`
PageCount pgtype.Int4 `db:"page_count" json:"page_count"`
Genre pgtype.Text `db:"genre" json:"genre"`
CopyrightYear pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
GoodreadsID pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
OpenlibraryID pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
GoogleBooksID pgtype.Text `db:"google_books_id" json:"google_books_id"`
MangaType pgtype.Text `db:"manga_type" json:"manga_type"`
ReadingDirection pgtype.Text `db:"reading_direction" json:"reading_direction"`
SeriesCount pgtype.Int4 `db:"series_count" json:"series_count"`
Volume pgtype.Int4 `db:"volume" json:"volume"`
Imprint pgtype.Text `db:"imprint" json:"imprint"`
AgeRating pgtype.Text `db:"age_rating" json:"age_rating"`
WebUrl pgtype.Text `db:"web_url" json:"web_url"`
MetadataNotes pgtype.Text `db:"metadata_notes" json:"metadata_notes"`
CommunityRating pgtype.Float8 `db:"community_rating" json:"community_rating"`
StoryArc pgtype.Text `db:"story_arc" json:"story_arc"`
IsBlackAndWhite pgtype.Bool `db:"is_black_and_white" json:"is_black_and_white"`
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
}
func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, UpdateMediaItem,
arg.ID,
arg.Title,
arg.Author,
arg.Isbn,
arg.Description,
arg.CoverImagePath,
arg.Series,
arg.SeriesNumber,
arg.Tags,
arg.TagsSearch,
arg.Asin,
arg.DatePublished,
arg.Publisher,
arg.Contributors,
arg.ContributorsSearch,
arg.Language,
arg.Edition,
arg.PageCount,
arg.Genre,
arg.CopyrightYear,
arg.GoodreadsID,
arg.OpenlibraryID,
arg.GoogleBooksID,
arg.MangaType,
arg.ReadingDirection,
arg.SeriesCount,
arg.Volume,
arg.Imprint,
arg.AgeRating,
arg.WebUrl,
arg.MetadataNotes,
arg.CommunityRating,
arg.StoryArc,
arg.IsBlackAndWhite,
arg.AlternateInfo,
arg.ScanInformation,
arg.Summary,
)
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const UpdateMediaItemChapterMetadata = `-- name: UpdateMediaItemChapterMetadata :one
UPDATE media_items
SET chapter_metadata = $2, updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemChapterMetadataParams struct {
ID pgtype.UUID `db:"id" json:"id"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
}
func (q *Queries) UpdateMediaItemChapterMetadata(ctx context.Context, arg UpdateMediaItemChapterMetadataParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, UpdateMediaItemChapterMetadata, arg.ID, arg.ChapterMetadata)
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.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const UpdateMediaItemFormat = `-- name: UpdateMediaItemFormat :one
UPDATE media_item_formats
SET
file_path = $2,
file_sha256 = $3,
file_size_bytes = $4,
mime_type = $5
WHERE id = $1
RETURNING id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id
`
type UpdateMediaItemFormatParams struct {
ID pgtype.UUID `db:"id" json:"id"`
FilePath pgtype.Text `db:"file_path" json:"file_path"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
FileSizeBytes pgtype.Int8 `db:"file_size_bytes" json:"file_size_bytes"`
MimeType pgtype.Text `db:"mime_type" json:"mime_type"`
}
// Update media item format
func (q *Queries) UpdateMediaItemFormat(ctx context.Context, arg UpdateMediaItemFormatParams) (MediaItemFormats, error) {
row := q.db.QueryRow(ctx, UpdateMediaItemFormat,
arg.ID,
arg.FilePath,
arg.FileSha256,
arg.FileSizeBytes,
arg.MimeType,
)
var i MediaItemFormats
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.FormatType,
&i.FilePath,
&i.FileSha256,
&i.FileSizeBytes,
&i.MimeType,
&i.CreatedAt,
&i.ConvertedFromFormatID,
)
return i, err
}
const UpdateMediaItemFormatGroup = `-- name: UpdateMediaItemFormatGroup :exec
UPDATE media_items
SET
format_group = $2,
format_mimetype = $3,
is_reflowable = $4,
has_fixed_layout = $5,
total_characters = $6,
chapter_count = $7,
updated_at = NOW()
WHERE id = $1
`
type UpdateMediaItemFormatGroupParams struct {
ID pgtype.UUID `db:"id" json:"id"`
FormatGroup string `db:"format_group" json:"format_group"`
FormatMimetype pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
IsReflowable pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
HasFixedLayout pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
ChapterCount pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
}
// ============================================
// FORMAT DETECTION & PROGRESS
// ============================================
// Update media item format group information
func (q *Queries) UpdateMediaItemFormatGroup(ctx context.Context, arg UpdateMediaItemFormatGroupParams) error {
_, err := q.db.Exec(ctx, UpdateMediaItemFormatGroup,
arg.ID,
arg.FormatGroup,
arg.FormatMimetype,
arg.IsReflowable,
arg.HasFixedLayout,
arg.TotalCharacters,
arg.ChapterCount,
)
return err
}
const UpdateMediaItemIdentifiers = `-- name: UpdateMediaItemIdentifiers :one
UPDATE media_items
SET
file_sha256 = $2,
opf_identifier = $3,
opf_uuid = $4,
hash_confidence = $5,
updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemIdentifiersParams struct {
ID pgtype.UUID `db:"id" json:"id"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
OpfIdentifier pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
OpfUuid pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
}
// Media Items Admin Operations
// ============================================
// UNIVERSAL BOOK IDENTIFIERS
// ============================================
// Update media item with universal identifiers
func (q *Queries) UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMediaItemIdentifiersParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, UpdateMediaItemIdentifiers,
arg.ID,
arg.FileSha256,
arg.OpfIdentifier,
arg.OpfUuid,
arg.HashConfidence,
)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const UpdateMediaItemKoboMetadata = `-- name: UpdateMediaItemKoboMetadata :one
UPDATE media_items
SET entitlement_id = $2,
kobo_content_id = $3,
revision_number = COALESCE($4, revision_number) + 1,
kobo_metadata = $5,
updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, library_type_name, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemKoboMetadataParams struct {
ID pgtype.UUID `db:"id" json:"id"`
EntitlementID pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
KoboContentID pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
KoboMetadata []byte `db:"kobo_metadata" json:"kobo_metadata"`
}
func (q *Queries) UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMediaItemKoboMetadataParams) (MediaItems, error) {
row := q.db.QueryRow(ctx, UpdateMediaItemKoboMetadata,
arg.ID,
arg.EntitlementID,
arg.KoboContentID,
arg.RevisionNumber,
arg.KoboMetadata,
)
var i MediaItems
err := row.Scan(
&i.ID,
&i.LibraryID,
&i.Title,
&i.Author,
&i.Isbn,
&i.Description,
&i.FilePath,
&i.FileSize,
&i.MimeType,
&i.CoverImagePath,
&i.Series,
&i.SeriesNumber,
&i.Tags,
&i.Asin,
&i.DatePublished,
&i.Publisher,
&i.Contributors,
&i.Language,
&i.Edition,
&i.PageCount,
&i.Genre,
&i.CopyrightYear,
&i.GoodreadsID,
&i.OpenlibraryID,
&i.GoogleBooksID,
&i.AddedByAdminID,
&i.CreatedAt,
&i.ImportedAt,
&i.UpdatedAt,
&i.FormatGroup,
&i.FormatMimetype,
&i.IsReflowable,
&i.HasFixedLayout,
&i.TotalCharacters,
&i.ChapterCount,
&i.EntitlementID,
&i.RevisionNumber,
&i.KoboContentID,
&i.KoboMetadata,
&i.MangaType,
&i.ReadingDirection,
&i.SeriesCount,
&i.Volume,
&i.Imprint,
&i.AgeRating,
&i.WebUrl,
&i.StoryArc,
&i.IsBlackAndWhite,
&i.MetadataNotes,
&i.CommunityRating,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.LibraryTypeName,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
&i.OpfIdentifier,
&i.OpfUuid,
&i.HashConfidence,
)
return i, err
}
const UpdateMediaNote = `-- name: UpdateMediaNote :one
UPDATE media_notes SET
content = $2,
position = $3,
updated_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at
`
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
)
return i, err
}
const UpdateMediaNoteForSync = `-- name: UpdateMediaNoteForSync :one
UPDATE media_notes SET
content = $2,
position = $3,
percentage_location = $4,
character_start = $5,
character_end = $6,
epubcfi_location = $7,
chapter_reference = $8,
paragraph_reference = $9,
last_modified_at = $10,
last_modified_source = $11,
device_sync_data = $12,
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, dedup_key, last_modified_at, last_modified_source, deleted, deleted_at
`
type UpdateMediaNoteForSyncParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Content string `db:"content" json:"content"`
Position pgtype.Text `db:"position" json:"position"`
PercentageLocation pgtype.Float8 `db:"percentage_location" json:"percentage_location"`
CharacterStart pgtype.Int4 `db:"character_start" json:"character_start"`
CharacterEnd pgtype.Int4 `db:"character_end" json:"character_end"`
EpubcfiLocation pgtype.Text `db:"epubcfi_location" json:"epubcfi_location"`
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
ParagraphReference pgtype.Int4 `db:"paragraph_reference" json:"paragraph_reference"`
LastModifiedAt pgtype.Timestamptz `db:"last_modified_at" json:"last_modified_at"`
LastModifiedSource pgtype.Text `db:"last_modified_source" json:"last_modified_source"`
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
}
func (q *Queries) UpdateMediaNoteForSync(ctx context.Context, arg UpdateMediaNoteForSyncParams) (MediaNotes, error) {
row := q.db.QueryRow(ctx, UpdateMediaNoteForSync,
arg.ID,
arg.Content,
arg.Position,
arg.PercentageLocation,
arg.CharacterStart,
arg.CharacterEnd,
arg.EpubcfiLocation,
arg.ChapterReference,
arg.ParagraphReference,
arg.LastModifiedAt,
arg.LastModifiedSource,
arg.DeviceSyncData,
)
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,
&i.DedupKey,
&i.LastModifiedAt,
&i.LastModifiedSource,
&i.Deleted,
&i.DeletedAt,
)
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, context_text, 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.ContextText,
&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 UpdateReadingSpeed = `-- name: UpdateReadingSpeed :one
UPDATE reading_speed
SET
pages_per_minute = $3,
pages_read = pages_read + $4,
total_reading_minutes = total_reading_minutes + $5,
last_read_at = $6,
updated_at = NOW()
WHERE user_id = $1 AND media_item_id = $2
RETURNING id, user_id, media_item_id, words_per_minute, pages_per_minute, pages_read, total_reading_minutes, last_read_at, updated_at
`
type UpdateReadingSpeedParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PagesPerMinute pgtype.Float4 `db:"pages_per_minute" json:"pages_per_minute"`
PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"`
TotalReadingMinutes pgtype.Float4 `db:"total_reading_minutes" json:"total_reading_minutes"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
}
func (q *Queries) UpdateReadingSpeed(ctx context.Context, arg UpdateReadingSpeedParams) (ReadingSpeed, error) {
row := q.db.QueryRow(ctx, UpdateReadingSpeed,
arg.UserID,
arg.MediaItemID,
arg.PagesPerMinute,
arg.PagesRead,
arg.TotalReadingMinutes,
arg.LastReadAt,
)
var i ReadingSpeed
err := row.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.WordsPerMinute,
&i.PagesPerMinute,
&i.PagesRead,
&i.TotalReadingMinutes,
&i.LastReadAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateSavedFilter = `-- name: UpdateSavedFilter :one
UPDATE saved_filters
SET name = $1,
filters = $2,
updated_at = NOW()
WHERE id = $3 AND user_id = $4
RETURNING id, user_id, name, resource_type, filters, created_at, updated_at
`
type UpdateSavedFilterParams struct {
Name string `db:"name" json:"name"`
Filters []byte `db:"filters" json:"filters"`
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) UpdateSavedFilter(ctx context.Context, arg UpdateSavedFilterParams) (SavedFilters, error) {
row := q.db.QueryRow(ctx, UpdateSavedFilter,
arg.Name,
arg.Filters,
arg.ID,
arg.UserID,
)
var i SavedFilters
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.ResourceType,
&i.Filters,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateSyncQueueItemStatus = `-- name: UpdateSyncQueueItemStatus :one
UPDATE sync_queue
SET
status = $2,
attempts = attempts + 1,
error_message = $3,
processed_at = CASE WHEN $2::varchar = 'completed' THEN NOW() ELSE NULL END
WHERE id = $1
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`
type UpdateSyncQueueItemStatusParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Status pgtype.Text `db:"status" json:"status"`
ErrorMessage pgtype.Text `db:"error_message" json:"error_message"`
}
func (q *Queries) UpdateSyncQueueItemStatus(ctx context.Context, arg UpdateSyncQueueItemStatusParams) (SyncQueue, error) {
row := q.db.QueryRow(ctx, UpdateSyncQueueItemStatus, arg.ID, arg.Status, arg.ErrorMessage)
var i SyncQueue
err := row.Scan(
&i.ID,
&i.DeviceID,
&i.MediaItemID,
&i.SyncType,
&i.SyncData,
&i.Priority,
&i.Attempts,
&i.MaxAttempts,
&i.Status,
&i.ErrorMessage,
&i.CreatedAt,
&i.ProcessedAt,
)
return i, err
}
const UpdateSystemSetting = `-- name: UpdateSystemSetting :exec
UPDATE system_settings SET setting_value = $2, updated_at = NOW() WHERE setting_key = $1
`
type UpdateSystemSettingParams struct {
SettingKey string `db:"setting_key" json:"setting_key"`
SettingValue string `db:"setting_value" json:"setting_value"`
}
func (q *Queries) UpdateSystemSetting(ctx context.Context, arg UpdateSystemSettingParams) error {
_, err := q.db.Exec(ctx, UpdateSystemSetting, arg.SettingKey, arg.SettingValue)
return err
}
const UpdateUniversalProgress = `-- name: UpdateUniversalProgress :one
INSERT INTO reading_progress (
media_item_id,
user_id,
percentage,
character_offset,
epubcfi,
context_text,
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, $17, NOW(), $18, $19, NOW()
)
ON CONFLICT (media_item_id, user_id)
DO UPDATE SET
percentage = EXCLUDED.percentage,
character_offset = EXCLUDED.character_offset,
epubcfi = EXCLUDED.epubcfi,
context_text = EXCLUDED.context_text,
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, context_text, 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"`
ContextText pgtype.Text `db:"context_text" json:"context_text"`
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.ContextText,
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.ContextText,
&i.Chapter,
&i.ChapterProgress,
&i.ViewportX,
&i.ViewportY,
&i.ZoomLevel,
&i.ScrollPositionX,
&i.ScrollPositionY,
&i.PanelNumber,
&i.ReadingMode,
&i.LastSyncDevice,
&i.LastSyncSource,
&i.LastSyncTimestamp,
&i.ConflictDetected,
&i.ConflictResolved,
)
return i, err
}
const UpdateUserMaxDevices = `-- name: UpdateUserMaxDevices :one
UPDATE users SET max_devices = $2, updated_at = NOW() WHERE id = $1
RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, timezone, updated_at
`
type UpdateUserMaxDevicesParams struct {
ID pgtype.UUID `db:"id" json:"id"`
MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"`
}
func (q *Queries) UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDevicesParams) (Users, error) {
row := q.db.QueryRow(ctx, UpdateUserMaxDevices, arg.ID, arg.MaxDevices)
var i Users
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.PasswordHash,
&i.FirstName,
&i.LastName,
&i.Role,
&i.Theme,
&i.MaxDevices,
&i.CreatedAt,
&i.Timezone,
&i.UpdatedAt,
)
return i, err
}
const UpdateUserProfile = `-- name: UpdateUserProfile :exec
UPDATE users SET first_name = $2, last_name = $3, updated_at = NOW() WHERE id = $1
`
type UpdateUserProfileParams struct {
ID pgtype.UUID `db:"id" json:"id"`
FirstName pgtype.Text `db:"first_name" json:"first_name"`
LastName pgtype.Text `db:"last_name" json:"last_name"`
}
func (q *Queries) UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) error {
_, err := q.db.Exec(ctx, UpdateUserProfile, arg.ID, arg.FirstName, arg.LastName)
return err
}
const UpdateUserRole = `-- name: UpdateUserRole :one
UPDATE users SET role = $2, updated_at = NOW() WHERE id = $1
RETURNING id, email, username, role
`
type UpdateUserRoleParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Role string `db:"role" json:"role"`
}
type UpdateUserRoleRow struct {
ID pgtype.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Username string `db:"username" json:"username"`
Role string `db:"role" json:"role"`
}
func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UpdateUserRoleRow, error) {
row := q.db.QueryRow(ctx, UpdateUserRole, arg.ID, arg.Role)
var i UpdateUserRoleRow
err := row.Scan(
&i.ID,
&i.Email,
&i.Username,
&i.Role,
)
return i, err
}
const UpdateUserTheme = `-- name: UpdateUserTheme :exec
UPDATE users SET theme = $2, updated_at = NOW() WHERE id = $1
`
type UpdateUserThemeParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Theme pgtype.Text `db:"theme" json:"theme"`
}
func (q *Queries) UpdateUserTheme(ctx context.Context, arg UpdateUserThemeParams) error {
_, err := q.db.Exec(ctx, UpdateUserTheme, arg.ID, arg.Theme)
return err
}
const UpdateUserTimezone = `-- name: UpdateUserTimezone :exec
UPDATE users SET timezone = $2, updated_at = NOW() WHERE id = $1
`
type UpdateUserTimezoneParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Timezone pgtype.Text `db:"timezone" json:"timezone"`
}
func (q *Queries) UpdateUserTimezone(ctx context.Context, arg UpdateUserTimezoneParams) error {
_, err := q.db.Exec(ctx, UpdateUserTimezone, arg.ID, arg.Timezone)
return err
}
const UpdateUsername = `-- name: UpdateUsername :exec
UPDATE users SET username = $2, updated_at = NOW() WHERE id = $1
`
type UpdateUsernameParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Username string `db:"username" json:"username"`
}
func (q *Queries) UpdateUsername(ctx context.Context, arg UpdateUsernameParams) error {
_, err := q.db.Exec(ctx, UpdateUsername, arg.ID, arg.Username)
return err
}
const UpsertDashboardPreferences = `-- name: UpsertDashboardPreferences :one
INSERT INTO user_dashboard_preferences (user_id, library_id, hidden_collections, collection_order, items_per_section)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id, library_id)
DO UPDATE SET
hidden_collections = EXCLUDED.hidden_collections,
collection_order = EXCLUDED.collection_order,
items_per_section = EXCLUDED.items_per_section,
updated_at = NOW()
RETURNING id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at
`
type UpsertDashboardPreferencesParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
HiddenCollections []string `db:"hidden_collections" json:"hidden_collections"`
CollectionOrder []string `db:"collection_order" json:"collection_order"`
ItemsPerSection pgtype.Int4 `db:"items_per_section" json:"items_per_section"`
}
func (q *Queries) UpsertDashboardPreferences(ctx context.Context, arg UpsertDashboardPreferencesParams) (UserDashboardPreferences, error) {
row := q.db.QueryRow(ctx, UpsertDashboardPreferences,
arg.UserID,
arg.LibraryID,
arg.HiddenCollections,
arg.CollectionOrder,
arg.ItemsPerSection,
)
var i UserDashboardPreferences
err := row.Scan(
&i.ID,
&i.UserID,
&i.LibraryID,
&i.HiddenCollections,
&i.CollectionOrder,
&i.ItemsPerSection,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpsertPanelData = `-- name: UpsertPanelData :one
INSERT INTO panel_data (media_item_id, page_number, detection_method, panels)
VALUES ($1, $2, $3, $4)
ON CONFLICT (media_item_id, page_number)
DO UPDATE SET
detection_method = EXCLUDED.detection_method,
panels = EXCLUDED.panels,
updated_at = NOW()
RETURNING id, media_item_id, page_number, detection_method, panels, created_at, updated_at
`
type UpsertPanelDataParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PageNumber int32 `db:"page_number" json:"page_number"`
DetectionMethod string `db:"detection_method" json:"detection_method"`
Panels []byte `db:"panels" json:"panels"`
}
func (q *Queries) UpsertPanelData(ctx context.Context, arg UpsertPanelDataParams) (PanelData, error) {
row := q.db.QueryRow(ctx, UpsertPanelData,
arg.MediaItemID,
arg.PageNumber,
arg.DetectionMethod,
arg.Panels,
)
var i PanelData
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.PageNumber,
&i.DetectionMethod,
&i.Panels,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpsertReaderSettings = `-- name: UpsertReaderSettings :one
INSERT INTO reader_settings (user_id, setting_key, setting_value)
VALUES ($1, 'reader_settings', $2)
ON CONFLICT (user_id, setting_key)
DO UPDATE SET
setting_value = EXCLUDED.setting_value,
updated_at = NOW()
RETURNING id, user_id, setting_key, setting_value, updated_at
`
type UpsertReaderSettingsParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
SettingValue []byte `db:"setting_value" json:"setting_value"`
}
func (q *Queries) UpsertReaderSettings(ctx context.Context, arg UpsertReaderSettingsParams) (ReaderSettings, error) {
row := q.db.QueryRow(ctx, UpsertReaderSettings, arg.UserID, arg.SettingValue)
var i ReaderSettings
err := row.Scan(
&i.ID,
&i.UserID,
&i.SettingKey,
&i.SettingValue,
&i.UpdatedAt,
)
return i, err
}
const UpsertSystemSetting = `-- name: UpsertSystemSetting :one
INSERT INTO system_settings (setting_key, setting_value, description, setting_type, min_value, max_value, requires_restart, category)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (setting_key) DO UPDATE
SET setting_value = EXCLUDED.setting_value,
description = EXCLUDED.description,
setting_type = EXCLUDED.setting_type,
min_value = EXCLUDED.min_value,
max_value = EXCLUDED.max_value,
requires_restart = EXCLUDED.requires_restart,
category = EXCLUDED.category,
updated_at = NOW()
RETURNING id, setting_key, setting_value, description, updated_at, setting_type, min_value, max_value, requires_restart, category
`
type UpsertSystemSettingParams struct {
SettingKey string `db:"setting_key" json:"setting_key"`
SettingValue string `db:"setting_value" json:"setting_value"`
Description pgtype.Text `db:"description" json:"description"`
SettingType pgtype.Text `db:"setting_type" json:"setting_type"`
MinValue pgtype.Text `db:"min_value" json:"min_value"`
MaxValue pgtype.Text `db:"max_value" json:"max_value"`
RequiresRestart pgtype.Bool `db:"requires_restart" json:"requires_restart"`
Category pgtype.Text `db:"category" json:"category"`
}
func (q *Queries) UpsertSystemSetting(ctx context.Context, arg UpsertSystemSettingParams) (SystemSettings, error) {
row := q.db.QueryRow(ctx, UpsertSystemSetting,
arg.SettingKey,
arg.SettingValue,
arg.Description,
arg.SettingType,
arg.MinValue,
arg.MaxValue,
arg.RequiresRestart,
arg.Category,
)
var i SystemSettings
err := row.Scan(
&i.ID,
&i.SettingKey,
&i.SettingValue,
&i.Description,
&i.UpdatedAt,
&i.SettingType,
&i.MinValue,
&i.MaxValue,
&i.RequiresRestart,
&i.Category,
)
return i, err
}