-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
adding paging to get repositories from the database #1793
Changes from 1 commit
8ed8515
56ef552
239c364
670f37e
64db811
46ceeb6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ type Feed struct { | |
Name string `json:"name" meddler:"repo_name"` | ||
FullName string `json:"full_name" meddler:"repo_full_name"` | ||
|
||
Id int `json:"id,omitempty" meddler:"build_id,zeroisnull"` | ||
Number int `json:"number,omitempty" meddler:"build_number,zeroisnull"` | ||
Event string `json:"event,omitempty" meddler:"build_event,zeroisnull"` | ||
Status string `json:"status,omitempty" meddler:"build_status,zeroisnull"` | ||
|
@@ -25,3 +26,17 @@ type Feed struct { | |
Avatar string `json:"author_avatar,omitempty" meddler:"build_avatar,zeroisnull"` | ||
Email string `json:"author_email,omitempty" meddler:"build_email,zeroisnull"` | ||
} | ||
|
||
type Feeds []*Feed | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we keep this type in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, |
||
func (slice Feeds) Len() int { | ||
return len(slice) | ||
} | ||
|
||
func (slice Feeds) Less(i, j int) bool { | ||
return slice[i].Id < slice[j].Id; | ||
} | ||
|
||
func (slice Feeds) Swap(i, j int) { | ||
slice[i], slice[j] = slice[j], slice[i] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import ( | |
|
||
"github.com/drone/drone/model" | ||
"github.com/franela/goblin" | ||
"fmt" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import grouping and sorting :) |
||
) | ||
|
||
func TestRepos(t *testing.T) { | ||
|
@@ -138,6 +139,52 @@ func TestRepos(t *testing.T) { | |
g.Assert(count).Equal(2) | ||
}) | ||
|
||
g.It("Should Get a Repo List Paginated", func() { | ||
_repos := []*model.RepoLite{ | ||
{FullName: "bradrydzewski/drone"}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the newer versions of the Go linter will complain when underscores are used in variable names, so we've tried to start removing these from our code. So perhaps |
||
{FullName: "drone/drone"}, | ||
} | ||
_repo := []*model.Repo{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps |
||
{ | ||
UserID: 1, | ||
Owner: "bradrydzewski", | ||
Name: "drone", | ||
FullName: "bradrydzewski/drone", | ||
}, | ||
{ | ||
UserID: 2, | ||
Owner: "drone", | ||
Name: "drone", | ||
FullName: "drone/drone", | ||
}, | ||
} | ||
s.CreateRepo(_repo[0]) | ||
s.CreateRepo(_repo[1]) | ||
|
||
for i := 0; i < 3000; i++{ | ||
// find by 3000 repos | ||
_repos = append(_repos, &model.RepoLite{FullName: "octocat/hello-world"+ fmt.Sprint(i)}) | ||
// but create only 2000 repos | ||
if i >= 1999 && i < 2999{ | ||
continue | ||
} | ||
repo := &model.Repo{ | ||
UserID: 2, | ||
Owner: "octocat", | ||
Name: "hello-world" + fmt.Sprint(i), | ||
FullName: "octocat/hello-world" + fmt.Sprint(i), | ||
} | ||
_repo = append(_repo, repo) | ||
s.CreateRepo(repo) | ||
} | ||
repos, err := s.GetRepoListOf(_repos) | ||
g.Assert(err == nil).IsTrue() | ||
g.Assert(len(repos)).Equal(2002) | ||
g.Assert(repos[0].ID).Equal(_repo[0].ID) | ||
g.Assert(repos[1].ID).Equal(_repo[1].ID) | ||
g.Assert(repos[2001].ID).Equal(_repo[2001].ID) | ||
}) | ||
|
||
g.It("Should Delete a Repo", func() { | ||
repo := model.Repo{ | ||
UserID: 1, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import ( | |
|
||
"github.com/drone/drone/model" | ||
"github.com/russross/meddler" | ||
"sort" | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. imports should be grouped and sorted based on Go style guide. See https://github.com/golang/go/wiki/CodeReviewComments#imports There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I'm newbie in go. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no worries :) appreciate you taking the time to fix the issue and learn Go along the way! |
||
|
||
func (db *datastore) GetUser(id int64) (*model.User, error) { | ||
|
@@ -28,39 +29,49 @@ func (db *datastore) GetUserList() ([]*model.User, error) { | |
func (db *datastore) GetUserFeed(listof []*model.RepoLite) ([]*model.Feed, error) { | ||
var ( | ||
args []interface{} | ||
stmt string | ||
err error | ||
|
||
feed = []*model.Feed{} | ||
feed = model.Feeds{} | ||
) | ||
switch meddler.Default { | ||
case meddler.PostgreSQL: | ||
stmt, args = toListPosgres(listof) | ||
default: | ||
stmt, args = toList(listof) | ||
_stmt, _args := toList(listof) | ||
|
||
for i, stmt := range _stmt{ | ||
args = _args[i] | ||
if len(args) > 0 { | ||
var _feed []*model.Feed | ||
err = meddler.QueryAll(db, &_feed, fmt.Sprintf(userFeedQuery, stmt), args...) | ||
if err != nil{ | ||
break | ||
} | ||
feed = append(feed, _feed...) | ||
} | ||
} | ||
if len(args) > 0 { | ||
err = meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedQuery, stmt), args...) | ||
sort.Sort(sort.Reverse(feed)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can probably return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, you're right! |
||
limit := 50 | ||
if len(feed) < limit{ | ||
limit = len(feed) | ||
} | ||
return feed, err | ||
return feed[:limit], err | ||
} | ||
|
||
func (db *datastore) GetUserFeedLatest(listof []*model.RepoLite) ([]*model.Feed, error) { | ||
var ( | ||
args []interface{} | ||
stmt string | ||
err error | ||
|
||
feed = []*model.Feed{} | ||
) | ||
switch meddler.Default { | ||
case meddler.PostgreSQL: | ||
stmt, args = toListPosgres(listof) | ||
default: | ||
stmt, args = toList(listof) | ||
} | ||
if len(args) > 0 { | ||
err = meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedLatest, stmt), args...) | ||
_stmt, _args := toList(listof) | ||
|
||
for i, stmt := range(_stmt){ | ||
args = _args[i] | ||
if len(args) > 0 { | ||
var _feed []*model.Feed | ||
err = meddler.QueryAll(db, &_feed, fmt.Sprintf(userFeedLatest, stmt), args...) | ||
if err != nil{ | ||
break | ||
} | ||
feed = append(feed, _feed...) | ||
} | ||
} | ||
return feed, err | ||
} | ||
|
@@ -114,6 +125,7 @@ SELECT | |
repo_owner | ||
,repo_name | ||
,repo_full_name | ||
,build_id | ||
,build_number | ||
,build_event | ||
,build_status | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import ( | |
|
||
"github.com/drone/drone/model" | ||
"github.com/russross/meddler" | ||
"math" | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import grouping / ordering |
||
|
||
// rebind is a helper function that changes the sql | ||
|
@@ -17,7 +18,7 @@ func rebind(query string) string { | |
|
||
qb := []byte(query) | ||
// Add space enough for 5 params before we have to allocate | ||
rqb := make([]byte, 0, len(qb)+5) | ||
rqb := make([]byte, 0, len(qb) + 5) | ||
j := 1 | ||
for _, b := range qb { | ||
switch b { | ||
|
@@ -38,34 +39,33 @@ func rebind(query string) string { | |
|
||
// helper function that converts a simple repsitory list | ||
// to a sql IN statment. | ||
func toList(listof []*model.RepoLite) (string, []interface{}) { | ||
var size = len(listof) | ||
if size > 999 { | ||
size = 999 | ||
listof = listof[:999] | ||
} | ||
var qs = make([]string, size, size) | ||
var in = make([]interface{}, size, size) | ||
for i, repo := range listof { | ||
qs[i] = "?" | ||
in[i] = repo.FullName | ||
} | ||
return strings.Join(qs, ","), in | ||
} | ||
func toList(listof []*model.RepoLite) ([]string, [][]interface{}) { | ||
var total = len(listof) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we avoid returning a
where
it could make sense to slice the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was my first solution... It did not seem attractive for me because the limit variable and the core logic for pagination was replicated on the repos and users functions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
this limit could be a global constant, for example:
I think this is OK There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
note that it could always get split out into a separate helper function:
|
||
var limit = 999 | ||
var pagesCount = int(math.Ceil(float64(total) / float64(limit))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we avoid the float64 allocation and conversion here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure, because |
||
|
||
// helper function that converts a simple repository list | ||
// to a sql IN statement compatible with postgres. | ||
func toListPosgres(listof []*model.RepoLite) (string, []interface{}) { | ||
var size = len(listof) | ||
if size > 999 { | ||
size = 999 | ||
listof = listof[:999] | ||
} | ||
var qs = make([]string, size, size) | ||
var in = make([]interface{}, size, size) | ||
for i, repo := range listof { | ||
qs[i] = "$" + strconv.Itoa(i+1) | ||
in[i] = repo.FullName | ||
var qs = make([]string, pagesCount, pagesCount) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we have |
||
var in = make([][]interface{}, pagesCount, pagesCount) | ||
|
||
for page := 0; page < int(pagesCount); page++ { | ||
var start = page * limit | ||
var end = (page * limit) + limit | ||
if end > total{ | ||
end = total | ||
} | ||
var size = end - start | ||
var _qs = make([]string, size, size) | ||
var _in = make([]interface{}, size, size) | ||
for i, repo := range listof[start:end] { | ||
if meddler.Default == meddler.PostgreSQL { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this seems a bit inefficient since it could add thousands of extra evaluations depending on the size of the list. This was the benefit of having this split into two functions before. The prior implementation was more efficient at the expense of being dry (which was on purpose) |
||
_qs[i] = "$" + strconv.Itoa(i + 1) | ||
}else{ | ||
_qs[i] = "?" | ||
} | ||
_in[i] = repo.FullName | ||
} | ||
qs = append(qs, strings.Join(_qs, ",")) | ||
in = append(in, _in) | ||
} | ||
return strings.Join(qs, ","), in | ||
} | ||
return qs, in | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps we sort on
Created
instead since we already have the field available?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, i dont know why did it! 😊