diff --git a/internal/database/db.go b/internal/database/db.go index bdf4241..51f4337 100644 --- a/internal/database/db.go +++ b/internal/database/db.go @@ -9,6 +9,7 @@ import ( "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgxpool" ) type DBTX interface { @@ -30,3 +31,8 @@ func (q *Queries) WithTx(tx pgx.Tx) *Queries { db: tx, } } + +// NewConnection creates a new database connection pool +func NewConnection(databaseURL string) (*pgxpool.Pool, error) { + return pgxpool.New(context.Background(), databaseURL) +} diff --git a/internal/database/models.go b/internal/database/models.go index 668a7a6..8be41eb 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -8,6 +8,31 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) +type EbookHighlights 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"` + 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"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` + EbookID pgtype.UUID `db:"ebook_id" json:"ebook_id"` +} + +type EbookNotes 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"` + Content string `db:"content" json:"content"` + Position pgtype.Text `db:"position" json:"position"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` + EbookID pgtype.UUID `db:"ebook_id" json:"ebook_id"` +} + type EbookRatings struct { ID pgtype.UUID `db:"id" json:"id"` MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` @@ -85,6 +110,19 @@ type LibraryVisibility struct { UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } +type MediaHighlights 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"` + 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"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` +} + type MediaItems struct { ID pgtype.UUID `db:"id" json:"id"` LibraryID pgtype.UUID `db:"library_id" json:"library_id"` @@ -108,6 +146,16 @@ type MediaItems struct { UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` } +type MediaNotes 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"` + Content string `db:"content" json:"content"` + Position pgtype.Text `db:"position" json:"position"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` +} + type MediaRatings struct { ID pgtype.UUID `db:"id" json:"id"` MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index a2c4cf7..64dd4c7 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -103,6 +103,83 @@ func (q *Queries) CreateEbook(ctx context.Context, arg CreateEbookParams) (Media return i, err } +const CreateEbookHighlight = `-- name: CreateEbookHighlight :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 +` + +type CreateEbookHighlightParams 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"` +} + +// Backward compatibility - Ebook Highlights queries (using views) +func (q *Queries) CreateEbookHighlight(ctx context.Context, arg CreateEbookHighlightParams) (MediaHighlights, error) { + row := q.db.QueryRow(ctx, CreateEbookHighlight, + 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, + ) + return i, err +} + +const CreateEbookNote = `-- name: CreateEbookNote :one +INSERT INTO media_notes (media_item_id, user_id, content, position) +VALUES ($1, $2, $3, $4) +RETURNING id, media_item_id, user_id, content, position, created_at, updated_at +` + +type CreateEbookNoteParams struct { + MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` + Content string `db:"content" json:"content"` + Position pgtype.Text `db:"position" json:"position"` +} + +// Backward compatibility - Ebook Notes queries (using views) +func (q *Queries) CreateEbookNote(ctx context.Context, arg CreateEbookNoteParams) (MediaNotes, error) { + row := q.db.QueryRow(ctx, CreateEbookNote, + arg.MediaItemID, + arg.UserID, + arg.Content, + arg.Position, + ) + var i MediaNotes + err := row.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.Content, + &i.Position, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + const CreateEbookRating = `-- name: CreateEbookRating :one INSERT INTO media_ratings (media_item_id, user_id, rating) VALUES ($1, $2, $3) @@ -168,6 +245,49 @@ func (q *Queries) CreateLibrary(ctx context.Context, arg CreateLibraryParams) (L 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 +` + +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, + ) + return i, err +} + const CreateMediaItem = `-- name: CreateMediaItem :one INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, added_by_admin_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) @@ -241,6 +361,40 @@ func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams 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 +` + +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, + ) + return i, err +} + const CreateMediaRating = `-- name: CreateMediaRating :one INSERT INTO media_ratings (media_item_id, user_id, rating) VALUES ($1, $2, $3) @@ -333,6 +487,24 @@ func (q *Queries) DeleteEbook(ctx context.Context, id pgtype.UUID) error { return err } +const DeleteEbookHighlight = `-- name: DeleteEbookHighlight :exec +DELETE FROM media_highlights WHERE id = $1 +` + +func (q *Queries) DeleteEbookHighlight(ctx context.Context, id pgtype.UUID) error { + _, err := q.db.Exec(ctx, DeleteEbookHighlight, id) + return err +} + +const DeleteEbookNote = `-- name: DeleteEbookNote :exec +DELETE FROM media_notes WHERE id = $1 +` + +func (q *Queries) DeleteEbookNote(ctx context.Context, id pgtype.UUID) error { + _, err := q.db.Exec(ctx, DeleteEbookNote, id) + return err +} + const DeleteEbookRating = `-- name: DeleteEbookRating :exec DELETE FROM media_ratings WHERE media_item_id = $1 AND user_id = $2 ` @@ -377,6 +549,15 @@ func (q *Queries) DeleteLibraryFolder(ctx context.Context, arg DeleteLibraryFold return i, err } +const DeleteMediaHighlight = `-- name: DeleteMediaHighlight :exec +DELETE FROM media_highlights WHERE id = $1 +` + +func (q *Queries) DeleteMediaHighlight(ctx context.Context, id pgtype.UUID) error { + _, err := q.db.Exec(ctx, DeleteMediaHighlight, id) + return err +} + const DeleteMediaItem = `-- name: DeleteMediaItem :exec DELETE FROM media_items WHERE id = $1 ` @@ -386,6 +567,15 @@ func (q *Queries) DeleteMediaItem(ctx context.Context, id pgtype.UUID) error { 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 ` @@ -491,6 +681,128 @@ func (q *Queries) GetEbookByFilePath(ctx context.Context, filePath string) (Eboo return i, err } +const GetEbookHighlight = `-- name: GetEbookHighlight :one +SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, ebook_id FROM ebook_highlights WHERE id = $1 +` + +func (q *Queries) GetEbookHighlight(ctx context.Context, id pgtype.UUID) (EbookHighlights, error) { + row := q.db.QueryRow(ctx, GetEbookHighlight, id) + var i EbookHighlights + err := row.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.SelectionText, + &i.StartPosition, + &i.EndPosition, + &i.Color, + &i.NoteID, + &i.CreatedAt, + &i.UpdatedAt, + &i.EbookID, + ) + return i, err +} + +const GetEbookHighlights = `-- name: GetEbookHighlights :many +SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, ebook_id FROM ebook_highlights WHERE ebook_id = $1 AND user_id = $2 ORDER BY created_at DESC +` + +type GetEbookHighlightsParams struct { + EbookID pgtype.UUID `db:"ebook_id" json:"ebook_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` +} + +func (q *Queries) GetEbookHighlights(ctx context.Context, arg GetEbookHighlightsParams) ([]EbookHighlights, error) { + rows, err := q.db.Query(ctx, GetEbookHighlights, arg.EbookID, arg.UserID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []EbookHighlights{} + for rows.Next() { + var i EbookHighlights + 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.EbookID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetEbookNote = `-- name: GetEbookNote :one +SELECT id, media_item_id, user_id, content, position, created_at, updated_at, ebook_id FROM ebook_notes WHERE id = $1 +` + +func (q *Queries) GetEbookNote(ctx context.Context, id pgtype.UUID) (EbookNotes, error) { + row := q.db.QueryRow(ctx, GetEbookNote, id) + var i EbookNotes + err := row.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.Content, + &i.Position, + &i.CreatedAt, + &i.UpdatedAt, + &i.EbookID, + ) + return i, err +} + +const GetEbookNotes = `-- name: GetEbookNotes :many +SELECT id, media_item_id, user_id, content, position, created_at, updated_at, ebook_id FROM ebook_notes WHERE ebook_id = $1 AND user_id = $2 ORDER BY created_at DESC +` + +type GetEbookNotesParams struct { + EbookID pgtype.UUID `db:"ebook_id" json:"ebook_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` +} + +func (q *Queries) GetEbookNotes(ctx context.Context, arg GetEbookNotesParams) ([]EbookNotes, error) { + rows, err := q.db.Query(ctx, GetEbookNotes, arg.EbookID, arg.UserID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []EbookNotes{} + for rows.Next() { + var i EbookNotes + if err := rows.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.Content, + &i.Position, + &i.CreatedAt, + &i.UpdatedAt, + &i.EbookID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const GetEbookRating = `-- name: GetEbookRating :one SELECT id, media_item_id, user_id, rating, created_at, updated_at, ebook_id FROM ebook_ratings WHERE ebook_id = $1 AND user_id = $2 ` @@ -716,6 +1028,68 @@ func (q *Queries) GetLibraryVisibility(ctx context.Context, arg GetLibraryVisibi return i, err } +const GetMediaHighlight = `-- name: GetMediaHighlight :one +SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at 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, + ) + 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 FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC +` + +type GetMediaHighlightsParams struct { + MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` +} + +func (q *Queries) GetMediaHighlights(ctx context.Context, arg GetMediaHighlightsParams) ([]MediaHighlights, error) { + rows, err := q.db.Query(ctx, GetMediaHighlights, arg.MediaItemID, arg.UserID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []MediaHighlights{} + for rows.Next() { + var i MediaHighlights + if err := rows.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.SelectionText, + &i.StartPosition, + &i.EndPosition, + &i.Color, + &i.NoteID, + &i.CreatedAt, + &i.UpdatedAt, + ); 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, added_by_admin_id, created_at, updated_at FROM media_items WHERE id = $1 ` @@ -780,6 +1154,62 @@ func (q *Queries) GetMediaItemByFilePath(ctx context.Context, filePath string) ( return i, err } +const GetMediaNote = `-- name: GetMediaNote :one +SELECT id, media_item_id, user_id, content, position, created_at, updated_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, + ) + return i, err +} + +const GetMediaNotes = `-- name: GetMediaNotes :many +SELECT id, media_item_id, user_id, content, position, created_at, updated_at FROM media_notes WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC +` + +type GetMediaNotesParams struct { + MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"` + UserID pgtype.UUID `db:"user_id" json:"user_id"` +} + +func (q *Queries) GetMediaNotes(ctx context.Context, arg GetMediaNotesParams) ([]MediaNotes, error) { + rows, err := q.db.Query(ctx, GetMediaNotes, arg.MediaItemID, arg.UserID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []MediaNotes{} + for rows.Next() { + var i MediaNotes + if err := rows.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.Content, + &i.Position, + &i.CreatedAt, + &i.UpdatedAt, + ); 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 ` @@ -1531,6 +1961,82 @@ func (q *Queries) UpdateEbook(ctx context.Context, arg UpdateEbookParams) (Media return i, err } +const UpdateEbookHighlight = `-- name: UpdateEbookHighlight :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 +` + +type UpdateEbookHighlightParams 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) UpdateEbookHighlight(ctx context.Context, arg UpdateEbookHighlightParams) (MediaHighlights, error) { + row := q.db.QueryRow(ctx, UpdateEbookHighlight, + 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, + ) + return i, err +} + +const UpdateEbookNote = `-- name: UpdateEbookNote :one +UPDATE media_notes SET + content = $2, + position = $3, + updated_at = NOW() +WHERE id = $1 +RETURNING id, media_item_id, user_id, content, position, created_at, updated_at +` + +type UpdateEbookNoteParams struct { + ID pgtype.UUID `db:"id" json:"id"` + Content string `db:"content" json:"content"` + Position pgtype.Text `db:"position" json:"position"` +} + +func (q *Queries) UpdateEbookNote(ctx context.Context, arg UpdateEbookNoteParams) (MediaNotes, error) { + row := q.db.QueryRow(ctx, UpdateEbookNote, arg.ID, arg.Content, arg.Position) + var i MediaNotes + err := row.Scan( + &i.ID, + &i.MediaItemID, + &i.UserID, + &i.Content, + &i.Position, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + const UpdateEbookRating = `-- name: UpdateEbookRating :one UPDATE media_ratings SET rating = $3, @@ -1603,6 +2109,52 @@ func (q *Queries) UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (L 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 +` + +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, + ) + return i, err +} + const UpdateMediaItem = `-- name: UpdateMediaItem :one UPDATE media_items SET title = $2, @@ -1680,6 +2232,36 @@ func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams 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 +` + +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, + ) + return i, err +} + const UpdateMediaRating = `-- name: UpdateMediaRating :one UPDATE media_ratings SET rating = $3, diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index 8066830..45f2744 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -279,4 +279,102 @@ DELETE FROM media_ratings WHERE media_item_id = $1 AND user_id = $2; -- Legacy folder management is now handled through libraries -- name: GetEbookByFilePath :one -SELECT * FROM ebooks WHERE file_path = $1; \ No newline at end of file +SELECT * FROM ebooks WHERE file_path = $1; + +-- Media Notes queries +-- name: CreateMediaNote :one +INSERT INTO media_notes (media_item_id, user_id, content, position) +VALUES ($1, $2, $3, $4) +RETURNING *; + +-- name: GetMediaNote :one +SELECT * FROM media_notes WHERE id = $1; + +-- name: GetMediaNotes :many +SELECT * FROM media_notes WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC; + +-- name: UpdateMediaNote :one +UPDATE media_notes SET + content = $2, + position = $3, + updated_at = NOW() +WHERE id = $1 +RETURNING *; + +-- name: DeleteMediaNote :exec +DELETE FROM media_notes WHERE id = $1; + +-- Media Highlights queries +-- 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 *; + +-- name: GetMediaHighlight :one +SELECT * FROM media_highlights WHERE id = $1; + +-- name: GetMediaHighlights :many +SELECT * FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC; + +-- 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 *; + +-- name: DeleteMediaHighlight :exec +DELETE FROM media_highlights WHERE id = $1; + +-- Backward compatibility - Ebook Notes queries (using views) +-- name: CreateEbookNote :one +INSERT INTO media_notes (media_item_id, user_id, content, position) +VALUES ($1, $2, $3, $4) +RETURNING *; + +-- name: GetEbookNote :one +SELECT * FROM ebook_notes WHERE id = $1; + +-- name: GetEbookNotes :many +SELECT * FROM ebook_notes WHERE ebook_id = $1 AND user_id = $2 ORDER BY created_at DESC; + +-- name: UpdateEbookNote :one +UPDATE media_notes SET + content = $2, + position = $3, + updated_at = NOW() +WHERE id = $1 +RETURNING *; + +-- name: DeleteEbookNote :exec +DELETE FROM media_notes WHERE id = $1; + +-- Backward compatibility - Ebook Highlights queries (using views) +-- name: CreateEbookHighlight :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 *; + +-- name: GetEbookHighlight :one +SELECT * FROM ebook_highlights WHERE id = $1; + +-- name: GetEbookHighlights :many +SELECT * FROM ebook_highlights WHERE ebook_id = $1 AND user_id = $2 ORDER BY created_at DESC; + +-- name: UpdateEbookHighlight :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 *; + +-- name: DeleteEbookHighlight :exec +DELETE FROM media_highlights WHERE id = $1; \ No newline at end of file