diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/database/migrations/0003_unique_url.sql | 3 | ||||
| -rw-r--r-- | pkg/database/migrations/0004_unread_kind.sql | 5 | ||||
| -rw-r--r-- | pkg/database/query/entries.sql | 20 | ||||
| -rw-r--r-- | pkg/database/sqlc/entries.sql.go | 99 | ||||
| -rw-r--r-- | pkg/entries/entries.go | 58 |
5 files changed, 185 insertions, 0 deletions
diff --git a/pkg/database/migrations/0003_unique_url.sql b/pkg/database/migrations/0003_unique_url.sql new file mode 100644 index 0000000..8be3293 --- /dev/null +++ b/pkg/database/migrations/0003_unique_url.sql @@ -0,0 +1,3 @@ +-- +goose Up + +CREATE UNIQUE INDEX ux_entries_url ON entries(url); diff --git a/pkg/database/migrations/0004_unread_kind.sql b/pkg/database/migrations/0004_unread_kind.sql new file mode 100644 index 0000000..e583050 --- /dev/null +++ b/pkg/database/migrations/0004_unread_kind.sql @@ -0,0 +1,5 @@ +-- +goose Up + +INSERT INTO kinds (name, emoji) +VALUES + ("unread", "📚"); diff --git a/pkg/database/query/entries.sql b/pkg/database/query/entries.sql index 1f39016..9584adf 100644 --- a/pkg/database/query/entries.sql +++ b/pkg/database/query/entries.sql @@ -5,7 +5,27 @@ FROM kinds WHERE kinds.name = ? RETURNING *; +-- name: UpdateEntryKind :one +UPDATE entries +SET kind = (SELECT id FROM kinds WHERE kinds.name = ?) +WHERE entries.id = ? +RETURNING *; + +-- name: DeleteEntry :execrows +DELETE FROM entries +WHERE id = ?; + -- name: GetEntries :many SELECT title, url, description, timestamp, kinds.name as kind_name, kinds.emoji as kind_emoji FROM entries JOIN kinds ON entries.kind == kinds.id ORDER BY timestamp DESC; + +-- name: GetEntryURLs :many +SELECT url FROM entries +ORDER BY timestamp DESC; + +-- name: GetEntryByUrl :one +SELECT entries.id, title, url, description, timestamp, kinds.name as kind_name, kinds.emoji as kind_emoji FROM entries +JOIN kinds ON entries.kind == kinds.id +WHERE url = ? +LIMIT 1; diff --git a/pkg/database/sqlc/entries.sql.go b/pkg/database/sqlc/entries.sql.go index c7b5e1c..846076d 100644 --- a/pkg/database/sqlc/entries.sql.go +++ b/pkg/database/sqlc/entries.sql.go @@ -43,6 +43,19 @@ func (q *Queries) CreateEntryWithKindName(ctx context.Context, arg CreateEntryWi return i, err } +const deleteEntry = `-- name: DeleteEntry :execrows +DELETE FROM entries +WHERE id = ? +` + +func (q *Queries) DeleteEntry(ctx context.Context, id int64) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteEntry, id) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + const getEntries = `-- name: GetEntries :many SELECT title, url, description, timestamp, kinds.name as kind_name, kinds.emoji as kind_emoji FROM entries JOIN kinds ON entries.kind == kinds.id @@ -87,3 +100,89 @@ func (q *Queries) GetEntries(ctx context.Context) ([]GetEntriesRow, error) { } return items, nil } + +const getEntryByUrl = `-- name: GetEntryByUrl :one +SELECT entries.id, title, url, description, timestamp, kinds.name as kind_name, kinds.emoji as kind_emoji FROM entries +JOIN kinds ON entries.kind == kinds.id +WHERE url = ? +LIMIT 1 +` + +type GetEntryByUrlRow struct { + ID int64 `json:"id"` + Title string `json:"title"` + Url string `json:"url"` + Description string `json:"description"` + Timestamp string `json:"timestamp"` + KindName string `json:"kind_name"` + KindEmoji string `json:"kind_emoji"` +} + +func (q *Queries) GetEntryByUrl(ctx context.Context, url string) (GetEntryByUrlRow, error) { + row := q.db.QueryRowContext(ctx, getEntryByUrl, url) + var i GetEntryByUrlRow + err := row.Scan( + &i.ID, + &i.Title, + &i.Url, + &i.Description, + &i.Timestamp, + &i.KindName, + &i.KindEmoji, + ) + return i, err +} + +const getEntryURLs = `-- name: GetEntryURLs :many +SELECT url FROM entries +ORDER BY timestamp DESC +` + +func (q *Queries) GetEntryURLs(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getEntryURLs) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var url string + if err := rows.Scan(&url); err != nil { + return nil, err + } + items = append(items, url) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateEntryKind = `-- name: UpdateEntryKind :one +UPDATE entries +SET kind = (SELECT id FROM kinds WHERE kinds.name = ?) +WHERE entries.id = ? +RETURNING id, title, kind, url, description, timestamp +` + +type UpdateEntryKindParams struct { + Name string `json:"name"` + ID int64 `json:"id"` +} + +func (q *Queries) UpdateEntryKind(ctx context.Context, arg UpdateEntryKindParams) (Entry, error) { + row := q.db.QueryRowContext(ctx, updateEntryKind, arg.Name, arg.ID) + var i Entry + err := row.Scan( + &i.ID, + &i.Title, + &i.Kind, + &i.Url, + &i.Description, + &i.Timestamp, + ) + return i, err +} diff --git a/pkg/entries/entries.go b/pkg/entries/entries.go index 0764f93..92f28d9 100644 --- a/pkg/entries/entries.go +++ b/pkg/entries/entries.go @@ -3,6 +3,7 @@ package entries import ( "context" "database/sql" + "errors" "fmt" "git.leonardobishop.net/stash/pkg/database/sqlc" @@ -10,9 +11,17 @@ import ( type Service interface { CreateEntry(title, kind, url, description string) (*sqlc.Entry, error) + UpdateEntryKind(id int64, kind string) (*sqlc.Entry, error) + DeleteEntry(id int64) error GetEntries() ([]sqlc.GetEntriesRow, error) + GetEntryURLs() ([]string, error) + GetEntryByUrl(url string) (*sqlc.GetEntryByUrlRow, error) } +var ( + ErrEntryNotFound = errors.New("entry not found") +) + type service struct { db *sql.DB } @@ -40,6 +49,30 @@ func (s *service) CreateEntry(title, kind, url, description string) (*sqlc.Entry return &entry, nil } +func (s *service) UpdateEntryKind(id int64, kind string) (*sqlc.Entry, error) { + queries := sqlc.New(s.db) + + entry, err := queries.UpdateEntryKind(context.Background(), sqlc.UpdateEntryKindParams{ + ID: id, + Name: kind, + }) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrEntryNotFound + } + return nil, fmt.Errorf("could not update entry: %w", err) + } + + return &entry, nil +} + +func (s *service) DeleteEntry(id int64) error { + queries := sqlc.New(s.db) + + _, err := queries.DeleteEntry(context.Background(), id) + return err +} + func (s *service) GetEntries() ([]sqlc.GetEntriesRow, error) { queries := sqlc.New(s.db) @@ -50,3 +83,28 @@ func (s *service) GetEntries() ([]sqlc.GetEntriesRow, error) { return entries, nil } + +func (s *service) GetEntryURLs() ([]string, error) { + queries := sqlc.New(s.db) + + entries, err := queries.GetEntryURLs(context.Background()) + if err != nil { + return make([]string, 0), fmt.Errorf("could not get entries: %w", err) + } + + return entries, nil +} + +func (s *service) GetEntryByUrl(url string) (*sqlc.GetEntryByUrlRow, error) { + queries := sqlc.New(s.db) + + entry, err := queries.GetEntryByUrl(context.Background(), url) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrEntryNotFound + } + return nil, fmt.Errorf("could not get entry: %w", err) + } + + return &entry, nil +} |
