fix(issues): keep one row per issue when sorting by exclusive label order (#39364) (#39928)

Backport #39364 by @shoemoney

Sorting by an exclusive label scope joined `issue_label`, returning one
row per label. Issues with several labels were listed repeatedly and
pushed others off the page, and `IssueIDs` returned inflated totals.

The sort key now comes from a correlated subquery, so each issue yields
one row.

Fixes https://github.com/go-gitea/gitea/issues/35711

This base-branch update was prepared with AI assistance.

Co-authored-by: Jeremy Schoemaker <jeremy@shoemoney.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
authored and GitHub committed 2026-10-22 00:22:16 -07:00
1 parent 716295015b
commit 3996c2c520
2 files changed
+26 -5

No files matched your search

+5 -5
View File
@@ -75,11 +75,11 @@ func applySorts(sess db.Session, sortType string, priorityRepoID int64) {
// Since this sortType is dynamically created, it has to be treated specially.
if after, ok := strings.CutPrefix(sortType, ScopeSortPrefix); ok {
scope := after
sess.Join("LEFT", "issue_label", "issue.id = issue_label.issue_id")
// "exclusive_order=0" means "no order is set", so exclude it from the JOIN criteria and then "LEFT JOIN" result is also null
sess.Join("LEFT", "label", "label.id = issue_label.label_id AND label.exclusive_order <> 0 AND label.name LIKE ?", scope+"/%")
// Use COALESCE to make sure we sort NULL last regardless of backend DB (2147483647 == max int)
sess.OrderBy("COALESCE(label.exclusive_order, 2147483647) ASC").Desc("issue.id")
// a subquery instead of a JOIN keeps one row per issue, "exclusive_order=0" means unset and COALESCE sorts it last on every DB
sess.OrderBy("COALESCE((SELECT MIN(label.exclusive_order) FROM issue_label"+
" INNER JOIN label ON label.id = issue_label.label_id"+
" WHERE issue_label.issue_id = issue.id AND label.exclusive_order <> 0 AND label.name LIKE ?), 2147483647) ASC", scope+"/%").
Desc("issue.id")
return
}