func (e *EntryQueryBuilder) GetEntryIDs() ([]int64, error) {
	query := `SELECT e.id FROM entries e LEFT JOIN feeds f ON f.id=e.feed_id WHERE %s %s`
	condition := e.buildCondition()
	query = fmt.Sprintf(query, condition, e.buildSorting())
	rows, err := e.store.db.Query(query, e.args...)
	if err != nil {
		return nil, fmt.Errorf("unable to get entries: %v", err)
	}
	defer rows.Close()
	var entryIDs []int64
	for rows.Next() {
		var entryID int64
		err := rows.Scan(&entryID)
		if err != nil {
			return nil, fmt.Errorf("unable to fetch entry row: %v", err)
		}
		entryIDs = append(entryIDs, entryID)
	}
	return entryIDs, nil
}
GetEntryIDs returns a list of entry IDs that match the condition.
package storage  
import (
	"database/sql"
	"fmt"
	"strings"
	"time"
	"github.com/lib/pq"
	"miniflux.app/model"
	"miniflux.app/timezone"
)
type EntryQueryBuilder struct {
	store      *Storage
	args       []interface{}
	conditions []string
	order      string
	direction  string
	limit      int
	offset     int
}
func (e *EntryQueryBuilder) WithSearchQuery(query string) *EntryQueryBuilder {
	if query != "" {
		nArgs := len(e.args) + 1
		e.conditions = append(e.conditions, fmt.Sprintf("e.document_vectors @@ plainto_tsquery($%d)", nArgs))
		e.args = append(e.args, query)
		e.WithOrder(fmt.Sprintf("ts_rank(document_vectors, plainto_tsquery($%d)) - extract (epoch from now() - published_at)::float * 0.0000001", nArgs))
		e.WithDirection("DESC")
	}
	return e
}
func (e *EntryQueryBuilder) WithStarred() *EntryQueryBuilder {
	e.conditions = append(e.conditions, "e.starred is true")
	return e
}
func (e *EntryQueryBuilder) BeforeDate(date time.Time) *EntryQueryBuilder {
	e.conditions = append(e.conditions, fmt.Sprintf("e.published_at < $%d", len(e.args)+1))
	e.args = append(e.args, date)
	return e
}
func (e *EntryQueryBuilder) AfterDate(date time.Time) *EntryQueryBuilder {
	e.conditions = append(e.conditions, fmt.Sprintf("e.published_at > $%d", len(e.args)+1))
	e.args = append(e.args, date)
	return e
}
func (e *EntryQueryBuilder) BeforeEntryID(entryID int64) *EntryQueryBuilder {
	if entryID != 0 {
		e.conditions = append(e.conditions, fmt.Sprintf("e.id < $%d", len(e.args)+1))
		e.args = append(e.args, entryID)
	}
	return e
}
func (e *EntryQueryBuilder) AfterEntryID(entryID int64) *EntryQueryBuilder {
	if entryID != 0 {
		e.conditions = append(e.conditions, fmt.Sprintf("e.id > $%d", len(e.args)+1))
		e.args = append(e.args, entryID)
	}
	return e
}
func (e *EntryQueryBuilder) WithEntryIDs(entryIDs []int64) *EntryQueryBuilder {
	e.conditions = append(e.conditions, fmt.Sprintf("e.id = ANY($%d)", len(e.args)+1))
	e.args = append(e.args, pq.Int64Array(entryIDs))
	return e
}
func (e *EntryQueryBuilder) WithEntryID(entryID int64) *EntryQueryBuilder {
	if entryID != 0 {
		e.conditions = append(e.conditions, fmt.Sprintf("e.id = $%d", len(e.args)+1))
		e.args = append(e.args, entryID)
	}
	return e
}
func (e *EntryQueryBuilder) WithFeedID(feedID int64) *EntryQueryBuilder {
	if feedID > 0 {
		e.conditions = append(e.conditions, fmt.Sprintf("e.feed_id = $%d", len(e.args)+1))
		e.args = append(e.args, feedID)
	}
	return e
}
func (e *EntryQueryBuilder) WithCategoryID(categoryID int64) *EntryQueryBuilder {
	if categoryID > 0 {
		e.conditions = append(e.conditions, fmt.Sprintf("f.category_id = $%d", len(e.args)+1))
		e.args = append(e.args, categoryID)
	}
	return e
}
func (e *EntryQueryBuilder) WithStatus(status string) *EntryQueryBuilder {
	if status != "" {
		e.conditions = append(e.conditions, fmt.Sprintf("e.status = $%d", len(e.args)+1))
		e.args = append(e.args, status)
	}
	return e
}
func (e *EntryQueryBuilder) WithStatuses(statuses []string) *EntryQueryBuilder {
	if len(statuses) > 0 {
		e.conditions = append(e.conditions, fmt.Sprintf("e.status = ANY($%d)", len(e.args)+1))
		e.args = append(e.args, pq.StringArray(statuses))
	}
	return e
}
func (e *EntryQueryBuilder) WithoutStatus(status string) *EntryQueryBuilder {
	if status != "" {
		e.conditions = append(e.conditions, fmt.Sprintf("e.status <> $%d", len(e.args)+1))
		e.args = append(e.args, status)
	}
	return e
}
func (e *EntryQueryBuilder) WithShareCode(shareCode string) *EntryQueryBuilder {
	e.conditions = append(e.conditions, fmt.Sprintf("e.share_code = $%d", len(e.args)+1))
	e.args = append(e.args, shareCode)
	return e
}
func (e *EntryQueryBuilder) WithShareCodeNotEmpty() *EntryQueryBuilder {
	e.conditions = append(e.conditions, "e.share_code <> ''")
	return e
}
func (e *EntryQueryBuilder) WithOrder(order string) *EntryQueryBuilder {
	e.order = order
	return e
}
func (e *EntryQueryBuilder) WithDirection(direction string) *EntryQueryBuilder {
	e.direction = direction
	return e
}
func (e *EntryQueryBuilder) WithLimit(limit int) *EntryQueryBuilder {
	if limit > 0 {
		e.limit = limit
	}
	return e
}
func (e *EntryQueryBuilder) WithOffset(offset int) *EntryQueryBuilder {
	if offset > 0 {
		e.offset = offset
	}
	return e
}
func (e *EntryQueryBuilder) WithGloballyVisible() *EntryQueryBuilder {
	e.conditions = append(e.conditions, "not c.hide_globally")
	e.conditions = append(e.conditions, "not f.hide_globally")
	return e
}
func (e *EntryQueryBuilder) CountEntries() (count int, err error) {
	query := `
		SELECT count(*)
		FROM entries e
			JOIN feeds f ON f.id = e.feed_id
			JOIN categories c ON c.id = f.category_id
		WHERE %s
	`
	condition := e.buildCondition()
	err = e.store.db.QueryRow(fmt.Sprintf(query, condition), e.args...).Scan(&count)
	if err != nil {
		return 0, fmt.Errorf("unable to count entries: %v", err)
	}
	return count, nil
}
func (e *EntryQueryBuilder) GetEntry() (*model.Entry, error) {
	e.limit = 1
	entries, err := e.GetEntries()
	if err != nil {
		return nil, err
	}
	if len(entries) != 1 {
		return nil, nil
	}
	entries[0].Enclosures, err = e.store.GetEnclosures(entries[0].ID)
	if err != nil {
		return nil, err
	}
	return entries[0], nil
}
func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
	query := `
		SELECT
			e.id,
			e.user_id,
			e.feed_id,
			e.hash,
			e.published_at at time zone u.timezone,
			e.title,
			e.url,
			e.comments_url,
			e.author,
			e.share_code,
			e.content,
			e.status,
			e.starred,
			e.reading_time,
			e.created_at,
			e.changed_at,
			f.title as feed_title,
			f.feed_url,
			f.site_url,
			f.checked_at,
			f.category_id, c.title as category_title,
			f.scraper_rules,
			f.rewrite_rules,
			f.crawler,
			f.user_agent,
			f.cookie,
			fi.icon_id,
			u.timezone
		FROM
			entries e
		LEFT JOIN
			feeds f ON f.id=e.feed_id
		LEFT JOIN
			categories c ON c.id=f.category_id
		LEFT JOIN
			feed_icons fi ON fi.feed_id=f.id
		LEFT JOIN
			users u ON u.id=e.user_id
		WHERE %s %s
	`
	condition := e.buildCondition()
	sorting := e.buildSorting()
	query = fmt.Sprintf(query, condition, sorting)
	rows, err := e.store.db.Query(query, e.args...)
	if err != nil {
		return nil, fmt.Errorf("unable to get entries: %v", err)
	}
	defer rows.Close()
	entries := make(model.Entries, 0)
	for rows.Next() {
		var entry model.Entry
		var iconID sql.NullInt64
		var tz string
		entry.Feed = &model.Feed{}
		entry.Feed.Category = &model.Category{}
		entry.Feed.Icon = &model.FeedIcon{}
		err := rows.Scan(
			&entry.ID,
			&entry.UserID,
			&entry.FeedID,
			&entry.Hash,
			&entry.Date,
			&entry.Title,
			&entry.URL,
			&entry.CommentsURL,
			&entry.Author,
			&entry.ShareCode,
			&entry.Content,
			&entry.Status,
			&entry.Starred,
			&entry.ReadingTime,
			&entry.CreatedAt,
			&entry.ChangedAt,
			&entry.Feed.Title,
			&entry.Feed.FeedURL,
			&entry.Feed.SiteURL,
			&entry.Feed.CheckedAt,
			&entry.Feed.Category.ID,
			&entry.Feed.Category.Title,
			&entry.Feed.ScraperRules,
			&entry.Feed.RewriteRules,
			&entry.Feed.Crawler,
			&entry.Feed.UserAgent,
			&entry.Feed.Cookie,
			&iconID,
			&tz,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to fetch entry row: %v", err)
		}
		if iconID.Valid {
			entry.Feed.Icon.IconID = iconID.Int64
		} else {
			entry.Feed.Icon.IconID = 0
		}
		entry.Date = timezone.Convert(tz, entry.Date)
		entry.CreatedAt = timezone.Convert(tz, entry.CreatedAt)
		entry.ChangedAt = timezone.Convert(tz, entry.ChangedAt)
		entry.Feed.CheckedAt = timezone.Convert(tz, entry.Feed.CheckedAt)
		entry.Feed.ID = entry.FeedID
		entry.Feed.UserID = entry.UserID
		entry.Feed.Icon.FeedID = entry.FeedID
		entry.Feed.Category.UserID = entry.UserID
		entries = append(entries, &entry)
	}
	return entries, nil
}