From 99cd70165eea385d76ee725c25afb353c5d16bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Hells=C3=A9n?= Date: Sat, 17 Feb 2024 04:50:23 +0100 Subject: [PATCH] Items will now be added when adding feed, add /feed/{id} and improve SQL --- db/feeds.sql.go | 351 +++++++++++++++++++-- db/models.go | 346 ++++++++++---------- db/querier.go | 6 + feeds.go | 70 +++- handlers.go | 91 +++++- main.go | 1 + sql/queries/feeds.sql | 84 +++++ sql/schema/20240214043229_feeds.sql | 22 +- sql/schema/20240215232236_extensions.sql | 20 +- sql/schema/20240215232245_authors.sql | 20 +- sql/schema/20240215232251_images.sql | 20 +- sql/schema/20240215232259_dublin_cores.sql | 20 +- sql/schema/20240215232318_itunes.sql | 28 +- sql/schema/20240215232334_enclousures.sql | 10 +- 14 files changed, 807 insertions(+), 282 deletions(-) diff --git a/db/feeds.sql.go b/db/feeds.sql.go index e448e0f..ccb60dd 100644 --- a/db/feeds.sql.go +++ b/db/feeds.sql.go @@ -11,7 +11,7 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) -const CountFeeds = `-- name: CountFeeds :one +const countFeeds = `-- name: CountFeeds :one SELECT COUNT(*) FROM @@ -19,13 +19,27 @@ FROM ` func (q *Queries) CountFeeds(ctx context.Context) (int64, error) { - row := q.db.QueryRow(ctx, CountFeeds) + row := q.db.QueryRow(ctx, countFeeds) var count int64 err := row.Scan(&count) return count, err } -const CreateFeed = `-- name: CreateFeed :one +const countItems = `-- name: CountItems :one +SELECT + COUNT(*) +FROM + items +` + +func (q *Queries) CountItems(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, countItems) + var count int64 + err := row.Scan(&count) + return count, err +} + +const createFeed = `-- name: CreateFeed :one INSERT INTO feeds ( "url", @@ -75,30 +89,30 @@ VALUES ` type CreateFeedParams struct { - Url string `json:"url"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Title pgtype.Text `json:"title"` - Description pgtype.Text `json:"description"` - Link pgtype.Text `json:"link"` - FeedLink pgtype.Text `json:"feed_link"` - Links []string `json:"links"` - Updated pgtype.Text `json:"updated"` - UpdatedParsed pgtype.Timestamp `json:"updated_parsed"` - Published pgtype.Text `json:"published"` - PublishedParsed pgtype.Timestamp `json:"published_parsed"` - Language pgtype.Text `json:"language"` - Copyright pgtype.Text `json:"copyright"` - Generator pgtype.Text `json:"generator"` - Categories []string `json:"categories"` - Custom []byte `json:"custom"` - FeedType pgtype.Text `json:"feed_type"` - FeedVersion pgtype.Text `json:"feed_version"` + Url string `json:"url"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Title pgtype.Text `json:"title"` + Description pgtype.Text `json:"description"` + Link pgtype.Text `json:"link"` + FeedLink pgtype.Text `json:"feed_link"` + Links []string `json:"links"` + Updated pgtype.Text `json:"updated"` + UpdatedParsed pgtype.Timestamptz `json:"updated_parsed"` + Published pgtype.Text `json:"published"` + PublishedParsed pgtype.Timestamptz `json:"published_parsed"` + Language pgtype.Text `json:"language"` + Copyright pgtype.Text `json:"copyright"` + Generator pgtype.Text `json:"generator"` + Categories []string `json:"categories"` + Custom []byte `json:"custom"` + FeedType pgtype.Text `json:"feed_type"` + FeedVersion pgtype.Text `json:"feed_version"` } func (q *Queries) CreateFeed(ctx context.Context, arg CreateFeedParams) (Feed, error) { - row := q.db.QueryRow(ctx, CreateFeed, + row := q.db.QueryRow(ctx, createFeed, arg.Url, arg.CreatedAt, arg.UpdatedAt, @@ -146,3 +160,292 @@ func (q *Queries) CreateFeed(ctx context.Context, arg CreateFeedParams) (Feed, e ) return i, err } + +const createItem = `-- name: CreateItem :one +INSERT INTO + items ( + created_at, + updated_at, + deleted_at, + title, + "description", + content, + link, + links, + updated, + updated_parsed, + published, + published_parsed, + "guid", + categories, + custom, + feed_id + ) +VALUES + ( + $1, + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + $11, + $12, + $13, + $14, + $15, + $16 + ) RETURNING id, created_at, updated_at, deleted_at, title, description, content, link, links, updated, updated_parsed, published, published_parsed, guid, categories, custom, feed_id +` + +type CreateItemParams struct { + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Title pgtype.Text `json:"title"` + Description pgtype.Text `json:"description"` + Content pgtype.Text `json:"content"` + Link pgtype.Text `json:"link"` + Links []string `json:"links"` + Updated pgtype.Text `json:"updated"` + UpdatedParsed pgtype.Timestamp `json:"updated_parsed"` + Published pgtype.Text `json:"published"` + PublishedParsed pgtype.Timestamp `json:"published_parsed"` + Guid pgtype.Text `json:"guid"` + Categories []string `json:"categories"` + Custom []byte `json:"custom"` + FeedID int64 `json:"feed_id"` +} + +func (q *Queries) CreateItem(ctx context.Context, arg CreateItemParams) (Item, error) { + row := q.db.QueryRow(ctx, createItem, + arg.CreatedAt, + arg.UpdatedAt, + arg.DeletedAt, + arg.Title, + arg.Description, + arg.Content, + arg.Link, + arg.Links, + arg.Updated, + arg.UpdatedParsed, + arg.Published, + arg.PublishedParsed, + arg.Guid, + arg.Categories, + arg.Custom, + arg.FeedID, + ) + var i Item + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.DeletedAt, + &i.Title, + &i.Description, + &i.Content, + &i.Link, + &i.Links, + &i.Updated, + &i.UpdatedParsed, + &i.Published, + &i.PublishedParsed, + &i.Guid, + &i.Categories, + &i.Custom, + &i.FeedID, + ) + return i, err +} + +const getFeed = `-- name: GetFeed :one +SELECT + id, url, created_at, updated_at, deleted_at, title, description, link, feed_link, links, updated, updated_parsed, published, published_parsed, language, copyright, generator, categories, custom, feed_type, feed_version +FROM + feeds +WHERE + id = $1 +` + +func (q *Queries) GetFeed(ctx context.Context, id int64) (Feed, error) { + row := q.db.QueryRow(ctx, getFeed, id) + var i Feed + err := row.Scan( + &i.ID, + &i.Url, + &i.CreatedAt, + &i.UpdatedAt, + &i.DeletedAt, + &i.Title, + &i.Description, + &i.Link, + &i.FeedLink, + &i.Links, + &i.Updated, + &i.UpdatedParsed, + &i.Published, + &i.PublishedParsed, + &i.Language, + &i.Copyright, + &i.Generator, + &i.Categories, + &i.Custom, + &i.FeedType, + &i.FeedVersion, + ) + return i, err +} + +const getFeeds = `-- name: GetFeeds :many +SELECT + id, url, created_at, updated_at, deleted_at, title, description, link, feed_link, links, updated, updated_parsed, published, published_parsed, language, copyright, generator, categories, custom, feed_type, feed_version +FROM + feeds +ORDER BY + created_at DESC +LIMIT $1 +OFFSET $2 +` + +type GetFeedsParams struct { + Limit int32 `json:"limit"` + Offset int32 `json:"offset"` +} + +func (q *Queries) GetFeeds(ctx context.Context, arg GetFeedsParams) ([]Feed, error) { + rows, err := q.db.Query(ctx, getFeeds, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Feed{} + for rows.Next() { + var i Feed + if err := rows.Scan( + &i.ID, + &i.Url, + &i.CreatedAt, + &i.UpdatedAt, + &i.DeletedAt, + &i.Title, + &i.Description, + &i.Link, + &i.FeedLink, + &i.Links, + &i.Updated, + &i.UpdatedParsed, + &i.Published, + &i.PublishedParsed, + &i.Language, + &i.Copyright, + &i.Generator, + &i.Categories, + &i.Custom, + &i.FeedType, + &i.FeedVersion, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getItem = `-- name: GetItem :one +SELECT + id, created_at, updated_at, deleted_at, title, description, content, link, links, updated, updated_parsed, published, published_parsed, guid, categories, custom, feed_id +FROM + items +WHERE + id = $1 +` + +func (q *Queries) GetItem(ctx context.Context, id int64) (Item, error) { + row := q.db.QueryRow(ctx, getItem, id) + var i Item + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.DeletedAt, + &i.Title, + &i.Description, + &i.Content, + &i.Link, + &i.Links, + &i.Updated, + &i.UpdatedParsed, + &i.Published, + &i.PublishedParsed, + &i.Guid, + &i.Categories, + &i.Custom, + &i.FeedID, + ) + return i, err +} + +const getItems = `-- name: GetItems :many +SELECT + id, created_at, updated_at, deleted_at, title, description, content, link, links, updated, updated_parsed, published, published_parsed, guid, categories, custom, feed_id +FROM + items +WHERE + feed_id = $1 +ORDER BY + created_at DESC +LIMIT $2 +OFFSET $3 +` + +type GetItemsParams struct { + FeedID int64 `json:"feed_id"` + Limit int32 `json:"limit"` + Offset int32 `json:"offset"` +} + +func (q *Queries) GetItems(ctx context.Context, arg GetItemsParams) ([]Item, error) { + rows, err := q.db.Query(ctx, getItems, arg.FeedID, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Item{} + for rows.Next() { + var i Item + if err := rows.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.DeletedAt, + &i.Title, + &i.Description, + &i.Content, + &i.Link, + &i.Links, + &i.Updated, + &i.UpdatedParsed, + &i.Published, + &i.PublishedParsed, + &i.Guid, + &i.Categories, + &i.Custom, + &i.FeedID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/db/models.go b/db/models.go index dd41a43..b3a81b2 100644 --- a/db/models.go +++ b/db/models.go @@ -9,229 +9,229 @@ import ( ) type Enclosure struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Url pgtype.Text `json:"url"` - Length pgtype.Text `json:"length"` - Type pgtype.Text `json:"type"` - ItemID int32 `json:"item_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Url pgtype.Text `json:"url"` + Length pgtype.Text `json:"length"` + Type pgtype.Text `json:"type"` + ItemID int64 `json:"item_id"` } type Feed struct { - ID int32 `json:"id"` - Url string `json:"url"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Title pgtype.Text `json:"title"` - Description pgtype.Text `json:"description"` - Link pgtype.Text `json:"link"` - FeedLink pgtype.Text `json:"feed_link"` - Links []string `json:"links"` - Updated pgtype.Text `json:"updated"` - UpdatedParsed pgtype.Timestamp `json:"updated_parsed"` - Published pgtype.Text `json:"published"` - PublishedParsed pgtype.Timestamp `json:"published_parsed"` - Language pgtype.Text `json:"language"` - Copyright pgtype.Text `json:"copyright"` - Generator pgtype.Text `json:"generator"` - Categories []string `json:"categories"` - Custom []byte `json:"custom"` - FeedType pgtype.Text `json:"feed_type"` - FeedVersion pgtype.Text `json:"feed_version"` + ID int64 `json:"id"` + Url string `json:"url"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Title pgtype.Text `json:"title"` + Description pgtype.Text `json:"description"` + Link pgtype.Text `json:"link"` + FeedLink pgtype.Text `json:"feed_link"` + Links []string `json:"links"` + Updated pgtype.Text `json:"updated"` + UpdatedParsed pgtype.Timestamptz `json:"updated_parsed"` + Published pgtype.Text `json:"published"` + PublishedParsed pgtype.Timestamptz `json:"published_parsed"` + Language pgtype.Text `json:"language"` + Copyright pgtype.Text `json:"copyright"` + Generator pgtype.Text `json:"generator"` + Categories []string `json:"categories"` + Custom []byte `json:"custom"` + FeedType pgtype.Text `json:"feed_type"` + FeedVersion pgtype.Text `json:"feed_version"` } type FeedAuthor struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Name pgtype.Text `json:"name"` - Email pgtype.Text `json:"email"` - Uri pgtype.Text `json:"uri"` - FeedID int32 `json:"feed_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Name pgtype.Text `json:"name"` + Email pgtype.Text `json:"email"` + Uri pgtype.Text `json:"uri"` + FeedID int64 `json:"feed_id"` } type FeedDublinCore struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Title []string `json:"title"` - Creator []string `json:"creator"` - Author []string `json:"author"` - Subject []string `json:"subject"` - Description []string `json:"description"` - Publisher []string `json:"publisher"` - Contributor []string `json:"contributor"` - Date []string `json:"date"` - Type []string `json:"type"` - Format []string `json:"format"` - Identifier []string `json:"identifier"` - Source []string `json:"source"` - Language []string `json:"language"` - Relation []string `json:"relation"` - Coverage []string `json:"coverage"` - Rights []string `json:"rights"` - FeedID int32 `json:"feed_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Title []string `json:"title"` + Creator []string `json:"creator"` + Author []string `json:"author"` + Subject []string `json:"subject"` + Description []string `json:"description"` + Publisher []string `json:"publisher"` + Contributor []string `json:"contributor"` + Date []string `json:"date"` + Type []string `json:"type"` + Format []string `json:"format"` + Identifier []string `json:"identifier"` + Source []string `json:"source"` + Language []string `json:"language"` + Relation []string `json:"relation"` + Coverage []string `json:"coverage"` + Rights []string `json:"rights"` + FeedID int64 `json:"feed_id"` } type FeedExtension struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Name pgtype.Text `json:"name"` - Value pgtype.Text `json:"value"` - Attrs []byte `json:"attrs"` - Children []byte `json:"children"` - FeedID int32 `json:"feed_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Name pgtype.Text `json:"name"` + Value pgtype.Text `json:"value"` + Attrs []byte `json:"attrs"` + Children []byte `json:"children"` + FeedID int64 `json:"feed_id"` } type FeedImage struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Url pgtype.Text `json:"url"` - Title pgtype.Text `json:"title"` - FeedID int32 `json:"feed_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Url pgtype.Text `json:"url"` + Title pgtype.Text `json:"title"` + FeedID int64 `json:"feed_id"` } type FeedItune struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Author pgtype.Text `json:"author"` - Block pgtype.Text `json:"block"` - Explicit pgtype.Text `json:"explicit"` - Keywords pgtype.Text `json:"keywords"` - Subtitle pgtype.Text `json:"subtitle"` - Summary pgtype.Text `json:"summary"` - Image pgtype.Text `json:"image"` - Complete pgtype.Text `json:"complete"` - NewFeedUrl pgtype.Text `json:"new_feed_url"` - Type pgtype.Text `json:"type"` - FeedID int32 `json:"feed_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Author pgtype.Text `json:"author"` + Block pgtype.Text `json:"block"` + Explicit pgtype.Text `json:"explicit"` + Keywords pgtype.Text `json:"keywords"` + Subtitle pgtype.Text `json:"subtitle"` + Summary pgtype.Text `json:"summary"` + Image pgtype.Text `json:"image"` + Complete pgtype.Text `json:"complete"` + NewFeedUrl pgtype.Text `json:"new_feed_url"` + Type pgtype.Text `json:"type"` + FeedID int64 `json:"feed_id"` } type Item struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Title pgtype.Text `json:"title"` - Description pgtype.Text `json:"description"` - Content pgtype.Text `json:"content"` - Link pgtype.Text `json:"link"` - Links []string `json:"links"` - Updated pgtype.Text `json:"updated"` - UpdatedParsed pgtype.Timestamp `json:"updated_parsed"` - Published pgtype.Text `json:"published"` - PublishedParsed pgtype.Timestamp `json:"published_parsed"` - Guid pgtype.Text `json:"guid"` - Categories []string `json:"categories"` - Custom []byte `json:"custom"` - FeedID int32 `json:"feed_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Title pgtype.Text `json:"title"` + Description pgtype.Text `json:"description"` + Content pgtype.Text `json:"content"` + Link pgtype.Text `json:"link"` + Links []string `json:"links"` + Updated pgtype.Text `json:"updated"` + UpdatedParsed pgtype.Timestamp `json:"updated_parsed"` + Published pgtype.Text `json:"published"` + PublishedParsed pgtype.Timestamp `json:"published_parsed"` + Guid pgtype.Text `json:"guid"` + Categories []string `json:"categories"` + Custom []byte `json:"custom"` + FeedID int64 `json:"feed_id"` } type ItemAuthor struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Name pgtype.Text `json:"name"` - Email pgtype.Text `json:"email"` - Uri pgtype.Text `json:"uri"` - ItemID int32 `json:"item_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Name pgtype.Text `json:"name"` + Email pgtype.Text `json:"email"` + Uri pgtype.Text `json:"uri"` + ItemID int64 `json:"item_id"` } type ItemDublinCore struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Title []string `json:"title"` - Creator []string `json:"creator"` - Author []string `json:"author"` - Subject []string `json:"subject"` - Description []string `json:"description"` - Publisher []string `json:"publisher"` - Contributor []string `json:"contributor"` - Date []string `json:"date"` - Type []string `json:"type"` - Format []string `json:"format"` - Identifier []string `json:"identifier"` - Source []string `json:"source"` - Language []string `json:"language"` - Relation []string `json:"relation"` - Coverage []string `json:"coverage"` - Rights []string `json:"rights"` - ItemID int32 `json:"item_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Title []string `json:"title"` + Creator []string `json:"creator"` + Author []string `json:"author"` + Subject []string `json:"subject"` + Description []string `json:"description"` + Publisher []string `json:"publisher"` + Contributor []string `json:"contributor"` + Date []string `json:"date"` + Type []string `json:"type"` + Format []string `json:"format"` + Identifier []string `json:"identifier"` + Source []string `json:"source"` + Language []string `json:"language"` + Relation []string `json:"relation"` + Coverage []string `json:"coverage"` + Rights []string `json:"rights"` + ItemID int64 `json:"item_id"` } type ItemExtension struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Name pgtype.Text `json:"name"` - Value pgtype.Text `json:"value"` - Attrs []byte `json:"attrs"` - Children []byte `json:"children"` - ItemID int32 `json:"item_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Name pgtype.Text `json:"name"` + Value pgtype.Text `json:"value"` + Attrs []byte `json:"attrs"` + Children []byte `json:"children"` + ItemID int64 `json:"item_id"` } type ItemImage struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Url pgtype.Text `json:"url"` - Title pgtype.Text `json:"title"` - ItemID int32 `json:"item_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Url pgtype.Text `json:"url"` + Title pgtype.Text `json:"title"` + ItemID int64 `json:"item_id"` } type ItemItune struct { - ID int32 `json:"id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - DeletedAt pgtype.Timestamp `json:"deleted_at"` - Author pgtype.Text `json:"author"` - Block pgtype.Text `json:"block"` - Duration pgtype.Text `json:"duration"` - Explicit pgtype.Text `json:"explicit"` - Keywords pgtype.Text `json:"keywords"` - Subtitle pgtype.Text `json:"subtitle"` - Summary pgtype.Text `json:"summary"` - Image pgtype.Text `json:"image"` - IsClosedCaptioned pgtype.Text `json:"is_closed_captioned"` - Episode pgtype.Text `json:"episode"` - Season pgtype.Text `json:"season"` - Order pgtype.Text `json:"order"` - EpisodeType pgtype.Text `json:"episode_type"` - ItemID int32 `json:"item_id"` + ID int64 `json:"id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` + Author pgtype.Text `json:"author"` + Block pgtype.Text `json:"block"` + Duration pgtype.Text `json:"duration"` + Explicit pgtype.Text `json:"explicit"` + Keywords pgtype.Text `json:"keywords"` + Subtitle pgtype.Text `json:"subtitle"` + Summary pgtype.Text `json:"summary"` + Image pgtype.Text `json:"image"` + IsClosedCaptioned pgtype.Text `json:"is_closed_captioned"` + Episode pgtype.Text `json:"episode"` + Season pgtype.Text `json:"season"` + Order pgtype.Text `json:"order"` + EpisodeType pgtype.Text `json:"episode_type"` + ItemID int64 `json:"item_id"` } type ItunesCategory struct { - ID int32 `json:"id"` + ID int64 `json:"id"` CreatedAt pgtype.Timestamp `json:"created_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"` DeletedAt pgtype.Timestamp `json:"deleted_at"` Text pgtype.Text `json:"text"` Subcategory pgtype.Text `json:"subcategory"` - ItunesID int32 `json:"itunes_id"` + ItunesID int64 `json:"itunes_id"` } type ItunesOwner struct { - ID int32 `json:"id"` + ID int64 `json:"id"` CreatedAt pgtype.Timestamp `json:"created_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"` DeletedAt pgtype.Timestamp `json:"deleted_at"` Email pgtype.Text `json:"email"` Name pgtype.Text `json:"name"` - ItunesID int32 `json:"itunes_id"` + ItunesID int64 `json:"itunes_id"` } diff --git a/db/querier.go b/db/querier.go index a86dd69..c6fdf11 100644 --- a/db/querier.go +++ b/db/querier.go @@ -10,7 +10,13 @@ import ( type Querier interface { CountFeeds(ctx context.Context) (int64, error) + CountItems(ctx context.Context) (int64, error) CreateFeed(ctx context.Context, arg CreateFeedParams) (Feed, error) + CreateItem(ctx context.Context, arg CreateItemParams) (Item, error) + GetFeed(ctx context.Context, id int64) (Feed, error) + GetFeeds(ctx context.Context, arg GetFeedsParams) ([]Feed, error) + GetItem(ctx context.Context, id int64) (Item, error) + GetItems(ctx context.Context, arg GetItemsParams) ([]Item, error) } var _ Querier = (*Queries)(nil) diff --git a/feeds.go b/feeds.go index 5410595..3c47508 100644 --- a/feeds.go +++ b/feeds.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" "time" "github.com/TheLovinator1/FeedVault/db" @@ -12,11 +13,6 @@ import ( ) func makeCreateFeedParams(feedURL string, feed *gofeed.Feed) db.CreateFeedParams { - links := make([]string, len(feed.Items)) - for i, item := range feed.Items { - links[i] = item.Link - } - var updatedTime time.Time if feed.UpdatedParsed != nil { updatedTime = *feed.UpdatedParsed @@ -32,20 +28,20 @@ func makeCreateFeedParams(feedURL string, feed *gofeed.Feed) db.CreateFeedParams feedCustom = []byte("{}") } - return db.CreateFeedParams{ + params := db.CreateFeedParams{ Url: feedURL, - CreatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true}, - UpdatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true}, - DeletedAt: pgtype.Timestamp{Valid: false}, + CreatedAt: pgtype.Timestamptz{Time: time.Now(), Valid: true}, + UpdatedAt: pgtype.Timestamptz{Time: time.Now(), Valid: true}, + DeletedAt: pgtype.Timestamptz{Valid: false}, Title: pgtype.Text{String: feed.Title, Valid: feed.Title != ""}, Description: pgtype.Text{String: feed.Description, Valid: feed.Description != ""}, Link: pgtype.Text{String: feed.Link, Valid: feed.Link != ""}, FeedLink: pgtype.Text{String: feed.FeedLink, Valid: feed.FeedLink != ""}, - Links: links, + Links: feed.Links, Updated: pgtype.Text{String: feed.Updated, Valid: feed.Updated != ""}, - UpdatedParsed: pgtype.Timestamp{Time: updatedTime, Valid: !updatedTime.IsZero()}, + UpdatedParsed: pgtype.Timestamptz{Time: updatedTime, Valid: !updatedTime.IsZero()}, Published: pgtype.Text{String: feed.Published, Valid: feed.Published != ""}, - PublishedParsed: pgtype.Timestamp{Time: publishedTime, Valid: !publishedTime.IsZero()}, + PublishedParsed: pgtype.Timestamptz{Time: publishedTime, Valid: !publishedTime.IsZero()}, Language: pgtype.Text{String: feed.Language, Valid: feed.Language != ""}, Copyright: pgtype.Text{String: feed.Copyright, Valid: feed.Copyright != ""}, Generator: pgtype.Text{String: feed.Generator, Valid: feed.Generator != ""}, @@ -54,6 +50,45 @@ func makeCreateFeedParams(feedURL string, feed *gofeed.Feed) db.CreateFeedParams FeedType: pgtype.Text{String: feed.FeedType, Valid: feed.FeedType != ""}, FeedVersion: pgtype.Text{String: feed.FeedVersion, Valid: feed.FeedVersion != ""}, } + + log.Printf("Created feed params: %+v", params) + + return params +} + +func makeCreateItemParams(item *gofeed.Item, feedID int64) db.CreateItemParams { + itemCustom := []byte("{}") + if item.Custom != nil { + var err error + itemCustom, err = json.Marshal(item.Custom) + if err != nil { + fmt.Println("Error marshalling item custom data:", err) + itemCustom = []byte("{}") + } + } + + params := db.CreateItemParams{ + CreatedAt: pgtype.Timestamptz{Time: time.Now(), Valid: true}, + UpdatedAt: pgtype.Timestamptz{Time: time.Now(), Valid: true}, + DeletedAt: pgtype.Timestamptz{Valid: false}, + Title: pgtype.Text{String: item.Title, Valid: item.Title != ""}, + Description: pgtype.Text{String: item.Description, Valid: item.Description != ""}, + Content: pgtype.Text{String: item.Content, Valid: item.Content != ""}, + Link: pgtype.Text{String: item.Link, Valid: item.Link != ""}, + Links: item.Links, + Updated: pgtype.Text{String: item.Updated, Valid: item.Updated != ""}, + UpdatedParsed: pgtype.Timestamp{Time: *item.UpdatedParsed, Valid: item.UpdatedParsed != nil}, + Published: pgtype.Text{String: item.Published, Valid: item.Published != ""}, + PublishedParsed: pgtype.Timestamp{Time: *item.PublishedParsed, Valid: item.PublishedParsed != nil}, + Guid: pgtype.Text{String: item.GUID, Valid: item.GUID != ""}, + Categories: item.Categories, + Custom: itemCustom, + FeedID: feedID, + } + + log.Printf("Created item params: %+v", params) + + return params } func AddFeedToDB(feedURL string) error { @@ -71,10 +106,19 @@ func AddFeedToDB(feedURL string) error { } // Add the feed to the database - _, err = DB.CreateFeed(ctx, makeCreateFeedParams(feedURL, feed)) + newFeed, err := DB.CreateFeed(ctx, makeCreateFeedParams(feedURL, feed)) if err != nil { return fmt.Errorf("Error adding feed to database: %s", err) } + log.Printf("Added feed to database: %+v", newFeed) + + // Add the items to the database + for _, item := range feed.Items { + _, err := DB.CreateItem(ctx, makeCreateItemParams(item, newFeed.ID)) + if err != nil { + log.Printf("Error adding item to database: %s", err) + } + } fmt.Println(feed.Title) return nil diff --git a/handlers.go b/handlers.go index 5834093..40205d4 100644 --- a/handlers.go +++ b/handlers.go @@ -1,11 +1,15 @@ package main import ( + "context" "io" "log" "net/http" + "strconv" "strings" + + "github.com/TheLovinator1/FeedVault/db" ) func ApiHandler(w http.ResponseWriter, _ *http.Request) { @@ -25,16 +29,31 @@ func ApiHandler(w http.ResponseWriter, _ *http.Request) { } func FeedsHandler(w http.ResponseWriter, _ *http.Request) { + feeds, err := DB.GetFeeds(context.Background(), db.GetFeedsParams{ + Limit: 100, + }) + if err != nil { + http.Error(w, "Error getting feeds", http.StatusInternalServerError) + return + } + + fb := strings.Builder{} + for _, feed := range feeds { + fb.WriteString("
  • ") + fb.WriteString("" + feed.Title.String + " - " + feed.Link.String + "") + fb.WriteString("
  • ") + } + htmlData := HTMLData{ Title: "FeedVault Feeds", Description: "FeedVault Feeds - A feed archive", Keywords: "RSS, Atom, Feed, Archive", Author: "TheLovinator", CanonicalURL: "http://localhost:8000/feeds", - Content: "

    No feeds yet.

    ", + Content: "", } html := FullHTML(htmlData) - _, err := w.Write([]byte(html)) + _, err = w.Write([]byte(html)) if err != nil { log.Println("Error writing response:", err) } @@ -226,3 +245,71 @@ func UploadOpmlHandler(w http.ResponseWriter, r *http.Request) { log.Println("Error writing response:", err) } } + +func FeedHandler(w http.ResponseWriter, r *http.Request) { + // Get the feed ID from the URL + parts := strings.Split(r.URL.Path, "/") + if len(parts) < 3 { + http.Error(w, "No feed ID provided", http.StatusBadRequest) + return + } + feedID, err := strconv.ParseInt(parts[2], 10, 64) + if err != nil { + http.Error(w, "Invalid feed ID", http.StatusBadRequest) + return + } + + // Get the feed from the database + feed, err := DB.GetFeed(context.Background(), feedID) + if err != nil { + http.Error(w, "Error getting feed", http.StatusInternalServerError) + return + } + + // Get the items for the feed + items, err := DB.GetItems(context.Background(), db.GetItemsParams{ + FeedID: feedID, + Limit: 100, + }) + if err != nil { + http.Error(w, "Error getting items", http.StatusInternalServerError) + return + } + + // Build the HTML + fb := strings.Builder{} + for _, item := range items { + fb.WriteString("
  • ") + fb.WriteString("" + item.Title.String + "") + fb.WriteString("") + fb.WriteString("
    ") + fb.WriteString("
  • ") + } + + htmlData := HTMLData{ + Title: feed.Title.String, + Description: feed.Description.String, + Keywords: "RSS, Atom, Feed, Archive", + Author: "TheLovinator", + CanonicalURL: "http://localhost:8000/feed/" + strconv.FormatInt(feed.ID, 10), + Content: "", + } + html := FullHTML(htmlData) + _, err = w.Write([]byte(html)) + if err != nil { + log.Println("Error writing response:", err) + } +} diff --git a/main.go b/main.go index ed03ca7..3e3dbc7 100644 --- a/main.go +++ b/main.go @@ -41,6 +41,7 @@ func main() { mux.HandleFunc("/", IndexHandler) mux.HandleFunc("/api", ApiHandler) mux.HandleFunc("/feeds", FeedsHandler) + mux.HandleFunc("/feed/", FeedHandler) mux.HandleFunc("/add", AddFeedHandler) mux.HandleFunc("/upload_opml", UploadOpmlHandler) diff --git a/sql/queries/feeds.sql b/sql/queries/feeds.sql index bb1a45a..90731b1 100644 --- a/sql/queries/feeds.sql +++ b/sql/queries/feeds.sql @@ -51,3 +51,87 @@ SELECT COUNT(*) FROM feeds; + +-- name: CreateItem :one +INSERT INTO + items ( + created_at, + updated_at, + deleted_at, + title, + "description", + content, + link, + links, + updated, + updated_parsed, + published, + published_parsed, + "guid", + categories, + custom, + feed_id + ) +VALUES + ( + $1, + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + $11, + $12, + $13, + $14, + $15, + $16 + ) RETURNING *; + +-- name: CountItems :one +SELECT + COUNT(*) +FROM + items; + +-- name: GetFeed :one +SELECT + * +FROM + feeds +WHERE + id = $1; + +-- name: GetFeeds :many +SELECT + * +FROM + feeds +ORDER BY + created_at DESC +LIMIT $1 +OFFSET $2; + +-- name: GetItem :one +SELECT + * +FROM + items +WHERE + id = $1; + +-- name: GetItems :many +SELECT + * +FROM + items +WHERE + feed_id = $1 +ORDER BY + created_at DESC +LIMIT $2 +OFFSET $3; diff --git a/sql/schema/20240214043229_feeds.sql b/sql/schema/20240214043229_feeds.sql index 6e3ff62..87911c3 100644 --- a/sql/schema/20240214043229_feeds.sql +++ b/sql/schema/20240214043229_feeds.sql @@ -2,11 +2,11 @@ -- +goose StatementBegin -- Create table feeds if not exists CREATE TABLE IF NOT EXISTS feeds ( - id SERIAL PRIMARY KEY, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "url" TEXT NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: https://github.com/mmcdole/gofeed/blob/master/feed.go title TEXT, "description" TEXT, @@ -14,9 +14,9 @@ CREATE TABLE IF NOT EXISTS feeds ( feed_link TEXT, links TEXT [], updated TEXT, - updated_parsed TIMESTAMP, + updated_parsed TIMESTAMPTZ, published TEXT, - published_parsed TIMESTAMP, + published_parsed TIMESTAMPTZ, -- Authors - See feed_authors "language" TEXT, -- Image - See feed_images @@ -35,10 +35,10 @@ CREATE TABLE IF NOT EXISTS feeds ( -- Feed item -- https://github.com/mmcdole/gofeed/blob/master/feed.go#L49 CREATE TABLE IF NOT EXISTS items ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: title TEXT, "description" TEXT, @@ -59,7 +59,7 @@ CREATE TABLE IF NOT EXISTS items ( -- Extensions - See item_extensions custom JSONB, -- Link to feed - feed_id INTEGER NOT NULL, + feed_id BIGINT NOT NULL, CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE ); diff --git a/sql/schema/20240215232236_extensions.sql b/sql/schema/20240215232236_extensions.sql index 354f4ee..52a38d3 100644 --- a/sql/schema/20240215232236_extensions.sql +++ b/sql/schema/20240215232236_extensions.sql @@ -3,34 +3,34 @@ -- Extensions for feeds -- https://github.com/mmcdole/gofeed/blob/master/extensions/extensions.go#L3 CREATE TABLE IF NOT EXISTS feed_extensions ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "name" TEXT, "value" TEXT, attrs JSONB, children JSONB, -- Link to feed - feed_id INTEGER NOT NULL, + feed_id BIGINT NOT NULL, CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE ); -- Extensions for items -- https://github.com/mmcdole/gofeed/blob/master/extensions/extensions.go#L3 CREATE TABLE IF NOT EXISTS item_extensions ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "name" TEXT, "value" TEXT, attrs JSONB, children JSONB, -- Link to feed item (Also called feed entry) - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE ); diff --git a/sql/schema/20240215232245_authors.sql b/sql/schema/20240215232245_authors.sql index a932655..ecdd0e8 100644 --- a/sql/schema/20240215232245_authors.sql +++ b/sql/schema/20240215232245_authors.sql @@ -3,32 +3,32 @@ -- Person for feeds -- https://github.com/mmcdole/gofeed/blob/master/feed.go#L73 CREATE TABLE IF NOT EXISTS feed_authors ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "name" TEXT, email TEXT, uri TEXT, -- Link to feed - feed_id INTEGER NOT NULL, + feed_id BIGINT NOT NULL, CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE ); -- Person for items -- https://github.com/mmcdole/gofeed/blob/master/feed.go#L73 CREATE TABLE IF NOT EXISTS item_authors ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "name" TEXT, email TEXT, uri TEXT, -- Link to feed item (Also called feed entry) - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE ); diff --git a/sql/schema/20240215232251_images.sql b/sql/schema/20240215232251_images.sql index 92000e7..5933861 100644 --- a/sql/schema/20240215232251_images.sql +++ b/sql/schema/20240215232251_images.sql @@ -3,30 +3,30 @@ -- Image for feeds -- https://github.com/mmcdole/gofeed/blob/master/feed.go#L80 CREATE TABLE IF NOT EXISTS feed_images ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "url" TEXT, title TEXT, -- Link to feed - feed_id INTEGER NOT NULL, + feed_id BIGINT NOT NULL, CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE ); -- Image for items -- https://github.com/mmcdole/gofeed/blob/master/feed.go#L80 CREATE TABLE IF NOT EXISTS item_images ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "url" TEXT, title TEXT, -- Link to feed item (Also called feed entry) - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE ); diff --git a/sql/schema/20240215232259_dublin_cores.sql b/sql/schema/20240215232259_dublin_cores.sql index 3d7fe79..8f1e251 100644 --- a/sql/schema/20240215232259_dublin_cores.sql +++ b/sql/schema/20240215232259_dublin_cores.sql @@ -3,10 +3,10 @@ -- Dublin Core for feeds -- https://github.com/mmcdole/gofeed/blob/master/extensions/dublincore.go#L5 CREATE TABLE IF NOT EXISTS feed_dublin_cores ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: title TEXT [], creator TEXT [], @@ -25,17 +25,17 @@ CREATE TABLE IF NOT EXISTS feed_dublin_cores ( coverage TEXT [], rights TEXT [], -- Link to feed - feed_id INTEGER NOT NULL, + feed_id BIGINT NOT NULL, CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE ); -- Dublin Core for items -- https://github.com/mmcdole/gofeed/blob/master/extensions/dublincore.go#L5 CREATE TABLE IF NOT EXISTS item_dublin_cores ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: title TEXT [], creator TEXT [], @@ -54,7 +54,7 @@ CREATE TABLE IF NOT EXISTS item_dublin_cores ( coverage TEXT [], rights TEXT [], -- Link to feed item (Also called feed entry) - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE ); diff --git a/sql/schema/20240215232318_itunes.sql b/sql/schema/20240215232318_itunes.sql index f57a864..6c356ac 100644 --- a/sql/schema/20240215232318_itunes.sql +++ b/sql/schema/20240215232318_itunes.sql @@ -3,10 +3,10 @@ -- Itunes for feeds -- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L5 CREATE TABLE IF NOT EXISTS feed_itunes ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: author TEXT, "block" TEXT, @@ -20,17 +20,17 @@ CREATE TABLE IF NOT EXISTS feed_itunes ( new_feed_url TEXT, "type" TEXT, -- Link to feed - feed_id INTEGER NOT NULL, + feed_id BIGINT NOT NULL, CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE ); -- Itunes for items -- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L22 CREATE TABLE IF NOT EXISTS item_itunes ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: author TEXT, "block" TEXT, @@ -46,14 +46,14 @@ CREATE TABLE IF NOT EXISTS item_itunes ( "order" TEXT, episode_type TEXT, -- Link to feed item (Also called feed entry) - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE ); -- Itunes categories -- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L39 CREATE TABLE IF NOT EXISTS itunes_categories ( - id SERIAL PRIMARY KEY, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP DEFAULT NULL, @@ -61,14 +61,14 @@ CREATE TABLE IF NOT EXISTS itunes_categories ( "text" TEXT, subcategory TEXT, -- Link to itunes - itunes_id INTEGER NOT NULL, + itunes_id BIGINT NOT NULL, CONSTRAINT fk_itunes_id FOREIGN KEY (itunes_id) REFERENCES feed_itunes (id) ON DELETE CASCADE ); -- Itunes owners -- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L45 CREATE TABLE IF NOT EXISTS itunes_owners ( - id SERIAL PRIMARY KEY, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP DEFAULT NULL, @@ -76,7 +76,7 @@ CREATE TABLE IF NOT EXISTS itunes_owners ( email TEXT, "name" TEXT, -- Link to itunes - itunes_id INTEGER NOT NULL, + itunes_id BIGINT NOT NULL, CONSTRAINT fk_itunes_id FOREIGN KEY (itunes_id) REFERENCES feed_itunes (id) ON DELETE CASCADE ); diff --git a/sql/schema/20240215232334_enclousures.sql b/sql/schema/20240215232334_enclousures.sql index 4ba553d..fce0c36 100644 --- a/sql/schema/20240215232334_enclousures.sql +++ b/sql/schema/20240215232334_enclousures.sql @@ -3,16 +3,16 @@ -- Enclosures -- https://github.com/mmcdole/gofeed/blob/master/feed.go#L86 CREATE TABLE IF NOT EXISTS enclosures ( - id SERIAL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP DEFAULT NULL, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMPTZ DEFAULT NULL, -- From gofeed: "url" TEXT, "length" TEXT, "type" TEXT, -- Link to feed item (Also called feed entry) - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE );