diff --git a/appview/db/db.go b/appview/db/db.go index afb4fe95..45cafa30 100644 --- a/appview/db/db.go +++ b/appview/db/db.go @@ -470,6 +470,10 @@ func Make(dbPath string) (*DB, error) { id integer primary key autoincrement, name text unique ); + + -- indexes for better star query performance + create index if not exists idx_stars_created on stars(created); + create index if not exists idx_stars_repo_at_created on stars(repo_at, created); `) if err != nil { return nil, err diff --git a/appview/db/star.go b/appview/db/star.go index 7a005f3b..fa2655a8 100644 --- a/appview/db/star.go +++ b/appview/db/star.go @@ -47,7 +47,7 @@ func AddStar(e Execer, star *Star) error { // Get a star record func GetStar(e Execer, starredByDid string, repoAt syntax.ATURI) (*Star, error) { query := ` - select starred_by_did, repo_at, created, rkey + select starred_by_did, repo_at, created, rkey from stars where starred_by_did = ? and repo_at = ?` row := e.QueryRow(query, starredByDid, repoAt) @@ -119,7 +119,7 @@ func GetStars(e Execer, limit int, filters ...filter) ([]Star, error) { } repoQuery := fmt.Sprintf( - `select starred_by_did, repo_at, created, rkey + `select starred_by_did, repo_at, created, rkey from stars %s order by created desc @@ -187,7 +187,7 @@ func GetAllStars(e Execer, limit int) ([]Star, error) { var stars []Star rows, err := e.Query(` - select + select s.starred_by_did, s.repo_at, s.rkey, @@ -244,3 +244,72 @@ func GetAllStars(e Execer, limit int) ([]Star, error) { return stars, nil } + +// GetTopStarredReposLastWeek returns the top 8 most starred repositories from the last week +func GetTopStarredReposLastWeek(e Execer) ([]Repo, error) { + // first, get the top repo URIs by star count from the last week + query := ` + with recent_starred_repos as ( + select distinct repo_at + from stars + where created >= datetime('now', '-7 days') + ), + repo_star_counts as ( + select + s.repo_at, + count(*) as star_count + from stars s + join recent_starred_repos rsr on s.repo_at = rsr.repo_at + group by s.repo_at + ) + select rsc.repo_at + from repo_star_counts rsc + order by rsc.star_count desc + limit 8 + ` + + rows, err := e.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + var repoUris []string + for rows.Next() { + var repoUri string + err := rows.Scan(&repoUri) + if err != nil { + return nil, err + } + repoUris = append(repoUris, repoUri) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + if len(repoUris) == 0 { + return []Repo{}, nil + } + + // get full repo data + repos, err := GetRepos(e, 0, FilterIn("at_uri", repoUris)) + if err != nil { + return nil, err + } + + // sort repos by the original trending order + repoMap := make(map[string]Repo) + for _, repo := range repos { + repoMap[repo.RepoAt().String()] = repo + } + + orderedRepos := make([]Repo, 0, len(repoUris)) + for _, uri := range repoUris { + if repo, exists := repoMap[uri]; exists { + orderedRepos = append(orderedRepos, repo) + } + } + + return orderedRepos, nil +} diff --git a/appview/pages/pages.go b/appview/pages/pages.go index e12e3ee2..f133a3b4 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -302,7 +302,16 @@ type TimelineParams struct { } func (p *Pages) Timeline(w io.Writer, params TimelineParams) error { - return p.execute("timeline", w, params) + return p.execute("timeline/timeline", w, params) +} + +type TopStarredReposLastWeekParams struct { + LoggedInUser *oauth.User + Repos []db.Repo +} + +func (p *Pages) TopStarredReposLastWeek(w io.Writer, params TopStarredReposLastWeekParams) error { + return p.executePlain("timeline/fragments/topStarredRepos", w, params) } type SettingsParams struct { diff --git a/appview/pages/templates/timeline/fragments/topStarredRepos.html b/appview/pages/templates/timeline/fragments/topStarredRepos.html new file mode 100644 index 00000000..e3fa2608 --- /dev/null +++ b/appview/pages/templates/timeline/fragments/topStarredRepos.html @@ -0,0 +1,25 @@ +{{ define "timeline/fragments/topStarredRepos" }} +