@@ 123,6 123,11 @@ type ComplexityRoot struct {
Target func(childComplexity int) int
}
+ ReferenceCursor struct {
+ Cursor func(childComplexity int) int
+ Results func(childComplexity int) int
+ }
+
Repository struct {
AccessControlList func(childComplexity int, cursor *model.Cursor) int
Created func(childComplexity int) int
@@ 231,7 236,7 @@ type RepositoryResolver interface {
Owner(ctx context.Context, obj *model.Repository) (model.Entity, error)
AccessControlList(ctx context.Context, obj *model.Repository, cursor *model.Cursor) (*model.ACLCursor, error)
- References(ctx context.Context, obj *model.Repository, cursor *model.Cursor) ([]*model.Reference, error)
+ References(ctx context.Context, obj *model.Repository, cursor *model.Cursor) (*model.ReferenceCursor, error)
}
type TreeResolver interface {
Entries(ctx context.Context, obj *model.Tree, cursor *model.Cursor) ([]*model.TreeEntry, error)
@@ 644,6 649,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Reference.Target(childComplexity), true
+ case "ReferenceCursor.cursor":
+ if e.complexity.ReferenceCursor.Cursor == nil {
+ break
+ }
+
+ return e.complexity.ReferenceCursor.Cursor(childComplexity), true
+
+ case "ReferenceCursor.results":
+ if e.complexity.ReferenceCursor.Results == nil {
+ break
+ }
+
+ return e.complexity.ReferenceCursor.Results(childComplexity), true
+
case "Repository.accessControlList":
if e.complexity.Repository.AccessControlList == nil {
break
@@ 1218,10 1237,7 @@ type Repository {
## Plumbing API:
# Returns a list of references for this repository
- #
- # glob: an optional string to filter the list of references, e.g. for tags
- # use "refs/tags/*", or leave null to enumerate all references
- references(cursor: Cursor): [Reference]!
+ references(cursor: Cursor): ReferenceCursor
# Returns a list of objects for this repository by their IDs (using fully
# qualified git object IDs, 40 character hex strings)
@@ 1273,6 1289,17 @@ type ACLCursor {
cursor: Cursor
}
+
+# A cursor for enumerating a list of references
+#
+# 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 ReferenceCursor {
+ results: [Reference]!
+ cursor: Cursor
+}
+
# Access Control List entry
type ACL {
id: Int!
@@ 3637,6 3664,71 @@ func (ec *executionContext) _Reference_follow(ctx context.Context, field graphql
return ec.marshalOObject2gitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐObject(ctx, field.Selections, res)
}
+func (ec *executionContext) _ReferenceCursor_results(ctx context.Context, field graphql.CollectedField, obj *model.ReferenceCursor) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "ReferenceCursor",
+ 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.Reference)
+ fc.Result = res
+ return ec.marshalNReference2ᚕᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐReference(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _ReferenceCursor_cursor(ctx context.Context, field graphql.CollectedField, obj *model.ReferenceCursor) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "ReferenceCursor",
+ 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_id(ctx context.Context, field graphql.CollectedField, obj *model.Repository) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ 3972,14 4064,11 @@ func (ec *executionContext) _Repository_references(ctx context.Context, field gr
return graphql.Null
}
if resTmp == nil {
- if !graphql.HasFieldError(ctx, fc) {
- ec.Errorf(ctx, "must not be null")
- }
return graphql.Null
}
- res := resTmp.([]*model.Reference)
+ res := resTmp.(*model.ReferenceCursor)
fc.Result = res
- return ec.marshalNReference2ᚕᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐReference(ctx, field.Selections, res)
+ return ec.marshalOReferenceCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐReferenceCursor(ctx, field.Selections, res)
}
func (ec *executionContext) _Repository_objects(ctx context.Context, field graphql.CollectedField, obj *model.Repository) (ret graphql.Marshaler) {
@@ 7200,6 7289,35 @@ func (ec *executionContext) _Reference(ctx context.Context, sel ast.SelectionSet
return out
}
+var referenceCursorImplementors = []string{"ReferenceCursor"}
+
+func (ec *executionContext) _ReferenceCursor(ctx context.Context, sel ast.SelectionSet, obj *model.ReferenceCursor) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, referenceCursorImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ var invalids uint32
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("ReferenceCursor")
+ case "results":
+ out.Values[i] = ec._ReferenceCursor_results(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "cursor":
+ out.Values[i] = ec._ReferenceCursor_cursor(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch()
+ if invalids > 0 {
+ return graphql.Null
+ }
+ return out
+}
+
var repositoryImplementors = []string{"Repository"}
func (ec *executionContext) _Repository(ctx context.Context, sel ast.SelectionSet, obj *model.Repository) graphql.Marshaler {
@@ 7274,9 7392,6 @@ func (ec *executionContext) _Repository(ctx context.Context, sel ast.SelectionSe
}
}()
res = ec._Repository_references(ctx, field, obj)
- if res == graphql.Null {
- atomic.AddUint32(&invalids, 1)
- }
return res
})
case "objects":
@@ 8839,6 8954,17 @@ func (ec *executionContext) marshalOReference2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgi
return ec._Reference(ctx, sel, v)
}
+func (ec *executionContext) marshalOReferenceCursor2gitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐReferenceCursor(ctx context.Context, sel ast.SelectionSet, v model.ReferenceCursor) graphql.Marshaler {
+ return ec._ReferenceCursor(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalOReferenceCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐReferenceCursor(ctx context.Context, sel ast.SelectionSet, v *model.ReferenceCursor) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return ec._ReferenceCursor(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalORepoInput2gitᚗsrᚗhtᚋאsircmpwnᚋgitᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐRepoInput(ctx context.Context, v interface{}) (model.RepoInput, error) {
return ec.unmarshalInputRepoInput(ctx, v)
}
@@ 18,6 18,40 @@ import (
"github.com/go-git/go-git/v5/plumbing"
)
+func (r *aCLResolver) Repository(ctx context.Context, obj *model.ACL) (*model.Repository, error) {
+ // XXX This could be moved into a loader, but it's unlikely to be a
+ // frequently utilized endpoint, so I'm not especially interested in the
+ // extra work/cruft.
+ repo := (&model.Repository{}).As(`repo`)
+ query := database.
+ Select(ctx, repo).
+ From(`repository repo`).
+ Join(`access acl ON acl.repo_id = repo.id`).
+ Where(`acl.id = ?`, obj.ID)
+ row := query.RunWith(r.DB).QueryRow()
+ if err := row.Scan(repo.Fields(ctx)...); err != nil {
+ panic(err)
+ }
+ return repo, nil
+}
+
+func (r *aCLResolver) Entity(ctx context.Context, obj *model.ACL) (model.Entity, error) {
+ // XXX This could be moved into a loader, but it's unlikely to be a
+ // frequently utilized endpoint, so I'm not especially interested in the
+ // extra work/cruft.
+ user := (&model.User{}).As(`u`)
+ query := database.
+ Select(ctx, user).
+ From(`"user" u`).
+ Join(`access acl ON acl.user_id = u.id`).
+ Where(`acl.id = ?`, obj.ID)
+ row := query.RunWith(r.DB).QueryRow()
+ if err := row.Scan(user.Fields(ctx)...); err != nil {
+ panic(err)
+ }
+ return user, nil
+}
+
func (r *mutationResolver) CreateRepository(ctx context.Context, params *model.RepoInput) (*model.Repository, error) {
panic(fmt.Errorf("createRepository: not implemented"))
}
@@ 127,59 161,41 @@ func (r *repositoryResolver) AccessControlList(ctx context.Context, obj *model.R
return &model.ACLCursor{acls, cursor}, nil
}
-func (r *aCLResolver) Repository(ctx context.Context, obj *model.ACL) (*model.Repository, error) {
- // XXX This could be moved into a loader, but it's unlikely to be a
- // frequently utilized endpoint, so I'm not especially interested in the
- // extra work/cruft.
- repo := (&model.Repository{}).As(`repo`)
- query := database.
- Select(ctx, repo).
- From(`repository repo`).
- Join(`access acl ON acl.repo_id = repo.id`).
- Where(`acl.id = ?`, obj.ID)
- row := query.RunWith(r.DB).QueryRow()
- if err := row.Scan(repo.Fields(ctx)...); err != nil {
- panic(err)
- }
- return repo, nil
-}
-
-func (r *aCLResolver) Entity(ctx context.Context, obj *model.ACL) (model.Entity, error) {
- // XXX This could be moved into a loader, but it's unlikely to be a
- // frequently utilized endpoint, so I'm not especially interested in the
- // extra work/cruft.
- user := (&model.User{}).As(`u`)
- query := database.
- Select(ctx, user).
- From(`"user" u`).
- Join(`access acl ON acl.user_id = u.id`).
- Where(`acl.id = ?`, obj.ID)
- row := query.RunWith(r.DB).QueryRow()
- if err := row.Scan(user.Fields(ctx)...); err != nil {
- panic(err)
- }
- return user, nil
-}
-
-func (r *repositoryResolver) References(ctx context.Context, obj *model.Repository, cursor *model.Cursor) ([]*model.Reference, error) {
+func (r *repositoryResolver) References(ctx context.Context, obj *model.Repository, cursor *model.Cursor) (*model.ReferenceCursor, error) {
iter, err := obj.Repo().References()
if err != nil {
return nil, err
}
defer iter.Close()
+
+ if cursor == nil {
+ cursor = model.NewCursor(nil)
+ }
+
var refs []*model.Reference
iter.ForEach(func(ref *plumbing.Reference) error {
refs = append(refs, &model.Reference{obj.Repo(), ref})
return nil
})
- // TODO: Implement globbing
+
sort.SliceStable(refs, func(i, j int) bool {
return refs[i].Name() < refs[j].Name()
})
- if len(refs) > 25 {
- refs = refs[:25]
+
+ // TODO: Implement cursor globbing/next
+
+ if len(refs) > cursor.Count {
+ cursor = &model.Cursor{
+ Count: cursor.Count,
+ Next: refs[len(refs)-1].Name(),
+ Search: cursor.Search,
+ }
+ refs = refs[:cursor.Count]
+ } else {
+ cursor = nil
}
- return refs, nil
+
+ return &model.ReferenceCursor{refs, cursor}, nil
}
func (r *treeResolver) Entries(ctx context.Context, obj *model.Tree, cursor *model.Cursor) ([]*model.TreeEntry, error) {