mirror of
https://github.com/miniflux/v2.git
synced 2025-06-27 16:36:00 +00:00
feat(storage): reduce the number of SQL queries when fetching entry enclosures
This commit is contained in:
parent
984a66b590
commit
82a6fe64ae
2 changed files with 65 additions and 11 deletions
|
@ -60,6 +60,51 @@ func (s *Storage) GetEnclosures(entryID int64) (model.EnclosureList, error) {
|
||||||
return enclosures, nil
|
return enclosures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Storage) GetEnclosuresForEntries(entryIDs []int64) (map[int64]model.EnclosureList, error) {
|
||||||
|
query := `
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
user_id,
|
||||||
|
entry_id,
|
||||||
|
url,
|
||||||
|
size,
|
||||||
|
mime_type,
|
||||||
|
media_progression
|
||||||
|
FROM
|
||||||
|
enclosures
|
||||||
|
WHERE
|
||||||
|
entry_id = ANY($1)
|
||||||
|
ORDER BY id ASC
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := s.db.Query(query, pq.Array(entryIDs))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("store: unable to fetch enclosures: %w", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
enclosuresMap := make(map[int64]model.EnclosureList)
|
||||||
|
for rows.Next() {
|
||||||
|
var enclosure model.Enclosure
|
||||||
|
err := rows.Scan(
|
||||||
|
&enclosure.ID,
|
||||||
|
&enclosure.UserID,
|
||||||
|
&enclosure.EntryID,
|
||||||
|
&enclosure.URL,
|
||||||
|
&enclosure.Size,
|
||||||
|
&enclosure.MimeType,
|
||||||
|
&enclosure.MediaProgression,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("store: unable to scan enclosure row: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enclosuresMap[enclosure.EntryID] = append(enclosuresMap[enclosure.EntryID], &enclosure)
|
||||||
|
}
|
||||||
|
|
||||||
|
return enclosuresMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Storage) GetEnclosure(enclosureID int64) (*model.Enclosure, error) {
|
func (s *Storage) GetEnclosure(enclosureID int64) (*model.Enclosure, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -277,7 +277,6 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
|
||||||
e.created_at,
|
e.created_at,
|
||||||
e.changed_at,
|
e.changed_at,
|
||||||
e.tags,
|
e.tags,
|
||||||
(SELECT true FROM enclosures WHERE entry_id=e.id LIMIT 1) as has_enclosure,
|
|
||||||
f.title as feed_title,
|
f.title as feed_title,
|
||||||
f.feed_url,
|
f.feed_url,
|
||||||
f.site_url,
|
f.site_url,
|
||||||
|
@ -319,10 +318,12 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
entries := make(model.Entries, 0)
|
entries := make(model.Entries, 0)
|
||||||
|
entryMap := make(map[int64]*model.Entry)
|
||||||
|
var entryIDs []int64
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var iconID sql.NullInt64
|
var iconID sql.NullInt64
|
||||||
var tz string
|
var tz string
|
||||||
var hasEnclosure sql.NullBool
|
|
||||||
|
|
||||||
entry := model.NewEntry()
|
entry := model.NewEntry()
|
||||||
|
|
||||||
|
@ -344,7 +345,6 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
|
||||||
&entry.CreatedAt,
|
&entry.CreatedAt,
|
||||||
&entry.ChangedAt,
|
&entry.ChangedAt,
|
||||||
pq.Array(&entry.Tags),
|
pq.Array(&entry.Tags),
|
||||||
&hasEnclosure,
|
|
||||||
&entry.Feed.Title,
|
&entry.Feed.Title,
|
||||||
&entry.Feed.FeedURL,
|
&entry.Feed.FeedURL,
|
||||||
&entry.Feed.SiteURL,
|
&entry.Feed.SiteURL,
|
||||||
|
@ -368,20 +368,13 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
|
||||||
return nil, fmt.Errorf("store: unable to fetch entry row: %v", err)
|
return nil, fmt.Errorf("store: unable to fetch entry row: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasEnclosure.Valid && hasEnclosure.Bool && e.fetchEnclosures {
|
|
||||||
entry.Enclosures, err = e.store.GetEnclosures(entry.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("store: unable to fetch enclosures for entry #%d: %w", entry.ID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iconID.Valid {
|
if iconID.Valid {
|
||||||
entry.Feed.Icon.IconID = iconID.Int64
|
entry.Feed.Icon.IconID = iconID.Int64
|
||||||
} else {
|
} else {
|
||||||
entry.Feed.Icon.IconID = 0
|
entry.Feed.Icon.IconID = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that timestamp fields contains timezone information (API)
|
// Make sure that timestamp fields contain timezone information (API)
|
||||||
entry.Date = timezone.Convert(tz, entry.Date)
|
entry.Date = timezone.Convert(tz, entry.Date)
|
||||||
entry.CreatedAt = timezone.Convert(tz, entry.CreatedAt)
|
entry.CreatedAt = timezone.Convert(tz, entry.CreatedAt)
|
||||||
entry.ChangedAt = timezone.Convert(tz, entry.ChangedAt)
|
entry.ChangedAt = timezone.Convert(tz, entry.ChangedAt)
|
||||||
|
@ -391,7 +384,23 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
|
||||||
entry.Feed.UserID = entry.UserID
|
entry.Feed.UserID = entry.UserID
|
||||||
entry.Feed.Icon.FeedID = entry.FeedID
|
entry.Feed.Icon.FeedID = entry.FeedID
|
||||||
entry.Feed.Category.UserID = entry.UserID
|
entry.Feed.Category.UserID = entry.UserID
|
||||||
|
|
||||||
entries = append(entries, entry)
|
entries = append(entries, entry)
|
||||||
|
entryMap[entry.ID] = entry
|
||||||
|
entryIDs = append(entryIDs, entry.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.fetchEnclosures && len(entryIDs) > 0 {
|
||||||
|
enclosures, err := e.store.GetEnclosuresForEntries(entryIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("store: unable to fetch enclosures: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for entryID, entryEnclosures := range enclosures {
|
||||||
|
if entry, exists := entryMap[entryID]; exists {
|
||||||
|
entry.Enclosures = entryEnclosures
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries, nil
|
return entries, nil
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue