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("
No feeds yet.
", + Content: "