M api/database/ql.go => api/database/ql.go +27 -16
@@ 10,13 10,34 @@ import (
"git.sr.ht/~sircmpwn/gqlgen/graphql"
)
-func ColumnsFor(ctx context.Context, alias string,
- colMap map[string]string) []string {
-
+func collectFields(ctx context.Context) []graphql.CollectedField {
var fields []graphql.CollectedField
if graphql.GetFieldContext(ctx) != nil {
fields = graphql.CollectFieldsCtx(ctx, nil)
- } else {
+
+ octx := graphql.GetOperationContext(ctx)
+ for _, col := range fields {
+ if col.Name == "results" {
+ // This endpoint is using the cursor pattern; the columns we
+ // actually need to filter with are nested into the results
+ // field.
+ fields = graphql.CollectFields(octx, col.SelectionSet, nil)
+ break
+ }
+ }
+
+ sort.Slice(fields, func(a, b int) bool {
+ return fields[a].Name < fields[b].Name
+ })
+ }
+ return fields
+}
+
+func ColumnsFor(ctx context.Context, alias string,
+ colMap map[string]string) []string {
+
+ fields := collectFields(ctx)
+ if len(fields) == 0 {
// Collect all fields if we are not in an active graphql context
for qlCol, _ := range colMap {
fields = append(fields, graphql.CollectedField{
@@ 25,10 46,6 @@ func ColumnsFor(ctx context.Context, alias string,
}
}
- sort.Slice(fields, func(a, b int) bool {
- return fields[a].Name < fields[b].Name
- })
-
var columns []string
for _, qlCol := range fields {
if sqlCol, ok := colMap[qlCol.Name]; ok {
@@ 47,10 64,8 @@ func ColumnsFor(ctx context.Context, alias string,
func FieldsFor(ctx context.Context,
colMap map[string]interface{}) []interface{} {
- var qlFields []graphql.CollectedField
- if graphql.GetFieldContext(ctx) != nil {
- qlFields = graphql.CollectFieldsCtx(ctx, nil)
- } else {
+ qlFields := collectFields(ctx)
+ if len(qlFields) == 0 {
// Collect all fields if we are not in an active graphql context
for qlCol, _ := range colMap {
qlFields = append(qlFields, graphql.CollectedField{
@@ 59,10 74,6 @@ func FieldsFor(ctx context.Context,
}
}
- sort.Slice(qlFields, func(a, b int) bool {
- return qlFields[a].Name < qlFields[b].Name
- })
-
var fields []interface{}
for _, qlField := range qlFields {
if field, ok := colMap[qlField.Name]; ok {
M api/go.sum => api/go.sum +1 -0
@@ 2,6 2,7 @@ git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3 h1:4wDp4BKF7NQqoh7
git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw=
git.sr.ht/~sircmpwn/git.sr.ht v0.0.0-20200405134845-b8fbf5bf484f h1:SW8+xV65kcga0rHmQbnZkLG36yp286BcbVOdQTVo1m8=
git.sr.ht/~sircmpwn/git.sr.ht v0.0.0-20200413150414-046cd382d7b7 h1:PYRTIcsHR5W+aPn98OCC73ly528uw5o/4Z3b5Rvc7vA=
+git.sr.ht/~sircmpwn/git.sr.ht v0.0.0-20200430231646-4014870a700b h1:xHyh0xixoMog7F1kqOG55daFfK0uso98i0lQ/D4dSM8=
git.sr.ht/~sircmpwn/gqlgen v0.0.0-20200412134447-57d7234737d4 h1:J/Sb88htNHzZaN6ZEF8BnRWj3LzYoTrOL4WRhZEEiQE=
git.sr.ht/~sircmpwn/gqlgen v0.0.0-20200412134447-57d7234737d4/go.mod h1:W1cijL2EqAyL1eo1WAJ3ijNVkZM2okpYyCF5TRu1VfI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
M api/graph/generated/generated.go => api/graph/generated/generated.go +143 -65
@@ 121,7 121,6 @@ type ComplexityRoot struct {
Repository struct {
AccessControlList func(childComplexity int, cursor *model.Cursor) int
Created func(childComplexity int) int
- Cursor func(childComplexity int) int
Description func(childComplexity int) int
File func(childComplexity int, revspec *string, path string) int
Head func(childComplexity int) int
@@ 138,6 137,11 @@ type ComplexityRoot struct {
Visibility func(childComplexity int) int
}
+ RepositoryCursor struct {
+ Cursor func(childComplexity int) int
+ Results func(childComplexity int) int
+ }
+
Signature struct {
Email func(childComplexity int) int
Name func(childComplexity int) int
@@ 210,7 214,7 @@ type QueryResolver interface {
Me(ctx context.Context) (*model.User, error)
Cursor(ctx context.Context, filter model.Filter) (*model.Cursor, error)
User(ctx context.Context, username string) (*model.User, error)
- Repositories(ctx context.Context, cursor *model.Cursor) ([]*model.Repository, error)
+ Repositories(ctx context.Context, cursor *model.Cursor) (*model.RepositoryCursor, error)
Repository(ctx context.Context, id int) (*model.Repository, error)
RepositoryByName(ctx context.Context, name string) (*model.Repository, error)
RepositoryByOwner(ctx context.Context, owner string, repo string) (*model.Repository, error)
@@ 225,7 229,7 @@ type TreeResolver interface {
Entries(ctx context.Context, obj *model.Tree, cursor *model.Cursor) ([]*model.TreeEntry, error)
}
type UserResolver interface {
- Repositories(ctx context.Context, obj *model.User, cursor *model.Cursor) ([]*model.Repository, error)
+ Repositories(ctx context.Context, obj *model.User, cursor *model.Cursor) (*model.RepositoryCursor, error)
}
type executableSchema struct {
@@ 649,13 653,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Repository.Created(childComplexity), true
- case "Repository.cursor":
- if e.complexity.Repository.Cursor == nil {
- break
- }
-
- return e.complexity.Repository.Cursor(childComplexity), true
-
case "Repository.description":
if e.complexity.Repository.Description == nil {
break
@@ 784,6 781,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Repository.Visibility(childComplexity), true
+ case "RepositoryCursor.cursor":
+ if e.complexity.RepositoryCursor.Cursor == nil {
+ break
+ }
+
+ return e.complexity.RepositoryCursor.Cursor(childComplexity), true
+
+ case "RepositoryCursor.results":
+ if e.complexity.RepositoryCursor.Results == nil {
+ break
+ }
+
+ return e.complexity.RepositoryCursor.Results(childComplexity), true
+
case "Signature.email":
if e.complexity.Signature.Email == nil {
break
@@ 1158,7 1169,7 @@ interface Entity {
canonicalName: String!
# A list of repositories owned by this entity
- repositories(cursor: Cursor): [Repository]!
+ repositories(cursor: Cursor): RepositoryCursor
}
# A registered user
@@ 1174,7 1185,7 @@ type User implements Entity {
bio: String
# A list of repositories owned by this user
- repositories(cursor: Cursor): [Repository]!
+ repositories(cursor: Cursor): RepositoryCursor
}
# A git repository
@@ 1187,9 1198,6 @@ type Repository {
description: String
visibility: Visibility!
- # Pass this into the same endpoint to receive a new page of results
- cursor: Cursor
-
# If this repository was cloned from another, this will be set to the
# original clone URL
upstreamUrl: String
@@ 1235,6 1243,16 @@ type Repository {
revparse_single(revspec: String!): Object
}
+# A cursor for enumerating a list of repositories
+#
+# If there are additional results available, the cursor object may be passed
+# back into the same endpoint to retrieve another page. If the cursor is null,
+# there are no remaining results to return.
+type RepositoryCursor {
+ results: [Repository]!
+ cursor: Cursor
+}
+
# Access Control List entry
type ACL {
id: Int!
@@ 1382,7 1400,7 @@ type Query {
# will be to return all repositories that the user either (1) has been given
# explicit access to via ACLs or (2) has implicit access to either by
# ownership or group membership.
- repositories(cursor: Cursor): [Repository]!
+ repositories(cursor: Cursor): RepositoryCursor
# Returns a specific repository
repository(id: Int!): Repository
@@ 3284,14 3302,11 @@ func (ec *executionContext) _Query_repositories(ctx context.Context, field graph
return graphql.Null
}
if resTmp == nil {
- if !graphql.HasFieldError(ctx, fc) {
- ec.Errorf(ctx, "must not be null")
- }
return graphql.Null
}
- res := resTmp.([]*model.Repository)
+ res := resTmp.(*model.RepositoryCursor)
fc.Result = res
- return ec.marshalNRepository2ᚕᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepository(ctx, field.Selections, res)
+ return ec.marshalORepositoryCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepositoryCursor(ctx, field.Selections, res)
}
func (ec *executionContext) _Query_repository(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ 3811,37 3826,6 @@ func (ec *executionContext) _Repository_visibility(ctx context.Context, field gr
return ec.marshalNVisibility2gitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐVisibility(ctx, field.Selections, res)
}
-func (ec *executionContext) _Repository_cursor(ctx context.Context, field graphql.CollectedField, obj *model.Repository) (ret graphql.Marshaler) {
- defer func() {
- if r := recover(); r != nil {
- ec.Error(ctx, ec.Recover(ctx, r))
- ret = graphql.Null
- }
- }()
- fc := &graphql.FieldContext{
- Object: "Repository",
- Field: field,
- Args: nil,
- IsMethod: false,
- }
-
- ctx = graphql.WithFieldContext(ctx, fc)
- resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
- ctx = rctx // use context from middleware stack in children
- return obj.Cursor, nil
- })
- if err != nil {
- ec.Error(ctx, err)
- return graphql.Null
- }
- if resTmp == nil {
- return graphql.Null
- }
- res := resTmp.(*model.Cursor)
- fc.Result = res
- return ec.marshalOCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐCursor(ctx, field.Selections, res)
-}
-
func (ec *executionContext) _Repository_upstreamUrl(ctx context.Context, field graphql.CollectedField, obj *model.Repository) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ 4182,6 4166,71 @@ func (ec *executionContext) _Repository_revparse_single(ctx context.Context, fie
return ec.marshalOObject2gitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐObject(ctx, field.Selections, res)
}
+func (ec *executionContext) _RepositoryCursor_results(ctx context.Context, field graphql.CollectedField, obj *model.RepositoryCursor) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "RepositoryCursor",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Results, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]*model.Repository)
+ fc.Result = res
+ return ec.marshalNRepository2ᚕᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepository(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _RepositoryCursor_cursor(ctx context.Context, field graphql.CollectedField, obj *model.RepositoryCursor) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "RepositoryCursor",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Cursor, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*model.Cursor)
+ fc.Result = res
+ return ec.marshalOCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐCursor(ctx, field.Selections, res)
+}
+
func (ec *executionContext) _Signature_name(ctx context.Context, field graphql.CollectedField, obj *model.Signature) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ 5266,14 5315,11 @@ func (ec *executionContext) _User_repositories(ctx context.Context, field graphq
return graphql.Null
}
if resTmp == nil {
- if !graphql.HasFieldError(ctx, fc) {
- ec.Errorf(ctx, "must not be null")
- }
return graphql.Null
}
- res := resTmp.([]*model.Repository)
+ res := resTmp.(*model.RepositoryCursor)
fc.Result = res
- return ec.marshalNRepository2ᚕᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepository(ctx, field.Selections, res)
+ return ec.marshalORepositoryCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepositoryCursor(ctx, field.Selections, res)
}
func (ec *executionContext) _Version_major(ctx context.Context, field graphql.CollectedField, obj *model.Version) (ret graphql.Marshaler) {
@@ 6991,9 7037,6 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
}
}()
res = ec._Query_repositories(ctx, field)
- if res == graphql.Null {
- atomic.AddUint32(&invalids, 1)
- }
return res
})
case "repository":
@@ 7130,8 7173,6 @@ func (ec *executionContext) _Repository(ctx context.Context, sel ast.SelectionSe
if out.Values[i] == graphql.Null {
atomic.AddUint32(&invalids, 1)
}
- case "cursor":
- out.Values[i] = ec._Repository_cursor(ctx, field, obj)
case "upstreamUrl":
out.Values[i] = ec._Repository_upstreamUrl(ctx, field, obj)
case "accessControlList":
@@ 7191,6 7232,35 @@ func (ec *executionContext) _Repository(ctx context.Context, sel ast.SelectionSe
return out
}
+var repositoryCursorImplementors = []string{"RepositoryCursor"}
+
+func (ec *executionContext) _RepositoryCursor(ctx context.Context, sel ast.SelectionSet, obj *model.RepositoryCursor) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, repositoryCursorImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ var invalids uint32
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("RepositoryCursor")
+ case "results":
+ out.Values[i] = ec._RepositoryCursor_results(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "cursor":
+ out.Values[i] = ec._RepositoryCursor_cursor(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch()
+ if invalids > 0 {
+ return graphql.Null
+ }
+ return out
+}
+
var signatureImplementors = []string{"Signature"}
func (ec *executionContext) _Signature(ctx context.Context, sel ast.SelectionSet, obj *model.Signature) graphql.Marshaler {
@@ 7470,9 7540,6 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
}
}()
res = ec._User_repositories(ctx, field, obj)
- if res == graphql.Null {
- atomic.AddUint32(&invalids, 1)
- }
return res
})
default:
@@ 8700,6 8767,17 @@ func (ec *executionContext) marshalORepository2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋg
return ec._Repository(ctx, sel, v)
}
+func (ec *executionContext) marshalORepositoryCursor2gitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepositoryCursor(ctx context.Context, sel ast.SelectionSet, v model.RepositoryCursor) graphql.Marshaler {
+ return ec._RepositoryCursor(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalORepositoryCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepositoryCursor(ctx context.Context, sel ast.SelectionSet, v *model.RepositoryCursor) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return ec._RepositoryCursor(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) {
return graphql.UnmarshalString(v)
}
M api/graph/model/cursor.go => api/graph/model/cursor.go +2 -0
@@ 37,5 37,7 @@ func (cur Cursor) MarshalGQL(w io.Writer) {
if err != nil {
panic(err)
}
+ w.Write([]byte("\""))
w.Write(crypto.Encrypt(data))
+ w.Write([]byte("\""))
}
M api/graph/model/models_gen.go => api/graph/model/models_gen.go +5 -0
@@ 43,6 43,11 @@ type RepoInput struct {
Visibility *Visibility `json:"visibility"`
}
+type RepositoryCursor struct {
+ Results []*Repository `json:"results"`
+ Cursor *Cursor `json:"cursor"`
+}
+
type Signature struct {
Name string `json:"name"`
Email string `json:"email"`
M api/graph/model/repository.go => api/graph/model/repository.go +1 -1
@@ 72,7 72,7 @@ func (r *Repository) As(alias string) database.Selectable {
}
func (r *Repository) Fields(ctx context.Context) []interface{} {
- fields := FieldsFor(ctx, map[string]interface{}{
+ fields := database.FieldsFor(ctx, map[string]interface{}{
"id": &r.ID,
"created": &r.Created,
"updated": &r.Updated,
D api/graph/model/util.go => api/graph/model/util.go +0 -71
@@ 1,71 0,0 @@
-package model
-
-import (
- "context"
- "sort"
-
- "git.sr.ht/~sircmpwn/gqlgen/graphql"
- "github.com/vektah/gqlparser/v2/ast"
-)
-
-func ColumnsFor(ctx context.Context,
- colMap map[string]string, tbl string) []string {
-
- var fields []graphql.CollectedField
- if graphql.GetFieldContext(ctx) != nil {
- fields = graphql.CollectFieldsCtx(ctx, nil)
- } else {
- // Collect all fields if we are not in an active graphql context
- for qlCol, _ := range colMap {
- fields = append(fields, graphql.CollectedField{
- &ast.Field{Name: qlCol}, nil,
- })
- }
- }
-
- sort.Slice(fields, func(a, b int) bool {
- return fields[a].Name < fields[b].Name
- })
-
- var columns []string
- for _, qlCol := range fields {
- if sqlCol, ok := colMap[qlCol.Name]; ok {
- if tbl != "" {
- columns = append(columns, tbl+"."+sqlCol)
- } else {
- columns = append(columns, sqlCol)
- }
- }
- }
-
- return columns
-}
-
-func FieldsFor(ctx context.Context,
- colMap map[string]interface{}) []interface{} {
-
- var qlFields []graphql.CollectedField
- if graphql.GetFieldContext(ctx) != nil {
- qlFields = graphql.CollectFieldsCtx(ctx, nil)
- } else {
- // Collect all fields if we are not in an active graphql context
- for qlCol, _ := range colMap {
- qlFields = append(qlFields, graphql.CollectedField{
- &ast.Field{Name: qlCol}, nil,
- })
- }
- }
-
- sort.Slice(qlFields, func(a, b int) bool {
- return qlFields[a].Name < qlFields[b].Name
- })
-
- var fields []interface{}
- for _, qlField := range qlFields {
- if field, ok := colMap[qlField.Name]; ok {
- fields = append(fields, field)
- }
- }
-
- return fields
-}
M api/graph/schema.graphqls => api/graph/schema.graphqls +13 -6
@@ 41,7 41,7 @@ interface Entity {
canonicalName: String!
# A list of repositories owned by this entity
- repositories(cursor: Cursor): [Repository]!
+ repositories(cursor: Cursor): RepositoryCursor
}
# A registered user
@@ 57,7 57,7 @@ type User implements Entity {
bio: String
# A list of repositories owned by this user
- repositories(cursor: Cursor): [Repository]!
+ repositories(cursor: Cursor): RepositoryCursor
}
# A git repository
@@ 70,9 70,6 @@ type Repository {
description: String
visibility: Visibility!
- # Pass this into the same endpoint to receive a new page of results
- cursor: Cursor
-
# If this repository was cloned from another, this will be set to the
# original clone URL
upstreamUrl: String
@@ 118,6 115,16 @@ type Repository {
revparse_single(revspec: String!): Object
}
+# A cursor for enumerating a list of repositories
+#
+# If there are additional results available, the cursor object may be passed
+# back into the same endpoint to retrieve another page. If the cursor is null,
+# there are no remaining results to return.
+type RepositoryCursor {
+ results: [Repository]!
+ cursor: Cursor
+}
+
# Access Control List entry
type ACL {
id: Int!
@@ 265,7 272,7 @@ type Query {
# will be to return all repositories that the user either (1) has been given
# explicit access to via ACLs or (2) has implicit access to either by
# ownership or group membership.
- repositories(cursor: Cursor): [Repository]!
+ repositories(cursor: Cursor): RepositoryCursor
# Returns a specific repository
repository(id: Int!): Repository
M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +16 -5
@@ 8,6 8,7 @@ import (
"database/sql"
"fmt"
"sort"
+ "strconv"
"strings"
"git.sr.ht/~sircmpwn/git.sr.ht/api/auth"
@@ 78,7 79,7 @@ func (r *queryResolver) User(ctx context.Context, username string) (*model.User,
return loaders.ForContext(ctx).UsersByName.Load(username)
}
-func (r *queryResolver) Repositories(ctx context.Context, cursor *model.Cursor) ([]*model.Repository, error) {
+func (r *queryResolver) Repositories(ctx context.Context, cursor *model.Cursor) (*model.RepositoryCursor, error) {
var (
err error
rows *sql.Rows
@@ 103,7 104,8 @@ func (r *queryResolver) Repositories(ctx context.Context, cursor *model.Cursor)
}
repos = append(repos, &repo)
}
- return repos, nil
+ // TODO: Cursor
+ return &model.RepositoryCursor{repos, nil}, nil
}
func (r *queryResolver) Repository(ctx context.Context, id int) (*model.Repository, error) {
@@ 157,7 159,7 @@ func (r *treeResolver) Entries(ctx context.Context, obj *model.Tree, cursor *mod
panic(fmt.Errorf("not implemented"))
}
-func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor *model.Cursor) ([]*model.Repository, error) {
+func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor *model.Cursor) (*model.RepositoryCursor, error) {
var (
err error
rows *sql.Rows
@@ 168,7 170,7 @@ func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor
From(`repository repo`).
Where(`repo.owner_id = ?`, obj.ID).
OrderBy(`id DESC`).
- Limit(25)
+ Limit(26)
if rows, err = query.RunWith(r.DB).QueryContext(ctx); err != nil {
panic(err)
}
@@ 181,7 183,16 @@ func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor
}
repos = append(repos, &repo)
}
- return repos, nil
+ if len(repos) > 25 {
+ cursor = &model.Cursor{
+ Count: 25,
+ Next: strconv.Itoa(repos[len(repos)-1].ID),
+ OrderBy: `id DESC`,
+ Search: "",
+ }
+ repos = repos[:25]
+ }
+ return &model.RepositoryCursor{repos, cursor}, nil
}
// Mutation returns generated.MutationResolver implementation.