| @@ -45,33 +45,39 @@ func (s *Store) dashboardQuery(q string, userID int64) ([]DashboardItem, error) |
| 45 | return out, rows.Err() |
45 | return out, rows.Err() |
| 46 | } |
46 | } |
| 47 | |
47 | |
| |
48 | // The dashboard's four list queries are named so the plan test can assert |
| |
49 | // each still walks the 0035 index that supplies its ORDER BY. |
| |
50 | const dashboardMRsQuery = ` |
| |
51 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
52 | x.number, x.title, au.username, x.state, x.updated_at |
| |
53 | FROM merge_requests x |
| |
54 | JOIN repos r ON r.id = x.repo_id |
| |
55 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
56 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
57 | JOIN users au ON au.id = x.author_id |
| |
58 | WHERE x.state IN ('open', 'source_gone') AND ` + involvedCond + ` |
| |
59 | ORDER BY x.updated_at DESC LIMIT 50` |
| |
60 | |
| 48 | // DashboardMRs returns open merge requests involving the user: on their |
61 | // DashboardMRs returns open merge requests involving the user: on their |
| 49 | // repositories (owned, granted, org) or authored by them anywhere. |
62 | // repositories (owned, granted, org) or authored by them anywhere. |
| 50 | func (s *Store) DashboardMRs(userID int64) ([]DashboardItem, error) { |
63 | func (s *Store) DashboardMRs(userID int64) ([]DashboardItem, error) { |
| 51 | return s.dashboardQuery(` |
64 | return s.dashboardQuery(dashboardMRsQuery, userID) |
| 52 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
| 53 | x.number, x.title, au.username, x.state, x.updated_at |
| |
| 54 | FROM merge_requests x |
| |
| 55 | JOIN repos r ON r.id = x.repo_id |
| |
| 56 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
| 57 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
| 58 | JOIN users au ON au.id = x.author_id |
| |
| 59 | WHERE x.state IN ('open', 'source_gone') AND `+involvedCond+` |
| |
| 60 | ORDER BY x.updated_at DESC LIMIT 50`, userID) |
| |
| 61 | } |
65 | } |
| 62 | |
66 | |
| 63 | // DashboardIssues is the issue counterpart of DashboardMRs. |
67 | // DashboardIssues is the issue counterpart of DashboardMRs. |
| |
68 | const dashboardIssuesQuery = ` |
| |
69 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
70 | x.number, x.title, au.username, x.state, x.updated_at |
| |
71 | FROM issues x |
| |
72 | JOIN repos r ON r.id = x.repo_id |
| |
73 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
74 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
75 | JOIN users au ON au.id = x.author_id |
| |
76 | WHERE x.state = 'open' AND ` + involvedCond + ` |
| |
77 | ORDER BY x.updated_at DESC LIMIT 50` |
| |
78 | |
| 64 | func (s *Store) DashboardIssues(userID int64) ([]DashboardItem, error) { |
79 | func (s *Store) DashboardIssues(userID int64) ([]DashboardItem, error) { |
| 65 | return s.dashboardQuery(` |
80 | return s.dashboardQuery(dashboardIssuesQuery, userID) |
| 66 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
| 67 | x.number, x.title, au.username, x.state, x.updated_at |
| |
| 68 | FROM issues x |
| |
| 69 | JOIN repos r ON r.id = x.repo_id |
| |
| 70 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
| 71 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
| 72 | JOIN users au ON au.id = x.author_id |
| |
| 73 | WHERE x.state = 'open' AND `+involvedCond+` |
| |
| 74 | ORDER BY x.updated_at DESC LIMIT 50`, userID) |
| |
| 75 | } |
81 | } |
| 76 | |
82 | |
| 77 | func (s *Store) PinRepo(userID, repoID int64) error { |
83 | func (s *Store) PinRepo(userID, repoID int64) error { |
| @@ -124,22 +130,24 @@ func (s *Store) PinnedRepos(userID int64) ([]Repo, error) { |
| 124 | // ReviewQueue returns open merge requests the user is involved in, has not |
130 | // ReviewQueue returns open merge requests the user is involved in, has not |
| 125 | // authored, and has not reviewed at the current head — what the rail shows |
131 | // authored, and has not reviewed at the current head — what the rail shows |
| 126 | // as waiting on them. Ordered most recently touched first. |
132 | // as waiting on them. Ordered most recently touched first. |
| |
133 | const reviewQueueQuery = ` |
| |
134 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
135 | x.number, x.title, au.username, x.state, x.updated_at |
| |
136 | FROM merge_requests x |
| |
137 | JOIN repos r ON r.id = x.repo_id |
| |
138 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
139 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
140 | JOIN users au ON au.id = x.author_id |
| |
141 | WHERE x.state IN ('open', 'source_gone') |
| |
142 | AND x.author_id <> ?1 |
| |
143 | AND NOT EXISTS (SELECT 1 FROM mr_reviews rv |
| |
144 | WHERE rv.mr_id = x.id AND rv.reviewer_id = ?1 |
| |
145 | AND rv.head_sha = x.head_sha) |
| |
146 | AND ` + involvedCond + ` |
| |
147 | ORDER BY x.updated_at DESC LIMIT 8` |
| |
148 | |
| 127 | func (s *Store) ReviewQueue(userID int64) ([]DashboardItem, error) { |
149 | func (s *Store) ReviewQueue(userID int64) ([]DashboardItem, error) { |
| 128 | return s.dashboardQuery(` |
150 | return s.dashboardQuery(reviewQueueQuery, userID) |
| 129 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
| 130 | x.number, x.title, au.username, x.state, x.updated_at |
| |
| 131 | FROM merge_requests x |
| |
| 132 | JOIN repos r ON r.id = x.repo_id |
| |
| 133 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
| 134 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
| 135 | JOIN users au ON au.id = x.author_id |
| |
| 136 | WHERE x.state IN ('open', 'source_gone') |
| |
| 137 | AND x.author_id <> ?1 |
| |
| 138 | AND NOT EXISTS (SELECT 1 FROM mr_reviews rv |
| |
| 139 | WHERE rv.mr_id = x.id AND rv.reviewer_id = ?1 |
| |
| 140 | AND rv.head_sha = x.head_sha) |
| |
| 141 | AND `+involvedCond+` |
| |
| 142 | ORDER BY x.updated_at DESC LIMIT 8`, userID) |
| |
| 143 | } |
151 | } |
| 144 | |
152 | |
| 145 | // OpenCounts returns the repo's open issue and open merge request counts, |
153 | // OpenCounts returns the repo's open issue and open merge request counts, |
| @@ -155,19 +163,24 @@ func (s *Store) OpenCounts(repoID int64) (issues, mrs int) { |
| 155 | // AssignedIssues returns open issues assigned to the user, wherever they |
163 | // AssignedIssues returns open issues assigned to the user, wherever they |
| 156 | // live. Assignment is a direct request for someone's attention, so it is |
164 | // live. Assignment is a direct request for someone's attention, so it is |
| 157 | // not narrowed by the involvement rule the other lists use. |
165 | // not narrowed by the involvement rule the other lists use. |
| |
166 | // |
| |
167 | // It drives from issue_assignees rather than testing EXISTS against every |
| |
168 | // issue: the assignee rows for one user are a handful, the issues table |
| |
169 | // is the whole instance. |
| |
170 | const assignedIssuesQuery = ` |
| |
171 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
172 | x.number, x.title, au.username, x.state, x.updated_at |
| |
173 | FROM issue_assignees ia |
| |
174 | JOIN issues x ON x.id = ia.issue_id |
| |
175 | JOIN repos r ON r.id = x.repo_id |
| |
176 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
177 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
178 | JOIN users au ON au.id = x.author_id |
| |
179 | WHERE ia.user_id = ?1 AND x.state = 'open' |
| |
180 | ORDER BY x.updated_at DESC LIMIT 20` |
| |
181 | |
| 158 | func (s *Store) AssignedIssues(userID int64) ([]DashboardItem, error) { |
182 | func (s *Store) AssignedIssues(userID int64) ([]DashboardItem, error) { |
| 159 | return s.dashboardQuery(` |
183 | return s.dashboardQuery(assignedIssuesQuery, userID) |
| 160 | SELECT COALESCE(u.username, o.name) || '/' || r.name, |
| |
| 161 | x.number, x.title, au.username, x.state, x.updated_at |
| |
| 162 | FROM issues x |
| |
| 163 | JOIN repos r ON r.id = x.repo_id |
| |
| 164 | LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id |
| |
| 165 | LEFT JOIN orgs o ON r.owner_kind = 'org' AND o.id = r.owner_id |
| |
| 166 | JOIN users au ON au.id = x.author_id |
| |
| 167 | WHERE x.state = 'open' |
| |
| 168 | AND EXISTS (SELECT 1 FROM issue_assignees ia |
| |
| 169 | WHERE ia.issue_id = x.id AND ia.user_id = ?1) |
| |
| 170 | ORDER BY x.updated_at DESC LIMIT 20`, userID) |
| |
| 171 | } |
184 | } |
| 172 | |
185 | |
| 173 | // DashboardBuild is one build row on the dashboard, with its repo resolved. |
186 | // DashboardBuild is one build row on the dashboard, with its repo resolved. |