diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2023-11-24 11:49:41 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-24 03:49:41 +0000 |
commit | df1e7d0067bb39913eb681ccc920649884fb1938 (patch) | |
tree | 2419feab5c28658adb7f71878df646bdc9bdc50e /models | |
parent | d24a8223ce1e47a0c9b103aae07f67c3112ca048 (diff) | |
download | gitea-df1e7d0067bb39913eb681ccc920649884fb1938.tar.gz gitea-df1e7d0067bb39913eb681ccc920649884fb1938.zip |
Use db.Find instead of writing methods for every object (#28084)
For those simple objects, it's unnecessary to write the find and count
methods again and again.
Diffstat (limited to 'models')
32 files changed, 369 insertions, 495 deletions
diff --git a/models/actions/artifact.go b/models/actions/artifact.go index 849a90fd10..42bd9c23cb 100644 --- a/models/actions/artifact.go +++ b/models/actions/artifact.go @@ -14,6 +14,8 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + + "xorm.io/builder" ) // ArtifactStatus is the status of an artifact, uploading, expired or need-delete @@ -108,29 +110,37 @@ func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) erro return err } -// ListArtifactsByRunID returns all artifacts of a run -func ListArtifactsByRunID(ctx context.Context, runID int64) ([]*ActionArtifact, error) { - arts := make([]*ActionArtifact, 0, 10) - return arts, db.GetEngine(ctx).Where("run_id=?", runID).Find(&arts) +type FindArtifactsOptions struct { + db.ListOptions + RepoID int64 + RunID int64 + ArtifactName string + Status int } -// ListArtifactsByRunIDAndArtifactName returns an artifacts of a run by artifact name -func ListArtifactsByRunIDAndArtifactName(ctx context.Context, runID int64, artifactName string) ([]*ActionArtifact, error) { - arts := make([]*ActionArtifact, 0, 10) - return arts, db.GetEngine(ctx).Where("run_id=? AND artifact_name=?", runID, artifactName).Find(&arts) -} +func (opts FindArtifactsOptions) ToConds() builder.Cond { + cond := builder.NewCond() + if opts.RepoID > 0 { + cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) + } + if opts.RunID > 0 { + cond = cond.And(builder.Eq{"run_id": opts.RunID}) + } + if opts.ArtifactName != "" { + cond = cond.And(builder.Eq{"artifact_name": opts.ArtifactName}) + } + if opts.Status > 0 { + cond = cond.And(builder.Eq{"status": opts.Status}) + } -// ListUploadedArtifactsByRunID returns all uploaded artifacts of a run -func ListUploadedArtifactsByRunID(ctx context.Context, runID int64) ([]*ActionArtifact, error) { - arts := make([]*ActionArtifact, 0, 10) - return arts, db.GetEngine(ctx).Where("run_id=? AND status=?", runID, ArtifactStatusUploadConfirmed).Find(&arts) + return cond } // ActionArtifactMeta is the meta data of an artifact type ActionArtifactMeta struct { ArtifactName string FileSize int64 - Status int64 + Status ArtifactStatus } // ListUploadedArtifactsMeta returns all uploaded artifacts meta of a run @@ -143,18 +153,6 @@ func ListUploadedArtifactsMeta(ctx context.Context, runID int64) ([]*ActionArtif Find(&arts) } -// ListArtifactsByRepoID returns all artifacts of a repo -func ListArtifactsByRepoID(ctx context.Context, repoID int64) ([]*ActionArtifact, error) { - arts := make([]*ActionArtifact, 0, 10) - return arts, db.GetEngine(ctx).Where("repo_id=?", repoID).Find(&arts) -} - -// ListArtifactsByRunIDAndName returns artifacts by name of a run -func ListArtifactsByRunIDAndName(ctx context.Context, runID int64, name string) ([]*ActionArtifact, error) { - arts := make([]*ActionArtifact, 0, 10) - return arts, db.GetEngine(ctx).Where("run_id=? AND artifact_name=?", runID, name).Find(&arts) -} - // ListNeedExpiredArtifacts returns all need expired artifacts but not deleted func ListNeedExpiredArtifacts(ctx context.Context) ([]*ActionArtifact, error) { arts := make([]*ActionArtifact, 0, 10) diff --git a/models/actions/run.go b/models/actions/run.go index 8078613fb8..4656aa22a2 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -170,7 +170,7 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err // CancelRunningJobs cancels all running and waiting jobs associated with a specific workflow. func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string) error { // Find all runs in the specified repository, reference, and workflow with statuses 'Running' or 'Waiting'. - runs, total, err := FindRuns(ctx, FindRunOptions{ + runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{ RepoID: repoID, Ref: ref, WorkflowID: workflowID, @@ -188,7 +188,7 @@ func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string // Iterate over each found run and cancel its associated jobs. for _, run := range runs { // Find all jobs associated with the current run. - jobs, _, err := FindRunJobs(ctx, FindRunJobOptions{ + jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{ RunID: run.ID, }) if err != nil { diff --git a/models/actions/run_job_list.go b/models/actions/run_job_list.go index a166396694..6ea6cb9d3b 100644 --- a/models/actions/run_job_list.go +++ b/models/actions/run_job_list.go @@ -61,7 +61,7 @@ type FindRunJobOptions struct { UpdatedBefore timeutil.TimeStamp } -func (opts FindRunJobOptions) toConds() builder.Cond { +func (opts FindRunJobOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RunID > 0 { cond = cond.And(builder.Eq{"run_id": opts.RunID}) @@ -83,17 +83,3 @@ func (opts FindRunJobOptions) toConds() builder.Cond { } return cond } - -func FindRunJobs(ctx context.Context, opts FindRunJobOptions) (ActionJobList, int64, error) { - e := db.GetEngine(ctx).Where(opts.toConds()) - if opts.PageSize > 0 && opts.Page >= 1 { - e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - var tasks ActionJobList - total, err := e.FindAndCount(&tasks) - return tasks, total, err -} - -func CountRunJobs(ctx context.Context, opts FindRunJobOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionRunJob)) -} diff --git a/models/actions/run_list.go b/models/actions/run_list.go index cd053ea7b5..375c46221b 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -75,7 +75,7 @@ type FindRunOptions struct { Status []Status } -func (opts FindRunOptions) toConds() builder.Cond { +func (opts FindRunOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) @@ -101,18 +101,8 @@ func (opts FindRunOptions) toConds() builder.Cond { return cond } -func FindRuns(ctx context.Context, opts FindRunOptions) (RunList, int64, error) { - e := db.GetEngine(ctx).Where(opts.toConds()) - if opts.PageSize > 0 && opts.Page >= 1 { - e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - var runs RunList - total, err := e.Desc("id").FindAndCount(&runs) - return runs, total, err -} - -func CountRuns(ctx context.Context, opts FindRunOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionRun)) +func (opts FindRunOptions) ToOrders() string { + return "`id` DESC" } type StatusInfo struct { diff --git a/models/actions/runner.go b/models/actions/runner.go index 2c092c2b4a..717b770800 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -156,7 +156,7 @@ type FindRunnerOptions struct { WithAvailable bool // not only runners belong to, but also runners can be used } -func (opts FindRunnerOptions) toCond() builder.Cond { +func (opts FindRunnerOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { @@ -181,7 +181,7 @@ func (opts FindRunnerOptions) toCond() builder.Cond { return cond } -func (opts FindRunnerOptions) toOrder() string { +func (opts FindRunnerOptions) ToOrders() string { switch opts.Sort { case "online": return "last_online DESC" @@ -199,22 +199,6 @@ func (opts FindRunnerOptions) toOrder() string { return "last_online DESC" } -func CountRunners(ctx context.Context, opts FindRunnerOptions) (int64, error) { - return db.GetEngine(ctx). - Where(opts.toCond()). - Count(ActionRunner{}) -} - -func FindRunners(ctx context.Context, opts FindRunnerOptions) (runners RunnerList, err error) { - sess := db.GetEngine(ctx). - Where(opts.toCond()). - OrderBy(opts.toOrder()) - if opts.Page > 0 { - sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - return runners, sess.Find(&runners) -} - // GetRunnerByUUID returns a runner via uuid func GetRunnerByUUID(ctx context.Context, uuid string) (*ActionRunner, error) { var runner ActionRunner @@ -263,8 +247,7 @@ func DeleteRunner(ctx context.Context, id int64) error { // CreateRunner creates new runner. func CreateRunner(ctx context.Context, t *ActionRunner) error { - _, err := db.GetEngine(ctx).Insert(t) - return err + return db.Insert(ctx, t) } func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) { diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go index ddd9a1321e..b806550b87 100644 --- a/models/actions/schedule_list.go +++ b/models/actions/schedule_list.go @@ -67,7 +67,7 @@ type FindScheduleOptions struct { OwnerID int64 } -func (opts FindScheduleOptions) toConds() builder.Cond { +func (opts FindScheduleOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) @@ -79,16 +79,6 @@ func (opts FindScheduleOptions) toConds() builder.Cond { return cond } -func FindSchedules(ctx context.Context, opts FindScheduleOptions) (ScheduleList, int64, error) { - e := db.GetEngine(ctx).Where(opts.toConds()) - if !opts.ListAll && opts.PageSize > 0 && opts.Page >= 1 { - e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - var schedules ScheduleList - total, err := e.Desc("id").FindAndCount(&schedules) - return schedules, total, err -} - -func CountSchedules(ctx context.Context, opts FindScheduleOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionSchedule)) +func (opts FindScheduleOptions) ToOrders() string { + return "`id` DESC" } diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go index 6bf91cf819..e9ae268a6e 100644 --- a/models/actions/schedule_spec_list.go +++ b/models/actions/schedule_spec_list.go @@ -71,7 +71,7 @@ type FindSpecOptions struct { Next int64 } -func (opts FindSpecOptions) toConds() builder.Cond { +func (opts FindSpecOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) @@ -84,23 +84,18 @@ func (opts FindSpecOptions) toConds() builder.Cond { return cond } +func (opts FindSpecOptions) ToOrders() string { + return "`id` DESC" +} + func FindSpecs(ctx context.Context, opts FindSpecOptions) (SpecList, int64, error) { - e := db.GetEngine(ctx).Where(opts.toConds()) - if opts.PageSize > 0 && opts.Page >= 1 { - e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - var specs SpecList - total, err := e.Desc("id").FindAndCount(&specs) + specs, total, err := db.FindAndCount[ActionScheduleSpec](ctx, opts) if err != nil { return nil, 0, err } - if err := specs.LoadSchedules(ctx); err != nil { + if err := SpecList(specs).LoadSchedules(ctx); err != nil { return nil, 0, err } return specs, total, nil } - -func CountSpecs(ctx context.Context, opts FindSpecOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionScheduleSpec)) -} diff --git a/models/actions/task_list.go b/models/actions/task_list.go index 1f6b16772b..b07d00b8db 100644 --- a/models/actions/task_list.go +++ b/models/actions/task_list.go @@ -62,7 +62,7 @@ type FindTaskOptions struct { IDOrderDesc bool } -func (opts FindTaskOptions) toConds() builder.Cond { +func (opts FindTaskOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) @@ -88,18 +88,9 @@ func (opts FindTaskOptions) toConds() builder.Cond { return cond } -func FindTasks(ctx context.Context, opts FindTaskOptions) (TaskList, error) { - e := db.GetEngine(ctx).Where(opts.toConds()) - if opts.PageSize > 0 && opts.Page >= 1 { - e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } +func (opts FindTaskOptions) ToOrders() string { if opts.IDOrderDesc { - e.OrderBy("id DESC") + return "`id` DESC" } - var tasks TaskList - return tasks, e.Find(&tasks) -} - -func CountTasks(ctx context.Context, opts FindTaskOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionTask)) + return "" } diff --git a/models/actions/variable.go b/models/actions/variable.go index e0bb59ccbe..030b7bae92 100644 --- a/models/actions/variable.go +++ b/models/actions/variable.go @@ -56,7 +56,7 @@ type FindVariablesOpts struct { RepoID int64 } -func (opts *FindVariablesOpts) toConds() builder.Cond { +func (opts FindVariablesOpts) ToConds() builder.Cond { cond := builder.NewCond() if opts.OwnerID > 0 { cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) @@ -67,15 +67,6 @@ func (opts *FindVariablesOpts) toConds() builder.Cond { return cond } -func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariable, error) { - var variables []*ActionVariable - sess := db.GetEngine(ctx) - if opts.PageSize != 0 { - sess = db.SetSessionPagination(sess, &opts.ListOptions) - } - return variables, sess.Where(opts.toConds()).Find(&variables) -} - func GetVariableByID(ctx context.Context, variableID int64) (*ActionVariable, error) { var variable ActionVariable has, err := db.GetEngine(ctx).Where("id=?", variableID).Get(&variable) diff --git a/models/activities/notification.go b/models/activities/notification.go index 7c794564b6..230bcdd6e8 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -22,7 +22,6 @@ import ( "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" - "xorm.io/xorm" ) type ( @@ -93,7 +92,7 @@ type FindNotificationOptions struct { } // ToCond will convert each condition into a xorm-Cond -func (opts *FindNotificationOptions) ToCond() builder.Cond { +func (opts FindNotificationOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.UserID != 0 { cond = cond.And(builder.Eq{"notification.user_id": opts.UserID}) @@ -105,7 +104,11 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond { cond = cond.And(builder.Eq{"notification.issue_id": opts.IssueID}) } if len(opts.Status) > 0 { - cond = cond.And(builder.In("notification.status", opts.Status)) + if len(opts.Status) == 1 { + cond = cond.And(builder.Eq{"notification.status": opts.Status[0]}) + } else { + cond = cond.And(builder.In("notification.status", opts.Status)) + } } if len(opts.Source) > 0 { cond = cond.And(builder.In("notification.source", opts.Source)) @@ -119,24 +122,8 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond { return cond } -// ToSession will convert the given options to a xorm Session by using the conditions from ToCond and joining with issue table if required -func (opts *FindNotificationOptions) ToSession(ctx context.Context) *xorm.Session { - sess := db.GetEngine(ctx).Where(opts.ToCond()) - if opts.Page != 0 { - sess = db.SetSessionPagination(sess, opts) - } - return sess -} - -// GetNotifications returns all notifications that fit to the given options. -func GetNotifications(ctx context.Context, options *FindNotificationOptions) (nl NotificationList, err error) { - err = options.ToSession(ctx).OrderBy("notification.updated_unix DESC").Find(&nl) - return nl, err -} - -// CountNotifications count all notifications that fit to the given options and ignore pagination. -func CountNotifications(ctx context.Context, opts *FindNotificationOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.ToCond()).Count(&Notification{}) +func (opts FindNotificationOptions) ToOrders() string { + return "notification.updated_unix DESC" } // CreateRepoTransferNotification creates notification for the user a repository was transferred to @@ -192,7 +179,9 @@ func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error { // init var toNotify container.Set[int64] - notifications, err := getNotificationsByIssueID(ctx, issueID) + notifications, err := db.Find[Notification](ctx, FindNotificationOptions{ + IssueID: issueID, + }) if err != nil { return err } @@ -273,23 +262,6 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n return nil } -func getNotificationsByIssueID(ctx context.Context, issueID int64) (notifications []*Notification, err error) { - err = db.GetEngine(ctx). - Where("issue_id = ?", issueID). - Find(¬ifications) - return notifications, err -} - -func notificationExists(notifications []*Notification, issueID, userID int64) bool { - for _, notification := range notifications { - if notification.IssueID == issueID && notification.UserID == userID { - return true - } - } - - return false -} - func createIssueNotification(ctx context.Context, userID int64, issue *issues_model.Issue, commentID, updatedByID int64) error { notification := &Notification{ UserID: userID, @@ -341,35 +313,6 @@ func GetIssueNotification(ctx context.Context, userID, issueID int64) (*Notifica return notification, err } -// NotificationsForUser returns notifications for a given user and status -func NotificationsForUser(ctx context.Context, user *user_model.User, statuses []NotificationStatus, page, perPage int) (notifications NotificationList, err error) { - if len(statuses) == 0 { - return nil, nil - } - - sess := db.GetEngine(ctx). - Where("user_id = ?", user.ID). - In("status", statuses). - OrderBy("updated_unix DESC") - - if page > 0 && perPage > 0 { - sess.Limit(perPage, (page-1)*perPage) - } - - err = sess.Find(¬ifications) - return notifications, err -} - -// CountUnread count unread notifications for a user -func CountUnread(ctx context.Context, userID int64) int64 { - exist, err := db.GetEngine(ctx).Where("user_id = ?", userID).And("status = ?", NotificationStatusUnread).Count(new(Notification)) - if err != nil { - log.Error("countUnread", err) - return 0 - } - return exist -} - // LoadAttributes load Repo Issue User and Comment if not loaded func (n *Notification) LoadAttributes(ctx context.Context) (err error) { if err = n.loadRepo(ctx); err != nil { @@ -481,17 +424,47 @@ func (n *Notification) APIURL() string { return setting.AppURL + "api/v1/notifications/threads/" + strconv.FormatInt(n.ID, 10) } +func notificationExists(notifications []*Notification, issueID, userID int64) bool { + for _, notification := range notifications { + if notification.IssueID == issueID && notification.UserID == userID { + return true + } + } + + return false +} + +// UserIDCount is a simple coalition of UserID and Count +type UserIDCount struct { + UserID int64 + Count int64 +} + +// GetUIDsAndNotificationCounts between the two provided times +func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) { + sql := `SELECT user_id, count(*) AS count FROM notification ` + + `WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` + + `updated_unix < ?) AND status = ? GROUP BY user_id` + var res []UserIDCount + return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res) +} + // NotificationList contains a list of notifications type NotificationList []*Notification // LoadAttributes load Repo Issue User and Comment if not loaded func (nl NotificationList) LoadAttributes(ctx context.Context) error { - var err error - for i := 0; i < len(nl); i++ { - err = nl[i].LoadAttributes(ctx) - if err != nil && !issues_model.IsErrCommentNotExist(err) { - return err - } + if _, _, err := nl.LoadRepos(ctx); err != nil { + return err + } + if _, err := nl.LoadIssues(ctx); err != nil { + return err + } + if _, err := nl.LoadUsers(ctx); err != nil { + return err + } + if _, err := nl.LoadComments(ctx); err != nil { + return err } return nil } @@ -665,6 +638,68 @@ func (nl NotificationList) getPendingCommentIDs() []int64 { return ids.Values() } +func (nl NotificationList) getUserIDs() []int64 { + ids := make(container.Set[int64], len(nl)) + for _, notification := range nl { + if notification.UserID == 0 || notification.User != nil { + continue + } + ids.Add(notification.UserID) + } + return ids.Values() +} + +// LoadUsers loads users from database +func (nl NotificationList) LoadUsers(ctx context.Context) ([]int, error) { + if len(nl) == 0 { + return []int{}, nil + } + + userIDs := nl.getUserIDs() + users := make(map[int64]*user_model.User, len(userIDs)) + left := len(userIDs) + for left > 0 { + limit := db.DefaultMaxInSize + if left < limit { + limit = left + } + rows, err := db.GetEngine(ctx). + In("id", userIDs[:limit]). + Rows(new(user_model.User)) + if err != nil { + return nil, err + } + + for rows.Next() { + var user user_model.User + err = rows.Scan(&user) + if err != nil { + rows.Close() + return nil, err + } + + users[user.ID] = &user + } + _ = rows.Close() + + left -= limit + userIDs = userIDs[limit:] + } + + failures := []int{} + for i, notification := range nl { + if notification.UserID > 0 && notification.User == nil && users[notification.UserID] != nil { + notification.User = users[notification.UserID] + if notification.User == nil { + log.Error("Notification[%d]: UserID[%d] failed to load", notification.ID, notification.UserID) + failures = append(failures, i) + continue + } + } + } + return failures, nil +} + // LoadComments loads comments from database func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) { if len(nl) == 0 { @@ -717,30 +752,6 @@ func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) { return failures, nil } -// GetNotificationCount returns the notification count for user -func GetNotificationCount(ctx context.Context, user *user_model.User, status NotificationStatus) (count int64, err error) { - count, err = db.GetEngine(ctx). - Where("user_id = ?", user.ID). - And("status = ?", status). - Count(&Notification{}) - return count, err -} - -// UserIDCount is a simple coalition of UserID and Count -type UserIDCount struct { - UserID int64 - Count int64 -} - -// GetUIDsAndNotificationCounts between the two provided times -func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) { - sql := `SELECT user_id, count(*) AS count FROM notification ` + - `WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` + - `updated_unix < ?) AND status = ? GROUP BY user_id` - var res []UserIDCount - return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res) -} - // SetIssueReadBy sets issue to be read by given user. func SetIssueReadBy(ctx context.Context, issueID, userID int64) error { if err := issues_model.UpdateIssueUserByRead(ctx, userID, issueID); err != nil { diff --git a/models/activities/notification_test.go b/models/activities/notification_test.go index b90ce70536..52f0eacba1 100644 --- a/models/activities/notification_test.go +++ b/models/activities/notification_test.go @@ -34,8 +34,13 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) { func TestNotificationsForUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - statuses := []activities_model.NotificationStatus{activities_model.NotificationStatusRead, activities_model.NotificationStatusUnread} - notfs, err := activities_model.NotificationsForUser(db.DefaultContext, user, statuses, 1, 10) + notfs, err := db.Find[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{ + UserID: user.ID, + Status: []activities_model.NotificationStatus{ + activities_model.NotificationStatusRead, + activities_model.NotificationStatusUnread, + }, + }) assert.NoError(t, err) if assert.Len(t, notfs, 3) { assert.EqualValues(t, 5, notfs[0].ID) @@ -68,11 +73,21 @@ func TestNotification_GetIssue(t *testing.T) { func TestGetNotificationCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - cnt, err := activities_model.GetNotificationCount(db.DefaultContext, user, activities_model.NotificationStatusRead) + cnt, err := db.Count[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{ + UserID: user.ID, + Status: []activities_model.NotificationStatus{ + activities_model.NotificationStatusRead, + }, + }) assert.NoError(t, err) assert.EqualValues(t, 0, cnt) - cnt, err = activities_model.GetNotificationCount(db.DefaultContext, user, activities_model.NotificationStatusUnread) + cnt, err = db.Count[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{ + UserID: user.ID, + Status: []activities_model.NotificationStatus{ + activities_model.NotificationStatusUnread, + }, + }) assert.NoError(t, err) assert.EqualValues(t, 1, cnt) } diff --git a/models/activities/statistic.go b/models/activities/statistic.go index e9dab6fc10..fe5f7d0872 100644 --- a/models/activities/statistic.go +++ b/models/activities/statistic.go @@ -52,7 +52,7 @@ type IssueByRepositoryCount struct { func GetStatistic(ctx context.Context) (stats Statistic) { e := db.GetEngine(ctx) stats.Counter.User = user_model.CountUsers(ctx, nil) - stats.Counter.Org, _ = organization.CountOrgs(ctx, organization.FindOrgOptions{IncludePrivate: true}) + stats.Counter.Org, _ = db.Count[organization.Organization](ctx, organization.FindOrgOptions{IncludePrivate: true}) stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey)) stats.Counter.Repo, _ = repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{}) stats.Counter.Watch, _ = e.Count(new(repo_model.Watch)) @@ -102,7 +102,7 @@ func GetStatistic(ctx context.Context) (stats Statistic) { stats.Counter.Follow, _ = e.Count(new(user_model.Follow)) stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror)) stats.Counter.Release, _ = e.Count(new(repo_model.Release)) - stats.Counter.AuthSource = auth.CountSources(ctx, auth.FindSourcesOptions{}) + stats.Counter.AuthSource, _ = db.Count[auth.Source](ctx, auth.FindSourcesOptions{}) stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook)) stats.Counter.Milestone, _ = e.Count(new(issues_model.Milestone)) stats.Counter.Label, _ = e.Count(new(issues_model.Label)) diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go index f36738fb3d..552f2ffd69 100644 --- a/models/asymkey/ssh_key.go +++ b/models/asymkey/ssh_key.go @@ -179,45 +179,33 @@ func SearchPublicKeyByContentExact(ctx context.Context, content string) (*Public return key, nil } -// SearchPublicKey returns a list of public keys matching the provided arguments. -func SearchPublicKey(ctx context.Context, uid int64, fingerprint string) ([]*PublicKey, error) { - keys := make([]*PublicKey, 0, 5) +type FindPublicKeyOptions struct { + db.ListOptions + OwnerID int64 + Fingerprint string + KeyTypes []KeyType + NotKeytype KeyType + LoginSourceID int64 +} + +func (opts FindPublicKeyOptions) ToConds() builder.Cond { cond := builder.NewCond() - if uid != 0 { - cond = cond.And(builder.Eq{"owner_id": uid}) + if opts.OwnerID > 0 { + cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) } - if fingerprint != "" { - cond = cond.And(builder.Eq{"fingerprint": fingerprint}) + if opts.Fingerprint != "" { + cond = cond.And(builder.Eq{"fingerprint": opts.Fingerprint}) } - return keys, db.GetEngine(ctx).Where(cond).Find(&keys) -} - -// ListPublicKeys returns a list of public keys belongs to given user. -func ListPublicKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*PublicKey, error) { - sess := db.GetEngine(ctx).Where("owner_id = ? AND type != ?", uid, KeyTypePrincipal) - if listOptions.Page != 0 { - sess = db.SetSessionPagination(sess, &listOptions) - - keys := make([]*PublicKey, 0, listOptions.PageSize) - return keys, sess.Find(&keys) + if len(opts.KeyTypes) > 0 { + cond = cond.And(builder.In("type", opts.KeyTypes)) } - - keys := make([]*PublicKey, 0, 5) - return keys, sess.Find(&keys) -} - -// CountPublicKeys count public keys a user has -func CountPublicKeys(ctx context.Context, userID int64) (int64, error) { - sess := db.GetEngine(ctx).Where("owner_id = ? AND type != ?", userID, KeyTypePrincipal) - return sess.Count(&PublicKey{}) -} - -// ListPublicKeysBySource returns a list of synchronized public keys for a given user and login source. -func ListPublicKeysBySource(ctx context.Context, uid, authSourceID int64) ([]*PublicKey, error) { - keys := make([]*PublicKey, 0, 5) - return keys, db.GetEngine(ctx). - Where("owner_id = ? AND login_source_id = ?", uid, authSourceID). - Find(&keys) + if opts.NotKeytype > 0 { + cond = cond.And(builder.Neq{"type": opts.NotKeytype}) + } + if opts.LoginSourceID > 0 { + cond = cond.And(builder.Eq{"login_source_id": opts.LoginSourceID}) + } + return cond } // UpdatePublicKeyUpdated updates public key use time. @@ -394,7 +382,10 @@ func SynchronizePublicKeys(ctx context.Context, usr *user_model.User, s *auth.So // Get Public Keys from DB with current LDAP source var giteaKeys []string - keys, err := ListPublicKeysBySource(ctx, usr.ID, s.ID) + keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{ + OwnerID: usr.ID, + LoginSourceID: s.ID, + }) if err != nil { log.Error("synchronizePublicKeys[%s]: Error listing Public SSH Keys for user %s: %v", s.Name, usr.Name, err) } diff --git a/models/asymkey/ssh_key_commit_verification.go b/models/asymkey/ssh_key_commit_verification.go index a61f0663b1..27c6df3578 100644 --- a/models/asymkey/ssh_key_commit_verification.go +++ b/models/asymkey/ssh_key_commit_verification.go @@ -21,7 +21,10 @@ import ( func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *CommitVerification { // Now try to associate the signature with the committer, if present if committer.ID != 0 { - keys, err := ListPublicKeys(ctx, committer.ID, db.ListOptions{}) + keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{ + OwnerID: committer.ID, + NotKeytype: KeyTypePrincipal, + }) if err != nil { // Skipping failed to get ssh keys of user log.Error("ListPublicKeys: %v", err) return &CommitVerification{ diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index e347604bcd..8f9f454051 100644 --- a/models/asymkey/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -210,7 +210,7 @@ type ListDeployKeysOptions struct { Fingerprint string } -func (opt ListDeployKeysOptions) toCond() builder.Cond { +func (opt ListDeployKeysOptions) ToConds() builder.Cond { cond := builder.NewCond() if opt.RepoID != 0 { cond = cond.And(builder.Eq{"repo_id": opt.RepoID}) @@ -223,23 +223,3 @@ func (opt ListDeployKeysOptions) toCond() builder.Cond { } return cond } - -// ListDeployKeys returns a list of deploy keys matching the provided arguments. -func ListDeployKeys(ctx context.Context, opts *ListDeployKeysOptions) ([]*DeployKey, error) { - sess := db.GetEngine(ctx).Where(opts.toCond()) - - if opts.Page != 0 { - sess = db.SetSessionPagination(sess, opts) - - keys := make([]*DeployKey, 0, opts.PageSize) - return keys, sess.Find(&keys) - } - - keys := make([]*DeployKey, 0, 5) - return keys, sess.Find(&keys) -} - -// CountDeployKeys returns count deploy keys matching the provided arguments. -func CountDeployKeys(ctx context.Context, opts *ListDeployKeysOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toCond()).Count(&DeployKey{}) -} diff --git a/models/auth/access_token.go b/models/auth/access_token.go index 8abcc622bc..63331b4841 100644 --- a/models/auth/access_token.go +++ b/models/auth/access_token.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/util" lru "github.com/hashicorp/golang-lru/v2" + "xorm.io/builder" ) // ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error. @@ -201,25 +202,18 @@ type ListAccessTokensOptions struct { UserID int64 } -// ListAccessTokens returns a list of access tokens belongs to given user. -func ListAccessTokens(ctx context.Context, opts ListAccessTokensOptions) ([]*AccessToken, error) { - sess := db.GetEngine(ctx).Where("uid=?", opts.UserID) - - if len(opts.Name) != 0 { - sess = sess.Where("name=?", opts.Name) - } - - sess = sess.Desc("created_unix") - - if opts.Page != 0 { - sess = db.SetSessionPagination(sess, &opts) - - tokens := make([]*AccessToken, 0, opts.PageSize) - return tokens, sess.Find(&tokens) +func (opts ListAccessTokensOptions) ToConds() builder.Cond { + cond := builder.NewCond() + // user id is required, otherwise it will return all result which maybe a possible bug + cond = cond.And(builder.Eq{"uid": opts.UserID}) + if len(opts.Name) > 0 { + cond = cond.And(builder.Eq{"name": opts.Name}) } + return cond +} - tokens := make([]*AccessToken, 0, 5) - return tokens, sess.Find(&tokens) +func (opts ListAccessTokensOptions) ToOrders() string { + return "created_unix DESC" } // UpdateAccessToken updates information of access token. @@ -228,15 +222,6 @@ func UpdateAccessToken(ctx context.Context, t *AccessToken) error { return err } -// CountAccessTokens count access tokens belongs to given user by options -func CountAccessTokens(ctx context.Context, opts ListAccessTokensOptions) (int64, error) { - sess := db.GetEngine(ctx).Where("uid=?", opts.UserID) - if len(opts.Name) != 0 { - sess = sess.Where("name=?", opts.Name) - } - return sess.Count(&AccessToken{}) -} - // DeleteAccessTokenByID deletes access token by given ID. func DeleteAccessTokenByID(ctx context.Context, id, userID int64) error { cnt, err := db.GetEngine(ctx).ID(id).Delete(&AccessToken{ diff --git a/models/auth/access_token_test.go b/models/auth/access_token_test.go index 72c937ffd6..4360f1a214 100644 --- a/models/auth/access_token_test.go +++ b/models/auth/access_token_test.go @@ -85,7 +85,7 @@ func TestGetAccessTokenBySHA(t *testing.T) { func TestListAccessTokens(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - tokens, err := auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1}) + tokens, err := db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1}) assert.NoError(t, err) if assert.Len(t, tokens, 2) { assert.Equal(t, int64(1), tokens[0].UID) @@ -94,14 +94,14 @@ func TestListAccessTokens(t *testing.T) { assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B") } - tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 2}) + tokens, err = db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 2}) assert.NoError(t, err) if assert.Len(t, tokens, 1) { assert.Equal(t, int64(2), tokens[0].UID) assert.Equal(t, "Token A", tokens[0].Name) } - tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100}) + tokens, err = db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100}) assert.NoError(t, err) assert.Empty(t, tokens) } diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index 76a4e9d835..9d53fffc78 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -5,6 +5,7 @@ package auth import ( "context" + "crypto/sha256" "encoding/base32" "encoding/base64" "fmt" @@ -19,7 +20,6 @@ import ( "code.gitea.io/gitea/modules/util" uuid "github.com/google/uuid" - "github.com/minio/sha256-simd" "golang.org/x/crypto/bcrypt" "xorm.io/builder" "xorm.io/xorm" @@ -243,13 +243,6 @@ func GetOAuth2ApplicationByID(ctx context.Context, id int64) (app *OAuth2Applica return app, nil } -// GetOAuth2ApplicationsByUserID returns all oauth2 applications owned by the user -func GetOAuth2ApplicationsByUserID(ctx context.Context, userID int64) (apps []*OAuth2Application, err error) { - apps = make([]*OAuth2Application, 0) - err = db.GetEngine(ctx).Where("uid = ?", userID).Find(&apps) - return apps, err -} - // CreateOAuth2ApplicationOptions holds options to create an oauth2 application type CreateOAuth2ApplicationOptions struct { Name string @@ -372,25 +365,6 @@ func DeleteOAuth2Application(ctx context.Context, id, userid int64) error { return committer.Commit() } -// ListOAuth2Applications returns a list of oauth2 applications belongs to given user. -func ListOAuth2Applications(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*OAuth2Application, int64, error) { - sess := db.GetEngine(ctx). - Where("uid=?", uid). - Desc("id") - - if listOptions.Page != 0 { - sess = db.SetSessionPagination(sess, &listOptions) - - apps := make([]*OAuth2Application, 0, listOptions.PageSize) - total, err := sess.FindAndCount(&apps) - return apps, total, err - } - - apps := make([]*OAuth2Application, 0, 5) - total, err := sess.FindAndCount(&apps) - return apps, total, err -} - ////////////////////////////////////////////////////// // OAuth2AuthorizationCode is a code to obtain an access token in combination with the client secret once. It has a limited lifetime. diff --git a/models/auth/oauth2_list.go b/models/auth/oauth2_list.go new file mode 100644 index 0000000000..c55f10b3c8 --- /dev/null +++ b/models/auth/oauth2_list.go @@ -0,0 +1,32 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package auth + +import ( + "code.gitea.io/gitea/models/db" + + "xorm.io/builder" +) + +type FindOAuth2ApplicationsOptions struct { + db.ListOptions + // OwnerID is the user id or org id of the owner of the application + OwnerID int64 + // find global applications, if true, then OwnerID will be igonred + IsGlobal bool +} + +func (opts FindOAuth2ApplicationsOptions) ToConds() builder.Cond { + conds := builder.NewCond() + if opts.IsGlobal { + conds = conds.And(builder.Eq{"uid": 0}) + } else if opts.OwnerID != 0 { + conds = conds.And(builder.Eq{"uid": opts.OwnerID}) + } + return conds +} + +func (opts FindOAuth2ApplicationsOptions) ToOrders() string { + return "id DESC" +} diff --git a/models/auth/source.go b/models/auth/source.go index 5f2781c808..5e77afddc3 100644 --- a/models/auth/source.go +++ b/models/auth/source.go @@ -242,6 +242,7 @@ func CreateSource(ctx context.Context, source *Source) error { } type FindSourcesOptions struct { + db.ListOptions IsActive util.OptionalBool LoginType Type } @@ -257,27 +258,22 @@ func (opts FindSourcesOptions) ToConds() builder.Cond { return conds } -// FindSources returns a slice of login sources found in DB according to given conditions. -func FindSources(ctx context.Context, opts FindSourcesOptions) ([]*Source, error) { - auths := make([]*Source, 0, 6) - return auths, db.GetEngine(ctx).Where(opts.ToConds()).Find(&auths) -} - // IsSSPIEnabled returns true if there is at least one activated login // source of type LoginSSPI func IsSSPIEnabled(ctx context.Context) bool { if !db.HasEngine { return false } - sources, err := FindSources(ctx, FindSourcesOptions{ + + exist, err := db.Exists[Source](ctx, FindSourcesOptions{ IsActive: util.OptionalBoolTrue, LoginType: SSPI, }) if err != nil { - log.Error("ActiveSources: %v", err) + log.Error("Active SSPI Sources: %v", err) return false } - return len(sources) > 0 + return exist } // GetSourceByID returns login source by given ID. @@ -346,12 +342,6 @@ func UpdateSource(ctx context.Context, source *Source) error { return err } -// CountSources returns number of login sources. -func CountSources(ctx context.Context, opts FindSourcesOptions) int64 { - count, _ := db.GetEngine(ctx).Where(opts.ToConds()).Count(new(Source)) - return count -} - // ErrSourceNotExist represents a "SourceNotExist" kind of error. type ErrSourceNotExist struct { ID int64 diff --git a/models/db/context.go b/models/db/context.go index 521857fae8..45765ef7d3 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -264,3 +264,8 @@ func inTransaction(ctx context.Context) (*xorm.Session, bool) { return nil, false } } + +func Exists[T any](ctx context.Context, opts FindOptions) (bool, error) { + var bean T + return GetEngine(ctx).Where(opts.ToConds()).Exist(&bean) +} diff --git a/models/db/list.go b/models/db/list.go index 9fb4d0741f..b2f932e89b 100644 --- a/models/db/list.go +++ b/models/db/list.go @@ -14,7 +14,8 @@ import ( const ( // DefaultMaxInSize represents default variables number on IN () in SQL - DefaultMaxInSize = 50 + DefaultMaxInSize = 50 + defaultFindSliceSize = 10 ) // Paginator is the base for different ListOptions types @@ -52,7 +53,12 @@ type ListOptions struct { ListAll bool // if true, then PageSize and Page will not be taken } -var _ Paginator = &ListOptions{} +var ListOptionsAll = ListOptions{ListAll: true} + +var ( + _ Paginator = &ListOptions{} + _ FindOptions = ListOptions{} +) // GetSkipTake returns the skip and take values func (opts *ListOptions) GetSkipTake() (skip, take int) { @@ -67,8 +73,16 @@ func (opts *ListOptions) GetStartEnd() (start, end int) { return start, end } +func (opts ListOptions) GetPage() int { + return opts.Page +} + +func (opts ListOptions) GetPageSize() int { + return opts.PageSize +} + // IsListAll indicates PageSize and Page will be ignored -func (opts *ListOptions) IsListAll() bool { +func (opts ListOptions) IsListAll() bool { return opts.ListAll } @@ -85,6 +99,10 @@ func (opts *ListOptions) SetDefaultValues() { } } +func (opts ListOptions) ToConds() builder.Cond { + return builder.NewCond() +} + // AbsoluteListOptions absolute options to paginate results type AbsoluteListOptions struct { skip int @@ -124,29 +142,63 @@ func (opts *AbsoluteListOptions) GetStartEnd() (start, end int) { // FindOptions represents a find options type FindOptions interface { - Paginator + GetPage() int + GetPageSize() int + IsListAll() bool ToConds() builder.Cond } +type FindOptionsOrder interface { + ToOrders() string +} + // Find represents a common find function which accept an options interface -func Find[T any](ctx context.Context, opts FindOptions, objects *[]T) error { +func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) { sess := GetEngine(ctx).Where(opts.ToConds()) - if !opts.IsListAll() { - sess.Limit(opts.GetSkipTake()) + page, pageSize := opts.GetPage(), opts.GetPageSize() + if !opts.IsListAll() && pageSize > 0 && page >= 1 { + sess.Limit(pageSize, (page-1)*pageSize) + } + if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" { + sess.OrderBy(newOpt.ToOrders()) + } + + findPageSize := defaultFindSliceSize + if pageSize > 0 { + findPageSize = pageSize + } + objects := make([]*T, 0, findPageSize) + if err := sess.Find(&objects); err != nil { + return nil, err } - return sess.Find(objects) + return objects, nil } // Count represents a common count function which accept an options interface -func Count[T any](ctx context.Context, opts FindOptions, object T) (int64, error) { - return GetEngine(ctx).Where(opts.ToConds()).Count(object) +func Count[T any](ctx context.Context, opts FindOptions) (int64, error) { + var object T + return GetEngine(ctx).Where(opts.ToConds()).Count(&object) } // FindAndCount represents a common findandcount function which accept an options interface -func FindAndCount[T any](ctx context.Context, opts FindOptions, objects *[]T) (int64, error) { +func FindAndCount[T any](ctx context.Context, opts FindOptions) ([]*T, int64, error) { sess := GetEngine(ctx).Where(opts.ToConds()) - if !opts.IsListAll() { - sess.Limit(opts.GetSkipTake()) + page, pageSize := opts.GetPage(), opts.GetPageSize() + if !opts.IsListAll() && pageSize > 0 && page >= 1 { + sess.Limit(pageSize, (page-1)*pageSize) + } + if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" { + sess.OrderBy(newOpt.ToOrders()) + } + + findPageSize := defaultFindSliceSize + if pageSize > 0 { + findPageSize = pageSize + } + objects := make([]*T, 0, findPageSize) + cnt, err := sess.FindAndCount(&objects) + if err != nil { + return nil, 0, err } - return sess.FindAndCount(objects) + return objects, cnt, nil } diff --git a/models/db/list_test.go b/models/db/list_test.go index b923dc9c22..45194611f8 100644 --- a/models/db/list_test.go +++ b/models/db/list_test.go @@ -18,11 +18,11 @@ type mockListOptions struct { db.ListOptions } -func (opts *mockListOptions) IsListAll() bool { +func (opts mockListOptions) IsListAll() bool { return true } -func (opts *mockListOptions) ToConds() builder.Cond { +func (opts mockListOptions) ToConds() builder.Cond { return builder.NewCond() } @@ -37,17 +37,16 @@ func TestFind(t *testing.T) { assert.NotEmpty(t, repoUnitCount) opts := mockListOptions{} - var repoUnits []repo_model.RepoUnit - err = db.Find(db.DefaultContext, &opts, &repoUnits) + repoUnits, err := db.Find[repo_model.RepoUnit](db.DefaultContext, opts) assert.NoError(t, err) assert.Len(t, repoUnits, repoUnitCount) - cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit)) + cnt, err := db.Count[repo_model.RepoUnit](db.DefaultContext, opts) assert.NoError(t, err) assert.EqualValues(t, repoUnitCount, cnt) - repoUnits = make([]repo_model.RepoUnit, 0, 10) - newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits) + repoUnits, newCnt, err := db.FindAndCount[repo_model.RepoUnit](db.DefaultContext, opts) assert.NoError(t, err) assert.EqualValues(t, cnt, newCnt) + assert.Len(t, repoUnits, repoUnitCount) } diff --git a/models/issues/comment.go b/models/issues/comment.go index 7fd07867df..a59fa570af 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1027,7 +1027,7 @@ type FindCommentsOptions struct { } // ToConds implements FindOptions interface -func (opts *FindCommentsOptions) ToConds() builder.Cond { +func (opts FindCommentsOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { cond = cond.And(builder.Eq{"issue.repo_id": opts.RepoID}) diff --git a/models/organization/org.go b/models/organization/org.go index 07091194eb..23a4e2f96a 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -456,7 +456,7 @@ func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { return builder.Select("org_id").From("org_user").Where(cond) } -func (opts FindOrgOptions) toConds() builder.Cond { +func (opts FindOrgOptions) ToConds() builder.Cond { var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization} if opts.UserID > 0 { cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate))) @@ -467,23 +467,8 @@ func (opts FindOrgOptions) toConds() builder.Cond { return cond } -// FindOrgs returns a list of organizations according given conditions -func FindOrgs(ctx context.Context, opts FindOrgOptions) ([]*Organization, error) { - orgs := make([]*Organization, 0, 10) - sess := db.GetEngine(ctx). - Where(opts.toConds()). - Asc("`user`.name") - if opts.Page > 0 && opts.PageSize > 0 { - sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1)) - } - return orgs, sess.Find(&orgs) -} - -// CountOrgs returns total count organizations according options -func CountOrgs(ctx context.Context, opts FindOrgOptions) (int64, error) { - return db.GetEngine(ctx). - Where(opts.toConds()). - Count(new(Organization)) +func (opts FindOrgOptions) ToOrders() string { + return "`user`.name ASC" } // HasOrgOrUserVisible tells if the given user can see the given org or user diff --git a/models/organization/org_test.go b/models/organization/org_test.go index aa72fc467e..5e40dd4190 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -131,7 +131,7 @@ func TestCountOrganizations(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{}) assert.NoError(t, err) - cnt, err := organization.CountOrgs(db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) + cnt, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) assert.NoError(t, err) assert.Equal(t, expected, cnt) } @@ -183,7 +183,7 @@ func TestIsPublicMembership(t *testing.T) { func TestFindOrgs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - orgs, err := organization.FindOrgs(db.DefaultContext, organization.FindOrgOptions{ + orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ UserID: 4, IncludePrivate: true, }) @@ -192,14 +192,14 @@ func TestFindOrgs(t *testing.T) { assert.EqualValues(t, 3, orgs[0].ID) } - orgs, err = organization.FindOrgs(db.DefaultContext, organization.FindOrgOptions{ + orgs, err = db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ UserID: 4, IncludePrivate: false, }) assert.NoError(t, err) assert.Len(t, orgs, 0) - total, err := organization.CountOrgs(db.DefaultContext, organization.FindOrgOptions{ + total, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ UserID: 4, IncludePrivate: true, }) diff --git a/models/project/project.go b/models/project/project.go index 3a1bfe1dbd..becfcbea1e 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -192,16 +192,16 @@ func IsTypeValid(p Type) bool { // SearchOptions are options for GetProjects type SearchOptions struct { + db.ListOptions OwnerID int64 RepoID int64 - Page int IsClosed util.OptionalBool OrderBy db.SearchOrderBy Type Type Title string } -func (opts *SearchOptions) toConds() builder.Cond { +func (opts SearchOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) @@ -226,9 +226,8 @@ func (opts *SearchOptions) toConds() builder.Cond { return cond } -// CountProjects counts projects -func CountProjects(ctx context.Context, opts SearchOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Project)) +func (opts SearchOptions) ToOrders() string { + return opts.OrderBy.String() } func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy { @@ -244,22 +243,6 @@ func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy { } } -// FindProjects returns a list of all projects that have been created in the repository -func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) { - e := db.GetEngine(ctx).Where(opts.toConds()) - if opts.OrderBy.String() != "" { - e = e.OrderBy(opts.OrderBy.String()) - } - projects := make([]*Project, 0, setting.UI.IssuePagingNum) - - if opts.Page > 0 { - e = e.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum) - } - - count, err := e.FindAndCount(&projects) - return projects, count, err -} - // NewProject creates a new Project func NewProject(ctx context.Context, p *Project) error { if !IsBoardTypeValid(p.BoardType) { diff --git a/models/project/project_test.go b/models/project/project_test.go index 6b5bd5b371..7a37c1faf2 100644 --- a/models/project/project_test.go +++ b/models/project/project_test.go @@ -34,13 +34,13 @@ func TestIsProjectTypeValid(t *testing.T) { func TestGetProjects(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - projects, _, err := FindProjects(db.DefaultContext, SearchOptions{RepoID: 1}) + projects, err := db.Find[Project](db.DefaultContext, SearchOptions{RepoID: 1}) assert.NoError(t, err) // 1 value for this repo exists in the fixtures assert.Len(t, projects, 1) - projects, _, err = FindProjects(db.DefaultContext, SearchOptions{RepoID: 3}) + projects, err = db.Find[Project](db.DefaultContext, SearchOptions{RepoID: 3}) assert.NoError(t, err) // 1 value for this repo exists in the fixtures @@ -109,7 +109,7 @@ func TestProjectsSort(t *testing.T) { } for _, tt := range tests { - projects, count, err := FindProjects(db.DefaultContext, SearchOptions{ + projects, count, err := db.FindAndCount[Project](db.DefaultContext, SearchOptions{ OrderBy: GetSearchOrderByBySortType(tt.sortType), }) assert.NoError(t, err) diff --git a/models/secret/secret.go b/models/secret/secret.go index 8df46b6c38..41e860d7f6 100644 --- a/models/secret/secret.go +++ b/models/secret/secret.go @@ -78,7 +78,7 @@ type FindSecretsOptions struct { Name string } -func (opts *FindSecretsOptions) toConds() builder.Cond { +func (opts FindSecretsOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.OwnerID > 0 { cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) @@ -96,22 +96,6 @@ func (opts *FindSecretsOptions) toConds() builder.Cond { return cond } -func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*Secret, error) { - var secrets []*Secret - sess := db.GetEngine(ctx) - if opts.PageSize != 0 { - sess = db.SetSessionPagination(sess, &opts.ListOptions) - } - return secrets, sess. - Where(opts.toConds()). - Find(&secrets) -} - -// CountSecrets counts the secrets -func CountSecrets(ctx context.Context, opts *FindSecretsOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Secret)) -} - // UpdateSecret changes org or user reop secret. func UpdateSecret(ctx context.Context, secretID int64, data string) error { encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data) diff --git a/models/user/external_login_user.go b/models/user/external_login_user.go index 4121c5d89f..0db702f225 100644 --- a/models/user/external_login_user.go +++ b/models/user/external_login_user.go @@ -96,19 +96,6 @@ func GetExternalLogin(ctx context.Context, externalLoginUser *ExternalLoginUser) return db.GetEngine(ctx).Get(externalLoginUser) } -// ListAccountLinks returns a map with the ExternalLoginUser and its LoginSource -func ListAccountLinks(ctx context.Context, user *User) ([]*ExternalLoginUser, error) { - externalAccounts := make([]*ExternalLoginUser, 0, 5) - err := db.GetEngine(ctx).Where("user_id=?", user.ID). - Desc("login_source_id"). - Find(&externalAccounts) - if err != nil { - return nil, err - } - - return externalAccounts, nil -} - // LinkExternalToUser link the external user to the user func LinkExternalToUser(ctx context.Context, user *User, externalLoginUser *ExternalLoginUser) error { has, err := db.GetEngine(ctx).Where("external_id=? AND login_source_id=?", externalLoginUser.ExternalID, externalLoginUser.LoginSourceID). @@ -173,28 +160,23 @@ func UpdateExternalUserByExternalID(ctx context.Context, external *ExternalLogin // FindExternalUserOptions represents an options to find external users type FindExternalUserOptions struct { + db.ListOptions Provider string - Limit int - Start int + UserID int64 + OrderBy string } -func (opts FindExternalUserOptions) toConds() builder.Cond { +func (opts FindExternalUserOptions) ToConds() builder.Cond { cond := builder.NewCond() if len(opts.Provider) > 0 { cond = cond.And(builder.Eq{"provider": opts.Provider}) } + if opts.UserID > 0 { + cond = cond.And(builder.Eq{"user_id": opts.UserID}) + } return cond } -// FindExternalUsersByProvider represents external users via provider -func FindExternalUsersByProvider(ctx context.Context, opts FindExternalUserOptions) ([]ExternalLoginUser, error) { - var users []ExternalLoginUser - err := db.GetEngine(ctx).Where(opts.toConds()). - Limit(opts.Limit, opts.Start). - OrderBy("login_source_id ASC, external_id ASC"). - Find(&users) - if err != nil { - return nil, err - } - return users, nil +func (opts FindExternalUserOptions) ToOrders() string { + return opts.OrderBy } diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index b28cea6a9c..408023507a 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -435,7 +435,7 @@ type ListWebhookOptions struct { IsActive util.OptionalBool } -func (opts *ListWebhookOptions) toCond() builder.Cond { +func (opts ListWebhookOptions) ToConds() builder.Cond { cond := builder.NewCond() if opts.RepoID != 0 { cond = cond.And(builder.Eq{"webhook.repo_id": opts.RepoID}) @@ -449,27 +449,6 @@ func (opts *ListWebhookOptions) toCond() builder.Cond { return cond } -// ListWebhooksByOpts return webhooks based on options -func ListWebhooksByOpts(ctx context.Context, opts *ListWebhookOptions) ([]*Webhook, error) { - sess := db.GetEngine(ctx).Where(opts.toCond()) - - if opts.Page != 0 { - sess = db.SetSessionPagination(sess, opts) - webhooks := make([]*Webhook, 0, opts.PageSize) - err := sess.Find(&webhooks) - return webhooks, err - } - - webhooks := make([]*Webhook, 0, 10) - err := sess.Find(&webhooks) - return webhooks, err -} - -// CountWebhooksByOpts count webhooks based on options and ignore pagination -func CountWebhooksByOpts(ctx context.Context, opts *ListWebhookOptions) (int64, error) { - return db.GetEngine(ctx).Where(opts.toCond()).Count(&Webhook{}) -} - // UpdateWebhook updates information of webhook. func UpdateWebhook(ctx context.Context, w *Webhook) error { _, err := db.GetEngine(ctx).ID(w.ID).AllCols().Update(w) diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index 6a01fdd75f..694fd7a873 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -123,7 +123,7 @@ func TestGetWebhookByOwnerID(t *testing.T) { func TestGetActiveWebhooksByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue}) + hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(1), hooks[0].ID) @@ -133,7 +133,7 @@ func TestGetActiveWebhooksByRepoID(t *testing.T) { func TestGetWebhooksByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{RepoID: 1}) + hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1}) assert.NoError(t, err) if assert.Len(t, hooks, 2) { assert.Equal(t, int64(1), hooks[0].ID) @@ -143,7 +143,7 @@ func TestGetWebhooksByRepoID(t *testing.T) { func TestGetActiveWebhooksByOwnerID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue}) + hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(3), hooks[0].ID) @@ -153,7 +153,7 @@ func TestGetActiveWebhooksByOwnerID(t *testing.T) { func TestGetWebhooksByOwnerID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3}) + hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(3), hooks[0].ID) |