feat(db): add annotation sync schema, queries, and tombstone support
Add migration columns to media_highlights, media_notes, and media_bookmarks for cross-device annotation sync: - dedup_key: SHA-1 of normalized selection text + bucketed position, used as the stable cross-device identity for annotations - last_modified_at / last_modified_source: edit clock for LWW resolution and cross-source conflict detection - deleted / deleted_at: sticky tombstone columns for delete-wins semantics with a 30-day TTL before rows are physically purged - note_text on highlights: stores attached notes from KOReader entries that have both selected text and a user note - Location columns on bookmarks (cfi_position, percentage_location, epubcfi_location, chapter_reference, paragraph_reference) - device_sync_data JSONB on all three tables: stores per-device native identifiers (e.g. KOReader pos0/datetime, Kobo bookmark_id) so each device can locate and manipulate its own copy of an annotation Add partial unique indexes on (user_id, media_item_id, dedup_key) where deleted = FALSE to enforce one active annotation per dedup key. Add tombstone purge indexes on (deleted, deleted_at) for efficient GC. New queries: - GetByDedupKey for all three tables (returns active or most-recent tombstone) - CreateFull / UpdateForSync for all three tables (populate sync columns) - TombstoneByDedupKey / TombstoneByID for all three tables - PurgeExpired* for all three tables (GC past TTL) - GetActiveAnnotationsForBook (filtered union of highlights + notes) - GetTombstonedAnnotationsForBook (union of all 3 deleted within TTL) - GetMediaBookmarks with deleted filter - GetMediaBookmark (singular) with deleted filter - Added deleted=FALSE filter to GetMediaHighlights, GetAnnotationsForBook - CreateAutoResolvedSyncConflict (INSERT with resolution_status='auto_resolved')
This commit is contained in:
@@ -1312,3 +1312,48 @@ CREATE TABLE IF NOT EXISTS media_bookmarks (
|
|||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_media ON media_bookmarks(media_item_id);
|
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_media ON media_bookmarks(media_item_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_user ON media_bookmarks(user_id);
|
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_user ON media_bookmarks(user_id);
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- ANNOTATION SYNC MIGRATIONS
|
||||||
|
-- Adds dedup_key, LWW timestamps, soft-delete,
|
||||||
|
-- and device_sync_data to annotation tables.
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
ALTER TABLE media_highlights ADD COLUMN IF NOT EXISTS dedup_key VARCHAR(40);
|
||||||
|
ALTER TABLE media_highlights ADD COLUMN IF NOT EXISTS last_modified_at TIMESTAMPTZ;
|
||||||
|
ALTER TABLE media_highlights ADD COLUMN IF NOT EXISTS last_modified_source VARCHAR(30);
|
||||||
|
ALTER TABLE media_highlights ADD COLUMN IF NOT EXISTS note_text TEXT;
|
||||||
|
ALTER TABLE media_highlights ADD COLUMN IF NOT EXISTS deleted BOOLEAN DEFAULT FALSE;
|
||||||
|
ALTER TABLE media_highlights ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
|
ALTER TABLE media_notes ADD COLUMN IF NOT EXISTS dedup_key VARCHAR(40);
|
||||||
|
ALTER TABLE media_notes ADD COLUMN IF NOT EXISTS last_modified_at TIMESTAMPTZ;
|
||||||
|
ALTER TABLE media_notes ADD COLUMN IF NOT EXISTS last_modified_source VARCHAR(30);
|
||||||
|
ALTER TABLE media_notes ADD COLUMN IF NOT EXISTS deleted BOOLEAN DEFAULT FALSE;
|
||||||
|
ALTER TABLE media_notes ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS dedup_key VARCHAR(40);
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS last_modified_at TIMESTAMPTZ;
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS last_modified_source VARCHAR(30);
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS device_sync_data JSONB;
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS percentage_location FLOAT;
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS epubcfi_location TEXT;
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS chapter_reference INTEGER;
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS deleted BOOLEAN DEFAULT FALSE;
|
||||||
|
ALTER TABLE media_bookmarks ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_media_highlights_dedup
|
||||||
|
ON media_highlights (user_id, media_item_id, dedup_key)
|
||||||
|
WHERE dedup_key IS NOT NULL AND deleted = FALSE;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_media_notes_dedup
|
||||||
|
ON media_notes (user_id, media_item_id, dedup_key)
|
||||||
|
WHERE dedup_key IS NOT NULL AND deleted = FALSE;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_media_bookmarks_dedup
|
||||||
|
ON media_bookmarks (user_id, media_item_id, dedup_key)
|
||||||
|
WHERE dedup_key IS NOT NULL AND deleted = FALSE;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_media_highlights_deleted_at ON media_highlights(deleted_at) WHERE deleted = TRUE;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_media_notes_deleted_at ON media_notes(deleted_at) WHERE deleted = TRUE;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_deleted_at ON media_bookmarks(deleted_at) WHERE deleted = TRUE;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.31.1
|
// sqlc v1.30.0
|
||||||
|
|
||||||
package database
|
package database
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.31.1
|
// sqlc v1.30.0
|
||||||
|
|
||||||
package database
|
package database
|
||||||
|
|
||||||
@@ -165,6 +165,15 @@ type MediaBookmarks struct {
|
|||||||
Position pgtype.Text `db:"position" json:"position"`
|
Position pgtype.Text `db:"position" json:"position"`
|
||||||
Notes pgtype.Text `db:"notes" json:"notes"`
|
Notes pgtype.Text `db:"notes" json:"notes"`
|
||||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||||
|
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"`
|
||||||
|
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"`
|
||||||
|
Deleted pgtype.Bool `db:"deleted" json:"deleted"`
|
||||||
|
DeletedAt pgtype.Timestamptz `db:"deleted_at" json:"deleted_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaHighlights struct {
|
type MediaHighlights struct {
|
||||||
@@ -189,6 +198,12 @@ type MediaHighlights struct {
|
|||||||
ParagraphEnd pgtype.Int4 `db:"paragraph_end" json:"paragraph_end"`
|
ParagraphEnd pgtype.Int4 `db:"paragraph_end" json:"paragraph_end"`
|
||||||
PanelNumber pgtype.Int4 `db:"panel_number" json:"panel_number"`
|
PanelNumber pgtype.Int4 `db:"panel_number" json:"panel_number"`
|
||||||
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
|
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
|
||||||
|
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"`
|
||||||
|
NoteText pgtype.Text `db:"note_text" json:"note_text"`
|
||||||
|
Deleted pgtype.Bool `db:"deleted" json:"deleted"`
|
||||||
|
DeletedAt pgtype.Timestamptz `db:"deleted_at" json:"deleted_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaItemFormats struct {
|
type MediaItemFormats struct {
|
||||||
@@ -304,6 +319,11 @@ type MediaNotes struct {
|
|||||||
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
|
ChapterReference pgtype.Int4 `db:"chapter_reference" json:"chapter_reference"`
|
||||||
ParagraphReference pgtype.Int4 `db:"paragraph_reference" json:"paragraph_reference"`
|
ParagraphReference pgtype.Int4 `db:"paragraph_reference" json:"paragraph_reference"`
|
||||||
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
|
DeviceSyncData []byte `db:"device_sync_data" json:"device_sync_data"`
|
||||||
|
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"`
|
||||||
|
Deleted pgtype.Bool `db:"deleted" json:"deleted"`
|
||||||
|
DeletedAt pgtype.Timestamptz `db:"deleted_at" json:"deleted_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaRatings struct {
|
type MediaRatings struct {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.31.1
|
// sqlc v1.30.0
|
||||||
|
|
||||||
package database
|
package database
|
||||||
|
|
||||||
@@ -34,6 +34,7 @@ type Querier interface {
|
|||||||
// Count unlinked books for a device
|
// Count unlinked books for a device
|
||||||
CountUnlinkedBooks(ctx context.Context, deviceID pgtype.UUID) (int64, error)
|
CountUnlinkedBooks(ctx context.Context, deviceID pgtype.UUID) (int64, error)
|
||||||
CountUserDevices(ctx context.Context, userID pgtype.UUID) (int64, error)
|
CountUserDevices(ctx context.Context, userID pgtype.UUID) (int64, error)
|
||||||
|
CreateAutoResolvedSyncConflict(ctx context.Context, arg CreateAutoResolvedSyncConflictParams) (SyncConflicts, error)
|
||||||
// COLLECTIONS QUERIES
|
// COLLECTIONS QUERIES
|
||||||
// Create collection
|
// Create collection
|
||||||
CreateCollection(ctx context.Context, arg CreateCollectionParams) (Collections, error)
|
CreateCollection(ctx context.Context, arg CreateCollectionParams) (Collections, error)
|
||||||
@@ -55,8 +56,10 @@ type Querier interface {
|
|||||||
// Libraries queries
|
// Libraries queries
|
||||||
CreateLibrary(ctx context.Context, arg CreateLibraryParams) (Libraries, error)
|
CreateLibrary(ctx context.Context, arg CreateLibraryParams) (Libraries, error)
|
||||||
CreateMediaBookmark(ctx context.Context, arg CreateMediaBookmarkParams) (MediaBookmarks, error)
|
CreateMediaBookmark(ctx context.Context, arg CreateMediaBookmarkParams) (MediaBookmarks, error)
|
||||||
|
CreateMediaBookmarkFull(ctx context.Context, arg CreateMediaBookmarkFullParams) (MediaBookmarks, error)
|
||||||
// Media Highlights queries
|
// Media Highlights queries
|
||||||
CreateMediaHighlight(ctx context.Context, arg CreateMediaHighlightParams) (MediaHighlights, error)
|
CreateMediaHighlight(ctx context.Context, arg CreateMediaHighlightParams) (MediaHighlights, error)
|
||||||
|
CreateMediaHighlightFull(ctx context.Context, arg CreateMediaHighlightFullParams) (MediaHighlights, error)
|
||||||
// Media Items queries
|
// Media Items queries
|
||||||
CreateMediaItem(ctx context.Context, arg CreateMediaItemParams) (MediaItems, error)
|
CreateMediaItem(ctx context.Context, arg CreateMediaItemParams) (MediaItems, error)
|
||||||
// MEDIA ITEM FORMATS QUERIES
|
// MEDIA ITEM FORMATS QUERIES
|
||||||
@@ -64,6 +67,7 @@ type Querier interface {
|
|||||||
CreateMediaItemFormat(ctx context.Context, arg CreateMediaItemFormatParams) (MediaItemFormats, error)
|
CreateMediaItemFormat(ctx context.Context, arg CreateMediaItemFormatParams) (MediaItemFormats, error)
|
||||||
// Media Notes queries
|
// Media Notes queries
|
||||||
CreateMediaNote(ctx context.Context, arg CreateMediaNoteParams) (MediaNotes, error)
|
CreateMediaNote(ctx context.Context, arg CreateMediaNoteParams) (MediaNotes, error)
|
||||||
|
CreateMediaNoteFull(ctx context.Context, arg CreateMediaNoteFullParams) (MediaNotes, error)
|
||||||
CreateMediaRating(ctx context.Context, arg CreateMediaRatingParams) (MediaRatings, error)
|
CreateMediaRating(ctx context.Context, arg CreateMediaRatingParams) (MediaRatings, error)
|
||||||
// OPDS TOKENS QUERIES
|
// OPDS TOKENS QUERIES
|
||||||
// Create OPDS token
|
// Create OPDS token
|
||||||
@@ -126,6 +130,10 @@ type Querier interface {
|
|||||||
DeleteUser(ctx context.Context, id pgtype.UUID) error
|
DeleteUser(ctx context.Context, id pgtype.UUID) error
|
||||||
DeleteUserSystemCollection(ctx context.Context, arg DeleteUserSystemCollectionParams) error
|
DeleteUserSystemCollection(ctx context.Context, arg DeleteUserSystemCollectionParams) error
|
||||||
GenerateKoboEntitlementId(ctx context.Context) (interface{}, error)
|
GenerateKoboEntitlementId(ctx context.Context) (interface{}, error)
|
||||||
|
// ============================================
|
||||||
|
// ANNOTATION SERVE QUERIES
|
||||||
|
// ============================================
|
||||||
|
GetActiveAnnotationsForBook(ctx context.Context, arg GetActiveAnnotationsForBookParams) ([]GetActiveAnnotationsForBookRow, error)
|
||||||
// Get all system config
|
// Get all system config
|
||||||
GetAllSystemConfig(ctx context.Context) ([]SystemConfig, error)
|
GetAllSystemConfig(ctx context.Context) ([]SystemConfig, error)
|
||||||
GetAllSystemSettings(ctx context.Context) ([]GetAllSystemSettingsRow, error)
|
GetAllSystemSettings(ctx context.Context) ([]GetAllSystemSettingsRow, error)
|
||||||
@@ -197,8 +205,17 @@ type Querier interface {
|
|||||||
// LIBRARY WITH TYPE INFO QUERIES
|
// LIBRARY WITH TYPE INFO QUERIES
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
GetLibraryWithType(ctx context.Context, id pgtype.UUID) (GetLibraryWithTypeRow, error)
|
GetLibraryWithType(ctx context.Context, id pgtype.UUID) (GetLibraryWithTypeRow, error)
|
||||||
|
GetMediaBookmark(ctx context.Context, id pgtype.UUID) (MediaBookmarks, error)
|
||||||
|
// ============================================
|
||||||
|
// ANNOTATION SYNC QUERIES (bookmarks)
|
||||||
|
// ============================================
|
||||||
|
GetMediaBookmarkByDedupKey(ctx context.Context, arg GetMediaBookmarkByDedupKeyParams) (MediaBookmarks, error)
|
||||||
GetMediaBookmarks(ctx context.Context, arg GetMediaBookmarksParams) ([]MediaBookmarks, error)
|
GetMediaBookmarks(ctx context.Context, arg GetMediaBookmarksParams) ([]MediaBookmarks, error)
|
||||||
GetMediaHighlight(ctx context.Context, id pgtype.UUID) (MediaHighlights, error)
|
GetMediaHighlight(ctx context.Context, id pgtype.UUID) (MediaHighlights, error)
|
||||||
|
// ============================================
|
||||||
|
// ANNOTATION SYNC QUERIES (highlights)
|
||||||
|
// ============================================
|
||||||
|
GetMediaHighlightByDedupKey(ctx context.Context, arg GetMediaHighlightByDedupKeyParams) (MediaHighlights, error)
|
||||||
GetMediaHighlights(ctx context.Context, arg GetMediaHighlightsParams) ([]MediaHighlights, error)
|
GetMediaHighlights(ctx context.Context, arg GetMediaHighlightsParams) ([]MediaHighlights, error)
|
||||||
GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error)
|
GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error)
|
||||||
GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemByFilePathParams) (MediaItems, error)
|
GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemByFilePathParams) (MediaItems, error)
|
||||||
@@ -221,6 +238,10 @@ type Querier interface {
|
|||||||
// Get media item formats
|
// Get media item formats
|
||||||
GetMediaItemFormats(ctx context.Context, mediaItemID pgtype.UUID) ([]MediaItemFormats, error)
|
GetMediaItemFormats(ctx context.Context, mediaItemID pgtype.UUID) ([]MediaItemFormats, error)
|
||||||
GetMediaNote(ctx context.Context, id pgtype.UUID) (MediaNotes, error)
|
GetMediaNote(ctx context.Context, id pgtype.UUID) (MediaNotes, error)
|
||||||
|
// ============================================
|
||||||
|
// ANNOTATION SYNC QUERIES (notes)
|
||||||
|
// ============================================
|
||||||
|
GetMediaNoteByDedupKey(ctx context.Context, arg GetMediaNoteByDedupKeyParams) (MediaNotes, error)
|
||||||
GetMediaNotes(ctx context.Context, arg GetMediaNotesParams) ([]MediaNotes, error)
|
GetMediaNotes(ctx context.Context, arg GetMediaNotesParams) ([]MediaNotes, error)
|
||||||
GetMediaRating(ctx context.Context, arg GetMediaRatingParams) (MediaRatings, error)
|
GetMediaRating(ctx context.Context, arg GetMediaRatingParams) (MediaRatings, error)
|
||||||
GetMediaRatings(ctx context.Context, mediaItemID pgtype.UUID) ([]GetMediaRatingsRow, error)
|
GetMediaRatings(ctx context.Context, mediaItemID pgtype.UUID) ([]GetMediaRatingsRow, error)
|
||||||
@@ -258,6 +279,7 @@ type Querier interface {
|
|||||||
// System Settings queries
|
// System Settings queries
|
||||||
GetSystemSetting(ctx context.Context, settingKey string) (string, error)
|
GetSystemSetting(ctx context.Context, settingKey string) (string, error)
|
||||||
GetSystemTimezone(ctx context.Context) (string, error)
|
GetSystemTimezone(ctx context.Context) (string, error)
|
||||||
|
GetTombstonedAnnotationsForBook(ctx context.Context, arg GetTombstonedAnnotationsForBookParams) ([]GetTombstonedAnnotationsForBookRow, error)
|
||||||
// Get universal progress for a book
|
// Get universal progress for a book
|
||||||
GetUniversalProgress(ctx context.Context, arg GetUniversalProgressParams) (GetUniversalProgressRow, error)
|
GetUniversalProgress(ctx context.Context, arg GetUniversalProgressParams) (GetUniversalProgressRow, error)
|
||||||
// Get unlinked book by ContentId
|
// Get unlinked book by ContentId
|
||||||
@@ -304,6 +326,9 @@ type Querier interface {
|
|||||||
// List unresolved unlinked books with pagination
|
// List unresolved unlinked books with pagination
|
||||||
ListUnresolvedUnlinkedBooks(ctx context.Context, arg ListUnresolvedUnlinkedBooksParams) ([]ListUnresolvedUnlinkedBooksRow, error)
|
ListUnresolvedUnlinkedBooks(ctx context.Context, arg ListUnresolvedUnlinkedBooksParams) ([]ListUnresolvedUnlinkedBooksRow, error)
|
||||||
ListUsers(ctx context.Context) ([]ListUsersRow, error)
|
ListUsers(ctx context.Context) ([]ListUsersRow, error)
|
||||||
|
PurgeExpiredBookmarkTombstones(ctx context.Context, deletedAt pgtype.Timestamptz) error
|
||||||
|
PurgeExpiredHighlightTombstones(ctx context.Context, deletedAt pgtype.Timestamptz) error
|
||||||
|
PurgeExpiredNoteTombstones(ctx context.Context, deletedAt pgtype.Timestamptz) error
|
||||||
// Query media items by multiple identifiers with confidence scoring
|
// Query media items by multiple identifiers with confidence scoring
|
||||||
QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMediaItemsByIdentifiersParams) ([]QueryMediaItemsByIdentifiersRow, error)
|
QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMediaItemsByIdentifiersParams) ([]QueryMediaItemsByIdentifiersRow, error)
|
||||||
ReassignLibraries(ctx context.Context, arg ReassignLibrariesParams) error
|
ReassignLibraries(ctx context.Context, arg ReassignLibrariesParams) error
|
||||||
@@ -334,6 +359,12 @@ type Querier interface {
|
|||||||
// Set system config
|
// Set system config
|
||||||
SetSystemConfig(ctx context.Context, arg SetSystemConfigParams) (SystemConfig, error)
|
SetSystemConfig(ctx context.Context, arg SetSystemConfigParams) (SystemConfig, error)
|
||||||
SyncLibraryTypeExtensions(ctx context.Context, arg SyncLibraryTypeExtensionsParams) error
|
SyncLibraryTypeExtensions(ctx context.Context, arg SyncLibraryTypeExtensionsParams) error
|
||||||
|
TombstoneMediaBookmarkByDedupKey(ctx context.Context, arg TombstoneMediaBookmarkByDedupKeyParams) error
|
||||||
|
TombstoneMediaBookmarkByID(ctx context.Context, id pgtype.UUID) error
|
||||||
|
TombstoneMediaHighlightByDedupKey(ctx context.Context, arg TombstoneMediaHighlightByDedupKeyParams) error
|
||||||
|
TombstoneMediaHighlightByID(ctx context.Context, id pgtype.UUID) error
|
||||||
|
TombstoneMediaNoteByDedupKey(ctx context.Context, arg TombstoneMediaNoteByDedupKeyParams) error
|
||||||
|
TombstoneMediaNoteByID(ctx context.Context, id pgtype.UUID) error
|
||||||
// Update collection
|
// Update collection
|
||||||
UpdateCollection(ctx context.Context, arg UpdateCollectionParams) (Collections, error)
|
UpdateCollection(ctx context.Context, arg UpdateCollectionParams) (Collections, error)
|
||||||
UpdateDashboardPreferences(ctx context.Context, arg UpdateDashboardPreferencesParams) (UserDashboardPreferences, error)
|
UpdateDashboardPreferences(ctx context.Context, arg UpdateDashboardPreferencesParams) (UserDashboardPreferences, error)
|
||||||
@@ -357,7 +388,9 @@ type Querier interface {
|
|||||||
UpdateKoboShelfCollection(ctx context.Context, arg UpdateKoboShelfCollectionParams) (KoboShelves, error)
|
UpdateKoboShelfCollection(ctx context.Context, arg UpdateKoboShelfCollectionParams) (KoboShelves, error)
|
||||||
UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (Libraries, error)
|
UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (Libraries, error)
|
||||||
UpdateMediaBookmark(ctx context.Context, arg UpdateMediaBookmarkParams) (MediaBookmarks, error)
|
UpdateMediaBookmark(ctx context.Context, arg UpdateMediaBookmarkParams) (MediaBookmarks, error)
|
||||||
|
UpdateMediaBookmarkForSync(ctx context.Context, arg UpdateMediaBookmarkForSyncParams) (MediaBookmarks, error)
|
||||||
UpdateMediaHighlight(ctx context.Context, arg UpdateMediaHighlightParams) (MediaHighlights, error)
|
UpdateMediaHighlight(ctx context.Context, arg UpdateMediaHighlightParams) (MediaHighlights, error)
|
||||||
|
UpdateMediaHighlightForSync(ctx context.Context, arg UpdateMediaHighlightForSyncParams) (MediaHighlights, error)
|
||||||
UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams) (MediaItems, error)
|
UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams) (MediaItems, error)
|
||||||
UpdateMediaItemChapterMetadata(ctx context.Context, arg UpdateMediaItemChapterMetadataParams) (MediaItems, error)
|
UpdateMediaItemChapterMetadata(ctx context.Context, arg UpdateMediaItemChapterMetadataParams) (MediaItems, error)
|
||||||
// Update media item format
|
// Update media item format
|
||||||
@@ -375,6 +408,7 @@ type Querier interface {
|
|||||||
UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMediaItemIdentifiersParams) (MediaItems, error)
|
UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMediaItemIdentifiersParams) (MediaItems, error)
|
||||||
UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMediaItemKoboMetadataParams) (MediaItems, error)
|
UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMediaItemKoboMetadataParams) (MediaItems, error)
|
||||||
UpdateMediaNote(ctx context.Context, arg UpdateMediaNoteParams) (MediaNotes, error)
|
UpdateMediaNote(ctx context.Context, arg UpdateMediaNoteParams) (MediaNotes, error)
|
||||||
|
UpdateMediaNoteForSync(ctx context.Context, arg UpdateMediaNoteForSyncParams) (MediaNotes, error)
|
||||||
UpdateMediaRating(ctx context.Context, arg UpdateMediaRatingParams) (MediaRatings, error)
|
UpdateMediaRating(ctx context.Context, arg UpdateMediaRatingParams) (MediaRatings, error)
|
||||||
UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error
|
UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error
|
||||||
UpdateReadingProgress(ctx context.Context, arg UpdateReadingProgressParams) (ReadingProgress, error)
|
UpdateReadingProgress(ctx context.Context, arg UpdateReadingProgressParams) (ReadingProgress, error)
|
||||||
|
|||||||
+1061
-15
File diff suppressed because it is too large
Load Diff
@@ -696,7 +696,7 @@ RETURNING *;
|
|||||||
SELECT * FROM media_notes WHERE id = $1;
|
SELECT * FROM media_notes WHERE id = $1;
|
||||||
|
|
||||||
-- name: GetMediaNotes :many
|
-- name: GetMediaNotes :many
|
||||||
SELECT * FROM media_notes WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC;
|
SELECT * FROM media_notes WHERE media_item_id = $1 AND user_id = $2 AND COALESCE(deleted, FALSE) = FALSE ORDER BY created_at DESC;
|
||||||
|
|
||||||
-- name: UpdateMediaNote :one
|
-- name: UpdateMediaNote :one
|
||||||
UPDATE media_notes SET
|
UPDATE media_notes SET
|
||||||
@@ -719,7 +719,7 @@ RETURNING *;
|
|||||||
SELECT * FROM media_highlights WHERE id = $1;
|
SELECT * FROM media_highlights WHERE id = $1;
|
||||||
|
|
||||||
-- name: GetMediaHighlights :many
|
-- name: GetMediaHighlights :many
|
||||||
SELECT * FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC;
|
SELECT * FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 AND COALESCE(deleted, FALSE) = FALSE ORDER BY created_at DESC;
|
||||||
|
|
||||||
-- name: UpdateMediaHighlight :one
|
-- name: UpdateMediaHighlight :one
|
||||||
UPDATE media_highlights SET
|
UPDATE media_highlights SET
|
||||||
@@ -735,6 +735,251 @@ RETURNING *;
|
|||||||
-- name: DeleteMediaHighlight :exec
|
-- name: DeleteMediaHighlight :exec
|
||||||
DELETE FROM media_highlights WHERE id = $1;
|
DELETE FROM media_highlights WHERE id = $1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- ANNOTATION SYNC QUERIES (highlights)
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
-- name: GetMediaHighlightByDedupKey :one
|
||||||
|
SELECT * 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;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
-- name: TombstoneMediaHighlightByID :exec
|
||||||
|
UPDATE media_highlights SET
|
||||||
|
deleted = TRUE,
|
||||||
|
deleted_at = NOW(),
|
||||||
|
last_modified_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: PurgeExpiredHighlightTombstones :exec
|
||||||
|
DELETE FROM media_highlights WHERE deleted = TRUE AND deleted_at < $1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- ANNOTATION SYNC QUERIES (notes)
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
-- name: GetMediaNoteByDedupKey :one
|
||||||
|
SELECT * 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;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
-- name: TombstoneMediaNoteByID :exec
|
||||||
|
UPDATE media_notes SET
|
||||||
|
deleted = TRUE,
|
||||||
|
deleted_at = NOW(),
|
||||||
|
last_modified_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: PurgeExpiredNoteTombstones :exec
|
||||||
|
DELETE FROM media_notes WHERE deleted = TRUE AND deleted_at < $1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- ANNOTATION SYNC QUERIES (bookmarks)
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
-- name: GetMediaBookmarkByDedupKey :one
|
||||||
|
SELECT * 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;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
-- name: TombstoneMediaBookmarkByID :exec
|
||||||
|
UPDATE media_bookmarks SET
|
||||||
|
deleted = TRUE,
|
||||||
|
deleted_at = NOW(),
|
||||||
|
last_modified_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: PurgeExpiredBookmarkTombstones :exec
|
||||||
|
DELETE FROM media_bookmarks WHERE deleted = TRUE AND deleted_at < $1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- ANNOTATION SERVE QUERIES
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
|
||||||
-- Refresh Tokens queries
|
-- Refresh Tokens queries
|
||||||
-- name: CreateRefreshToken :one
|
-- name: CreateRefreshToken :one
|
||||||
INSERT INTO refresh_tokens (user_id, token, expires_at)
|
INSERT INTO refresh_tokens (user_id, token, expires_at)
|
||||||
@@ -1126,6 +1371,11 @@ INSERT INTO sync_conflicts (media_item_id, user_id, conflict_type, conflict_data
|
|||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
|
-- 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 *;
|
||||||
|
|
||||||
-- name: GetSyncConflict :one
|
-- name: GetSyncConflict :one
|
||||||
SELECT * FROM sync_conflicts WHERE id = $1;
|
SELECT * FROM sync_conflicts WHERE id = $1;
|
||||||
|
|
||||||
@@ -1225,7 +1475,7 @@ SELECT
|
|||||||
mh.epubcfi_start,
|
mh.epubcfi_start,
|
||||||
mh.epubcfi_end
|
mh.epubcfi_end
|
||||||
FROM media_highlights mh
|
FROM media_highlights mh
|
||||||
WHERE mh.media_item_id = $1 AND mh.user_id = $2
|
WHERE mh.media_item_id = $1 AND mh.user_id = $2 AND COALESCE(mh.deleted, FALSE) = FALSE
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT
|
SELECT
|
||||||
mn.id,
|
mn.id,
|
||||||
@@ -1241,7 +1491,7 @@ SELECT
|
|||||||
mn.epubcfi_location as epubcfi_start,
|
mn.epubcfi_location as epubcfi_start,
|
||||||
NULL as epubcfi_end
|
NULL as epubcfi_end
|
||||||
FROM media_notes mn
|
FROM media_notes mn
|
||||||
WHERE mn.media_item_id = $1 AND mn.user_id = $2
|
WHERE mn.media_item_id = $1 AND mn.user_id = $2 AND COALESCE(mn.deleted, FALSE) = FALSE
|
||||||
ORDER BY created_at DESC;
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
-- name: UpdateDeviceSyncTimestamp :one
|
-- name: UpdateDeviceSyncTimestamp :one
|
||||||
@@ -2112,9 +2362,12 @@ RETURNING *;
|
|||||||
|
|
||||||
-- name: GetMediaBookmarks :many
|
-- name: GetMediaBookmarks :many
|
||||||
SELECT * FROM media_bookmarks
|
SELECT * FROM media_bookmarks
|
||||||
WHERE media_item_id = $1 AND user_id = $2
|
WHERE media_item_id = $1 AND user_id = $2 AND COALESCE(deleted, FALSE) = FALSE
|
||||||
ORDER BY created_at DESC;
|
ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: GetMediaBookmark :one
|
||||||
|
SELECT * FROM media_bookmarks WHERE id = $1;
|
||||||
|
|
||||||
-- name: CreateMediaBookmark :one
|
-- name: CreateMediaBookmark :one
|
||||||
INSERT INTO media_bookmarks (media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes)
|
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)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
|||||||
Reference in New Issue
Block a user