From 87c55fbcafc126e21ab4bda02918437af1cf0965 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 5 May 2020 17:35:35 -0400 Subject: [PATCH] API: More progress on working cursors --- api/database/sq.go | 1 - api/graph/model/cursor.go | 11 +++++++++++ api/graph/model/repository.go | 16 +++++++++++++++- api/graph/schema.resolvers.go | 15 ++++++++++++--- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/api/database/sq.go b/api/database/sq.go index 82c8a2b..22b2558 100644 --- a/api/database/sq.go +++ b/api/database/sq.go @@ -8,7 +8,6 @@ import ( ) type Selectable interface { - As(alias string) Selectable Select(ctx context.Context) []string Fields(ctx context.Context) []interface{} } diff --git a/api/graph/model/cursor.go b/api/graph/model/cursor.go index 4a8955c..d6108b1 100644 --- a/api/graph/model/cursor.go +++ b/api/graph/model/cursor.go @@ -8,6 +8,7 @@ import ( "git.sr.ht/~sircmpwn/git.sr.ht/api/crypto" ) +// TODO: Add a field for the resource this is intended to be used with type Cursor struct { Count int `json:"count"` Next string `json:"next"` @@ -41,3 +42,13 @@ func (cur Cursor) MarshalGQL(w io.Writer) { w.Write(crypto.Encrypt(data)) w.Write([]byte("\"")) } + +func NewCursor(filter *Filter) *Cursor { + // TODO: Apply filter + return &Cursor{ + Count: 25, + Next: "", + OrderBy: "", + Search: "", + } +} diff --git a/api/graph/model/repository.go b/api/graph/model/repository.go index 501a4fe..86a8247 100644 --- a/api/graph/model/repository.go +++ b/api/graph/model/repository.go @@ -3,6 +3,7 @@ package model import ( "context" "time" + "strconv" "github.com/go-git/go-git/v5" sq "github.com/Masterminds/squirrel" @@ -66,7 +67,7 @@ func (r *Repository) Select(ctx context.Context) []string { database.WithAlias(r.alias, "owner_id")) } -func (r *Repository) As(alias string) database.Selectable { +func (r *Repository) As(alias string) *Repository { r.alias = alias return r } @@ -84,6 +85,19 @@ func (r *Repository) Fields(ctx context.Context) []interface{} { return append(fields, &r.Path, &r.OwnerID) } +func (r *Repository) ApplyCursor(q sq.SelectBuilder, c *Cursor) sq.SelectBuilder { + if c.Next != "" { + id, _ := strconv.Atoi(c.Next) + q = q.Where(r.alias + `.id <= ?`, id) + } + if c.OrderBy != "" { + q = q.OrderBy(c.OrderBy) + } else { + q = q.OrderBy(r.alias + `.id DESC`) + } + return q.Limit(uint64(c.Count + 1)) +} + func (r *Repository) DefaultSearch(query sq.SelectBuilder, term string) (sq.SelectBuilder, error) { name := database.WithAlias(r.alias, "name") diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go index 357aa06..9c4d271 100644 --- a/api/graph/schema.resolvers.go +++ b/api/graph/schema.resolvers.go @@ -160,17 +160,22 @@ func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor err error rows *sql.Rows ) + repo := (&model.Repository{}).As(`repo`) query := database. Select(ctx, repo). From(`repository repo`). - Where(`repo.owner_id = ?`, obj.ID). - OrderBy(`id DESC`). - Limit(26) + Where(`repo.owner_id = ?`, obj.ID) + if cursor == nil { + cursor = model.NewCursor(filter) + } + query = repo.ApplyCursor(query, cursor) + if rows, err = query.RunWith(r.DB).QueryContext(ctx); err != nil { panic(err) } defer rows.Close() + var repos []*model.Repository for rows.Next() { var repo model.Repository @@ -179,6 +184,7 @@ func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor } repos = append(repos, &repo) } + if len(repos) > 25 { cursor = &model.Cursor{ Count: 25, @@ -187,7 +193,10 @@ func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor Search: "", } repos = repos[:25] + } else { + cursor = nil } + return &model.RepositoryCursor{repos, cursor}, nil } -- 2.38.4