From 87ab9ea91c2c61e6f9e6409fc80e35b1d0358291 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 18 Apr 2024 15:01:36 +0800 Subject: [PATCH 01/14] Fix issue comment number --- models/db/engine.go | 1 + models/issues/comment.go | 29 ++++++++++++++++++++++++----- models/repo.go | 4 ++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/models/db/engine.go b/models/db/engine.go index 26abf0b96c21e..97aa37ed6d1af 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -57,6 +57,7 @@ type Engine interface { SumInt(bean any, columnName string) (res int64, err error) Sync(...any) error Select(string) *xorm.Session + SetExpr(column string, expression any) *xorm.Session NotIn(string, ...any) *xorm.Session OrderBy(any, ...any) *xorm.Session Exist(...any) (bool, error) diff --git a/models/issues/comment.go b/models/issues/comment.go index 353163ebd6f99..980b1f374b721 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -868,7 +868,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment } fallthrough case CommentTypeComment: - if _, err = db.Exec(ctx, "UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil { + if err := UpdateIssueNumComments(ctx, opts.Issue.ID); err != nil { return err } fallthrough @@ -1148,8 +1148,8 @@ func DeleteComment(ctx context.Context, comment *Comment) error { return err } - if comment.Type == CommentTypeComment { - if _, err := e.ID(comment.IssueID).Decr("num_comments").Update(new(Issue)); err != nil { + if comment.Type == CommentTypeComment || comment.Type == CommentTypeReview { + if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil { return err } } @@ -1266,6 +1266,26 @@ func (c *Comment) HasOriginalAuthor() bool { return c.OriginalAuthor != "" && c.OriginalAuthorID != 0 } +func CountCommentsBuilder(issueID int64) *builder.Builder { + return builder.Select("count(*)").From("comment").Where(builder.Eq{ + "issue_id": issueID, + }.And(builder.Or( + builder.Eq{"type": CommentTypeComment}, + builder.Eq{"type": CommentTypeReview}, + builder.Eq{"type": CommentTypeCode}, + )).And(builder.Neq{ + "invalidated": true, + })) +} + +func UpdateIssueNumComments(ctx context.Context, issueID int64) error { + _, err := db.GetEngine(ctx). + SetExpr("num_comments", CountCommentsBuilder(issueID)). + ID(issueID). + Update(new(Issue)) + return err +} + // InsertIssueComments inserts many comments of issues. func InsertIssueComments(ctx context.Context, comments []*Comment) error { if len(comments) == 0 { @@ -1298,8 +1318,7 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error { } for _, issueID := range issueIDs { - if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?", - issueID, CommentTypeComment, issueID); err != nil { + if err := UpdateIssueNumComments(ctx, issueID); err != nil { return err } } diff --git a/models/repo.go b/models/repo.go index 0dc8ee5df33e7..020a4145277f0 100644 --- a/models/repo.go +++ b/models/repo.go @@ -109,7 +109,7 @@ func userStatsCorrectNumRepos(ctx context.Context, id int64) error { } func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, "UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND type=0) WHERE id=?", id) + return StatsCorrectSQL(ctx, "UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND (type=0 or type=22)) WHERE id=?", id) } func repoStatsCorrectNumIssues(ctx context.Context, id int64) error { @@ -201,7 +201,7 @@ func CheckRepoStats(ctx context.Context) error { }, // Issue.NumComments { - statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND type=0)"), + statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=0 OR type=22))"), repoStatsCorrectIssueNumComments, "issue count 'num_comments'", }, From c9c3e764467f6df7011b67afd633aae25123f185 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Dec 2024 21:35:58 -0800 Subject: [PATCH 02/14] Fix test --- models/issues/comment.go | 7 +++---- models/issues/comment_test.go | 9 +++++++++ models/repo.go | 7 +++++-- models/repo_test.go | 12 ++++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index 385e2ecddc9b6..8ee6486c0261f 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1303,10 +1303,9 @@ func (c *Comment) HasOriginalAuthor() bool { func CountCommentsBuilder(issueID int64) *builder.Builder { return builder.Select("count(*)").From("comment").Where(builder.Eq{ "issue_id": issueID, - }.And(builder.Or( - builder.Eq{"type": CommentTypeComment}, - builder.Eq{"type": CommentTypeReview}, - builder.Eq{"type": CommentTypeCode}, + }.And(builder.In("type", + CommentTypeComment, + CommentTypeReview, )).And(builder.Neq{ "invalidated": true, })) diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index d81f33f953d0e..cb31a21f92105 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -97,3 +97,12 @@ func TestMigrate_InsertIssueComments(t *testing.T) { unittest.CheckConsistencyFor(t, &issues_model.Issue{}) } + +func Test_UpdateIssueNumComments(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + + assert.NoError(t, issues_model.UpdateIssueNumComments(db.DefaultContext, issue2.ID)) + issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + assert.EqualValues(t, 1, issue2.NumComments) +} diff --git a/models/repo.go b/models/repo.go index bf87ef6b3231c..6b34dcad783d7 100644 --- a/models/repo.go +++ b/models/repo.go @@ -6,6 +6,7 @@ package models import ( "context" + "fmt" "strconv" _ "image/jpeg" // Needed for jpeg support @@ -106,7 +107,8 @@ func userStatsCorrectNumRepos(ctx context.Context, id int64) error { } func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, "UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND (type=0 or type=22)) WHERE id=?", id) + return StatsCorrectSQL(ctx, fmt.Sprintf("UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND (type=%d or type=%d)) WHERE id=?", + issues_model.CommentTypeComment, issues_model.CommentTypeReview), id) } func repoStatsCorrectNumIssues(ctx context.Context, id int64) error { @@ -198,7 +200,8 @@ func CheckRepoStats(ctx context.Context) error { }, // Issue.NumComments { - statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=0 OR type=22))"), + statsQuery(fmt.Sprintf("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=%d OR type=%d))", + issues_model.CommentTypeComment, issues_model.CommentTypeReview)), repoStatsCorrectIssueNumComments, "issue count 'num_comments'", }, diff --git a/models/repo_test.go b/models/repo_test.go index 2a8a4a743ed27..b924687a6d20f 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -7,6 +7,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -22,3 +23,14 @@ func TestDoctorUserStarNum(t *testing.T) { assert.NoError(t, DoctorUserStarNum(db.DefaultContext)) } + +func Test_repoStatsCorrectIssueNumComments(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + assert.NotNil(t, issue2) + assert.EqualValues(t, 0, issue2.NumComments) // the fixture data is wrong, but we don't fix it here + + assert.NoError(t, repoStatsCorrectIssueNumComments(db.DefaultContext, 2)) + assert.EqualValues(t, 1, issue2.NumComments) +} From 58a81cdab2592f082d0b42ec1d168e51dff70175 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Dec 2024 22:10:21 -0800 Subject: [PATCH 03/14] Fix bug --- models/issues/comment.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index 8ee6486c0261f..7599e926a051c 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1306,9 +1306,7 @@ func CountCommentsBuilder(issueID int64) *builder.Builder { }.And(builder.In("type", CommentTypeComment, CommentTypeReview, - )).And(builder.Neq{ - "invalidated": true, - })) + ))) } func UpdateIssueNumComments(ctx context.Context, issueID int64) error { From 9da2b3682261c07a1a090504771c8a5f6960a93d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 28 Dec 2024 16:17:01 -0800 Subject: [PATCH 04/14] Fix bug --- models/repo_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models/repo_test.go b/models/repo_test.go index b924687a6d20f..bcf62237f08d7 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -32,5 +32,7 @@ func Test_repoStatsCorrectIssueNumComments(t *testing.T) { assert.EqualValues(t, 0, issue2.NumComments) // the fixture data is wrong, but we don't fix it here assert.NoError(t, repoStatsCorrectIssueNumComments(db.DefaultContext, 2)) + // reload the issue + issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) assert.EqualValues(t, 1, issue2.NumComments) } From fcfb518a321bfd56f190cb001916a955603bec87 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 28 Dec 2024 16:34:48 -0800 Subject: [PATCH 05/14] Fix test and follow wxiaoguang's suggestion --- models/issues/comment.go | 20 +++++++++++++++----- models/repo.go | 4 ++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index 7599e926a051c..fbeceb95fd060 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -197,6 +197,19 @@ func (t CommentType) HasMailReplySupport() bool { return false } +func (t CommentType) CountedAsConversation() bool { + for _, ct := range ConversationCountedCommentType() { + if t == ct { + return true + } + } + return false +} + +func ConversationCountedCommentType() []any { + return []any{CommentTypeComment, CommentTypeReview} +} + // RoleInRepo presents the user's participation in the repo type RoleInRepo string @@ -1182,7 +1195,7 @@ func DeleteComment(ctx context.Context, comment *Comment) error { return err } - if comment.Type == CommentTypeComment || comment.Type == CommentTypeReview { + if comment.Type.CountedAsConversation() { if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil { return err } @@ -1303,10 +1316,7 @@ func (c *Comment) HasOriginalAuthor() bool { func CountCommentsBuilder(issueID int64) *builder.Builder { return builder.Select("count(*)").From("comment").Where(builder.Eq{ "issue_id": issueID, - }.And(builder.In("type", - CommentTypeComment, - CommentTypeReview, - ))) + }.And(builder.In("type", ConversationCountedCommentType()...))) } func UpdateIssueNumComments(ctx context.Context, issueID int64) error { diff --git a/models/repo.go b/models/repo.go index 6b34dcad783d7..93b3bd61b4723 100644 --- a/models/repo.go +++ b/models/repo.go @@ -108,7 +108,7 @@ func userStatsCorrectNumRepos(ctx context.Context, id int64) error { func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error { return StatsCorrectSQL(ctx, fmt.Sprintf("UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND (type=%d or type=%d)) WHERE id=?", - issues_model.CommentTypeComment, issues_model.CommentTypeReview), id) + issues_model.ConversationCountedCommentType()...), id) } func repoStatsCorrectNumIssues(ctx context.Context, id int64) error { @@ -201,7 +201,7 @@ func CheckRepoStats(ctx context.Context) error { // Issue.NumComments { statsQuery(fmt.Sprintf("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=%d OR type=%d))", - issues_model.CommentTypeComment, issues_model.CommentTypeReview)), + issues_model.ConversationCountedCommentType()...)), repoStatsCorrectIssueNumComments, "issue count 'num_comments'", }, From aca3361a5f4a33c696261c481dbd091257a636bb Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 28 Dec 2024 16:42:18 -0800 Subject: [PATCH 06/14] Fix test --- models/issues/comment.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index fbeceb95fd060..6001999bba7cd 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1313,15 +1313,13 @@ func (c *Comment) HasOriginalAuthor() bool { return c.OriginalAuthor != "" && c.OriginalAuthorID != 0 } -func CountCommentsBuilder(issueID int64) *builder.Builder { - return builder.Select("count(*)").From("comment").Where(builder.Eq{ +func UpdateIssueNumComments(ctx context.Context, issueID int64) error { + countCommentsBuilder := builder.Select("count(*)").From("comment").Where(builder.Eq{ "issue_id": issueID, }.And(builder.In("type", ConversationCountedCommentType()...))) -} -func UpdateIssueNumComments(ctx context.Context, issueID int64) error { _, err := db.GetEngine(ctx). - SetExpr("num_comments", CountCommentsBuilder(issueID)). + SetExpr("num_comments", countCommentsBuilder). ID(issueID). Update(new(Issue)) return err From 37ce8674430ac6716cb5a424d1504e0001d6610d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 28 Dec 2024 22:35:52 -0800 Subject: [PATCH 07/14] Fix bug --- models/issues/comment.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/issues/comment.go b/models/issues/comment.go index 6001999bba7cd..e7c014258416b 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1321,6 +1321,7 @@ func UpdateIssueNumComments(ctx context.Context, issueID int64) error { _, err := db.GetEngine(ctx). SetExpr("num_comments", countCommentsBuilder). ID(issueID). + NoAutoTime(). Update(new(Issue)) return err } From ee4bf009ebcd16d8c6b2f49d9a7a2f1cc7469f78 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 29 Dec 2024 17:03:57 -0800 Subject: [PATCH 08/14] Don't use format in SQL --- models/repo.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/repo.go b/models/repo.go index 93b3bd61b4723..7f19fcf4248a7 100644 --- a/models/repo.go +++ b/models/repo.go @@ -127,9 +127,9 @@ func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error { return repo_model.UpdateRepoIssueNumbers(ctx, id, true, true) } -func statsQuery(args ...any) func(context.Context) ([]map[string][]byte, error) { +func statsQuery(sql string, args ...any) func(context.Context) ([]map[string][]byte, error) { return func(ctx context.Context) ([]map[string][]byte, error) { - return db.GetEngine(ctx).Query(args...) + return db.GetEngine(ctx).Query(append([]any{sql}, args...)...) } } @@ -200,8 +200,8 @@ func CheckRepoStats(ctx context.Context) error { }, // Issue.NumComments { - statsQuery(fmt.Sprintf("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=%d OR type=%d))", - issues_model.ConversationCountedCommentType()...)), + statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=? OR type=?))", + issues_model.ConversationCountedCommentType()...), repoStatsCorrectIssueNumComments, "issue count 'num_comments'", }, From 17d8a24801dfd5af8cec6efcdb3c78050155203f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 29 Dec 2024 17:06:16 -0800 Subject: [PATCH 09/14] Add some comments --- models/issues/comment.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models/issues/comment.go b/models/issues/comment.go index e7c014258416b..9fcae3ce284a0 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -206,6 +206,8 @@ func (t CommentType) CountedAsConversation() bool { return false } +// ConversationCountedCommentType returns the comment types that are counted as a conversation +// The returned types are []any rather than []CommentType to allow for easy use as xorm args func ConversationCountedCommentType() []any { return []any{CommentTypeComment, CommentTypeReview} } From c3d5d26c495de84cd3bf5565eba93bc6ef7f14a0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 29 Dec 2024 23:50:04 -0800 Subject: [PATCH 10/14] Use builder --- models/issues/comment.go | 6 +++--- models/repo.go | 44 ++++++++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index 9fcae3ce284a0..c033f02036262 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -208,8 +208,8 @@ func (t CommentType) CountedAsConversation() bool { // ConversationCountedCommentType returns the comment types that are counted as a conversation // The returned types are []any rather than []CommentType to allow for easy use as xorm args -func ConversationCountedCommentType() []any { - return []any{CommentTypeComment, CommentTypeReview} +func ConversationCountedCommentType() []CommentType { + return []CommentType{CommentTypeComment, CommentTypeReview} } // RoleInRepo presents the user's participation in the repo @@ -1318,7 +1318,7 @@ func (c *Comment) HasOriginalAuthor() bool { func UpdateIssueNumComments(ctx context.Context, issueID int64) error { countCommentsBuilder := builder.Select("count(*)").From("comment").Where(builder.Eq{ "issue_id": issueID, - }.And(builder.In("type", ConversationCountedCommentType()...))) + }.And(builder.In("type", ConversationCountedCommentType()))) _, err := db.GetEngine(ctx). SetExpr("num_comments", countCommentsBuilder). diff --git a/models/repo.go b/models/repo.go index 7f19fcf4248a7..3b4e5dee400c6 100644 --- a/models/repo.go +++ b/models/repo.go @@ -6,7 +6,6 @@ package models import ( "context" - "fmt" "strconv" _ "image/jpeg" // Needed for jpeg support @@ -17,6 +16,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + "xorm.io/builder" ) // Init initialize model @@ -25,7 +25,7 @@ func Init(ctx context.Context) error { } type repoChecker struct { - querySQL func(ctx context.Context) ([]map[string][]byte, error) + querySQL func(ctx context.Context) ([]int64, error) correctSQL func(ctx context.Context, id int64) error desc string } @@ -36,8 +36,7 @@ func repoStatsCheck(ctx context.Context, checker *repoChecker) { log.Error("Select %s: %v", checker.desc, err) return } - for _, result := range results { - id, _ := strconv.ParseInt(string(result["id"]), 10, 64) + for _, id := range results { select { case <-ctx.Done(): log.Warn("CheckRepoStats: Cancelled before checking %s for with id=%d", checker.desc, id) @@ -52,8 +51,10 @@ func repoStatsCheck(ctx context.Context, checker *repoChecker) { } } -func StatsCorrectSQL(ctx context.Context, sql string, id int64) error { - _, err := db.GetEngine(ctx).Exec(sql, id, id) +func StatsCorrectSQL(ctx context.Context, sql any, ids ...any) error { + args := []any{sql} + args = append(args, ids...) + _, err := db.GetEngine(ctx).Exec(args...) return err } @@ -107,8 +108,14 @@ func userStatsCorrectNumRepos(ctx context.Context, id int64) error { } func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, fmt.Sprintf("UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND (type=%d or type=%d)) WHERE id=?", - issues_model.ConversationCountedCommentType()...), id) + return StatsCorrectSQL(ctx, + builder.Update(builder.Eq{ + "num_comments": builder.Select("COUNT(*)").From("`comment`").Where( + builder.Eq{"issue_id": id}.And( + builder.In("type", issues_model.ConversationCountedCommentType()), + )), + }).From("`issue`").Where(builder.Eq{"id": id}), + ) } func repoStatsCorrectNumIssues(ctx context.Context, id int64) error { @@ -127,9 +134,12 @@ func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error { return repo_model.UpdateRepoIssueNumbers(ctx, id, true, true) } -func statsQuery(sql string, args ...any) func(context.Context) ([]map[string][]byte, error) { - return func(ctx context.Context) ([]map[string][]byte, error) { - return db.GetEngine(ctx).Query(append([]any{sql}, args...)...) +// statsQuery returns a function that queries the database for a list of IDs +// sql could be a string or a *builder.Builder +func statsQuery(sql any, args ...any) func(context.Context) ([]int64, error) { + return func(ctx context.Context) ([]int64, error) { + var ids []int64 + return ids, db.GetEngine(ctx).SQL(sql, args...).Find(&ids) } } @@ -200,8 +210,16 @@ func CheckRepoStats(ctx context.Context) error { }, // Issue.NumComments { - statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND (type=? OR type=?))", - issues_model.ConversationCountedCommentType()...), + statsQuery(builder.Select("`issue`.id").From("`issue`").Where( + builder.Neq{ + "`issue`.num_comments": builder.Select("COUNT(*)").From("`comment`").Where( + builder.Expr("issue_id = `issue`.id").And( + builder.In("type", issues_model.ConversationCountedCommentType()), + ), + ), + }, + ), + ), repoStatsCorrectIssueNumComments, "issue count 'num_comments'", }, From 2ea18d67d069453551b45dbb930d7a7239608cfc Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 30 Dec 2024 00:05:24 -0800 Subject: [PATCH 11/14] Fix lint --- models/repo.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/repo.go b/models/repo.go index 3b4e5dee400c6..2c8be3082b4de 100644 --- a/models/repo.go +++ b/models/repo.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + "xorm.io/builder" ) From a04cca56cf78badb30a5e29eeb5b97550a14929b Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 30 Dec 2024 17:06:36 +0800 Subject: [PATCH 12/14] Update models/issues/comment.go --- models/issues/comment.go | 1 - 1 file changed, 1 deletion(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index c033f02036262..e4029565d64f5 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -207,7 +207,6 @@ func (t CommentType) CountedAsConversation() bool { } // ConversationCountedCommentType returns the comment types that are counted as a conversation -// The returned types are []any rather than []CommentType to allow for easy use as xorm args func ConversationCountedCommentType() []CommentType { return []CommentType{CommentTypeComment, CommentTypeReview} } From d86747534bef5cb68d09aca948787954da1bfdca Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 30 Dec 2024 11:17:55 -0800 Subject: [PATCH 13/14] Merge the update logic --- models/issues/comment.go | 20 +++++++++++--------- models/issues/review.go | 4 ++++ models/repo.go | 9 +-------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/models/issues/comment.go b/models/issues/comment.go index c033f02036262..bd06f9850ab50 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1315,16 +1315,18 @@ func (c *Comment) HasOriginalAuthor() bool { return c.OriginalAuthor != "" && c.OriginalAuthorID != 0 } +func UpdateIssueNumCommentsBuilder(issueID int64) *builder.Builder { + subQuery := builder.Select("COUNT(*)").From("`comment`").Where( + builder.Eq{"issue_id": issueID}.And( + builder.In("`type`", ConversationCountedCommentType()), + )) + + return builder.Update(builder.Eq{"num_comments": subQuery}). + From("`issue`").Where(builder.Eq{"id": issueID}) +} + func UpdateIssueNumComments(ctx context.Context, issueID int64) error { - countCommentsBuilder := builder.Select("count(*)").From("comment").Where(builder.Eq{ - "issue_id": issueID, - }.And(builder.In("type", ConversationCountedCommentType()))) - - _, err := db.GetEngine(ctx). - SetExpr("num_comments", countCommentsBuilder). - ID(issueID). - NoAutoTime(). - Update(new(Issue)) + _, err := db.GetEngine(ctx).Exec(UpdateIssueNumCommentsBuilder(issueID)) return err } diff --git a/models/issues/review.go b/models/issues/review.go index 8b345e5fd8002..3e787273be8e1 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -639,6 +639,10 @@ func InsertReviews(ctx context.Context, reviews []*Review) error { return err } } + + if err := UpdateIssueNumComments(ctx, review.IssueID); err != nil { + return err + } } return committer.Commit() diff --git a/models/repo.go b/models/repo.go index 2c8be3082b4de..d262d897b31e7 100644 --- a/models/repo.go +++ b/models/repo.go @@ -109,14 +109,7 @@ func userStatsCorrectNumRepos(ctx context.Context, id int64) error { } func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, - builder.Update(builder.Eq{ - "num_comments": builder.Select("COUNT(*)").From("`comment`").Where( - builder.Eq{"issue_id": id}.And( - builder.In("type", issues_model.ConversationCountedCommentType()), - )), - }).From("`issue`").Where(builder.Eq{"id": id}), - ) + return StatsCorrectSQL(ctx, issues_model.UpdateIssueNumCommentsBuilder(id)) } func repoStatsCorrectNumIssues(ctx context.Context, id int64) error { From 7301b6d3eb59884eb6d83aa41f5087a236497cbc Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 30 Dec 2024 12:04:01 -0800 Subject: [PATCH 14/14] Fix bug --- models/repo.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/repo.go b/models/repo.go index d262d897b31e7..9bc67079a947c 100644 --- a/models/repo.go +++ b/models/repo.go @@ -60,15 +60,15 @@ func StatsCorrectSQL(ctx context.Context, sql any, ids ...any) error { } func repoStatsCorrectNumWatches(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", id) + return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", id, id) } func repoStatsCorrectNumStars(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", id) + return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", id, id) } func labelStatsCorrectNumIssues(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, "UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", id) + return StatsCorrectSQL(ctx, "UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", id, id) } func labelStatsCorrectNumIssuesRepo(ctx context.Context, id int64) error { @@ -105,7 +105,7 @@ func milestoneStatsCorrectNumIssuesRepo(ctx context.Context, id int64) error { } func userStatsCorrectNumRepos(ctx context.Context, id int64) error { - return StatsCorrectSQL(ctx, "UPDATE `user` SET num_repos=(SELECT COUNT(*) FROM `repository` WHERE owner_id=?) WHERE id=?", id) + return StatsCorrectSQL(ctx, "UPDATE `user` SET num_repos=(SELECT COUNT(*) FROM `repository` WHERE owner_id=?) WHERE id=?", id, id) } func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error {