From 7df170939f2bad0f03b834dda5af1b55bd0d6830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Mur=C3=A9?= Date: Wed, 4 Sep 2019 21:04:05 +0200 Subject: [PATCH] graphql: make repository.validLabels a connection --- graphql/connections/connections.go | 1 + graphql/connections/gen_label.go | 113 +++++++ graphql/graph/gen_graph.go | 515 ++++++++++++++++++++++++++++- graphql/models/edges.go | 5 + graphql/models/gen_models.go | 12 + graphql/resolvers/repo.go | 27 +- graphql/schema/label.graphql | 19 ++ graphql/schema/repository.graphql | 11 +- graphql/schema/types.graphql | 8 - 9 files changed, 685 insertions(+), 26 deletions(-) create mode 100644 graphql/connections/gen_label.go create mode 100644 graphql/schema/label.graphql diff --git a/graphql/connections/connections.go b/graphql/connections/connections.go index d82c5620..82ad2514 100644 --- a/graphql/connections/connections.go +++ b/graphql/connections/connections.go @@ -4,6 +4,7 @@ //go:generate genny -in=connection_template.go -out=gen_operation.go gen "Name=Operation NodeType=bug.Operation EdgeType=models.OperationEdge ConnectionType=models.OperationConnection" //go:generate genny -in=connection_template.go -out=gen_comment.go gen "Name=Comment NodeType=bug.Comment EdgeType=models.CommentEdge ConnectionType=models.CommentConnection" //go:generate genny -in=connection_template.go -out=gen_timeline.go gen "Name=TimelineItem NodeType=bug.TimelineItem EdgeType=models.TimelineItemEdge ConnectionType=models.TimelineItemConnection" +//go:generate genny -in=connection_template.go -out=gen_label.go gen "Name=Label NodeType=bug.Label EdgeType=models.LabelEdge ConnectionType=models.LabelConnection" // Package connections implement a generic GraphQL relay connection package connections diff --git a/graphql/connections/gen_label.go b/graphql/connections/gen_label.go new file mode 100644 index 00000000..7f1b2fc9 --- /dev/null +++ b/graphql/connections/gen_label.go @@ -0,0 +1,113 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package connections + +import ( + "fmt" + + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/graphql/models" +) + +// BugLabelEdgeMaker define a function that take a bug.Label and an offset and +// create an Edge. +type LabelEdgeMaker func(value bug.Label, offset int) Edge + +// LabelConMaker define a function that create a models.LabelConnection +type LabelConMaker func( + edges []*models.LabelEdge, + nodes []bug.Label, + info *models.PageInfo, + totalCount int) (*models.LabelConnection, error) + +// LabelCon will paginate a source according to the input of a relay connection +func LabelCon(source []bug.Label, edgeMaker LabelEdgeMaker, conMaker LabelConMaker, input models.ConnectionInput) (*models.LabelConnection, error) { + var nodes []bug.Label + var edges []*models.LabelEdge + var cursors []string + var pageInfo = &models.PageInfo{} + var totalCount = len(source) + + emptyCon, _ := conMaker(edges, nodes, pageInfo, 0) + + offset := 0 + + if input.After != nil { + for i, value := range source { + edge := edgeMaker(value, i) + if edge.GetCursor() == *input.After { + // remove all previous element including the "after" one + source = source[i+1:] + offset = i + 1 + pageInfo.HasPreviousPage = true + break + } + } + } + + if input.Before != nil { + for i, value := range source { + edge := edgeMaker(value, i+offset) + + if edge.GetCursor() == *input.Before { + // remove all after element including the "before" one + pageInfo.HasNextPage = true + break + } + + e := edge.(models.LabelEdge) + edges = append(edges, &e) + cursors = append(cursors, edge.GetCursor()) + nodes = append(nodes, value) + } + } else { + edges = make([]*models.LabelEdge, len(source)) + cursors = make([]string, len(source)) + nodes = source + + for i, value := range source { + edge := edgeMaker(value, i+offset) + e := edge.(models.LabelEdge) + edges[i] = &e + cursors[i] = edge.GetCursor() + } + } + + if input.First != nil { + if *input.First < 0 { + return emptyCon, fmt.Errorf("first less than zero") + } + + if len(edges) > *input.First { + // Slice result to be of length first by removing edges from the end + edges = edges[:*input.First] + cursors = cursors[:*input.First] + nodes = nodes[:*input.First] + pageInfo.HasNextPage = true + } + } + + if input.Last != nil { + if *input.Last < 0 { + return emptyCon, fmt.Errorf("last less than zero") + } + + if len(edges) > *input.Last { + // Slice result to be of length last by removing edges from the start + edges = edges[len(edges)-*input.Last:] + cursors = cursors[len(cursors)-*input.Last:] + nodes = nodes[len(nodes)-*input.Last:] + pageInfo.HasPreviousPage = true + } + } + + // Fill up pageInfo cursors + if len(cursors) > 0 { + pageInfo.StartCursor = cursors[0] + pageInfo.EndCursor = cursors[len(cursors)-1] + } + + return conMaker(edges, nodes, pageInfo, totalCount) +} diff --git a/graphql/graph/gen_graph.go b/graphql/graph/gen_graph.go index c052e57b..a1f7133d 100644 --- a/graphql/graph/gen_graph.go +++ b/graphql/graph/gen_graph.go @@ -252,6 +252,18 @@ type ComplexityRoot struct { Removed func(childComplexity int) int } + LabelConnection struct { + Edges func(childComplexity int) int + Nodes func(childComplexity int) int + PageInfo func(childComplexity int) int + TotalCount func(childComplexity int) int + } + + LabelEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + Mutation struct { AddComment func(childComplexity int, input models.AddCommentInput) int ChangeLabels func(childComplexity int, input *models.ChangeLabelInput) int @@ -305,7 +317,7 @@ type ComplexityRoot struct { Bug func(childComplexity int, prefix string) int Identity func(childComplexity int, prefix string) int UserIdentity func(childComplexity int) int - ValidLabels func(childComplexity int) int + ValidLabels func(childComplexity int, after *string, before *string, first *int, last *int) int } SetStatusOperation struct { @@ -452,7 +464,7 @@ type RepositoryResolver interface { AllIdentities(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) Identity(ctx context.Context, obj *models.Repository, prefix string) (identity.Interface, error) UserIdentity(ctx context.Context, obj *models.Repository) (identity.Interface, error) - ValidLabels(ctx context.Context, obj *models.Repository) ([]bug.Label, error) + ValidLabels(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.LabelConnection, error) } type SetStatusOperationResolver interface { ID(ctx context.Context, obj *bug.SetStatusOperation) (string, error) @@ -1287,6 +1299,48 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.LabelChangeTimelineItem.Removed(childComplexity), true + case "LabelConnection.edges": + if e.complexity.LabelConnection.Edges == nil { + break + } + + return e.complexity.LabelConnection.Edges(childComplexity), true + + case "LabelConnection.nodes": + if e.complexity.LabelConnection.Nodes == nil { + break + } + + return e.complexity.LabelConnection.Nodes(childComplexity), true + + case "LabelConnection.pageInfo": + if e.complexity.LabelConnection.PageInfo == nil { + break + } + + return e.complexity.LabelConnection.PageInfo(childComplexity), true + + case "LabelConnection.totalCount": + if e.complexity.LabelConnection.TotalCount == nil { + break + } + + return e.complexity.LabelConnection.TotalCount(childComplexity), true + + case "LabelEdge.cursor": + if e.complexity.LabelEdge.Cursor == nil { + break + } + + return e.complexity.LabelEdge.Cursor(childComplexity), true + + case "LabelEdge.node": + if e.complexity.LabelEdge.Node == nil { + break + } + + return e.complexity.LabelEdge.Node(childComplexity), true + case "Mutation.addComment": if e.complexity.Mutation.AddComment == nil { break @@ -1574,7 +1628,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - return e.complexity.Repository.ValidLabels(childComplexity), true + args, err := ec.field_Repository_validLabels_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Repository.ValidLabels(childComplexity, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int)), true case "SetStatusOperation.author": if e.complexity.SetStatusOperation.Author == nil { @@ -1977,6 +2036,25 @@ type IdentityConnection { type IdentityEdge { cursor: String! node: Identity! +}`}, + &ast.Source{Name: "schema/label.graphql", Input: `"""Label for a bug.""" +type Label { + """The name of the label.""" + name: String! + """Color of the label.""" + color: Color! +} + +type LabelConnection { + edges: [LabelEdge!]! + nodes: [Label!]! + pageInfo: PageInfo! + totalCount: Int! +} + +type LabelEdge { + cursor: String! + node: Label! }`}, &ast.Source{Name: "schema/mutations.graphql", Input: `input NewBugInput { """A unique identifier for the client performing the mutation.""" @@ -2286,7 +2364,16 @@ type Repository { userIdentity: Identity """List of valid labels.""" - validLabels: [Label!]! + validLabels( + """Returns the elements in the list that come after the specified cursor.""" + after: String + """Returns the elements in the list that come before the specified cursor.""" + before: String + """Returns the first _n_ elements from the list.""" + first: Int + """Returns the last _n_ elements from the list.""" + last: Int + ): LabelConnection! }`}, &ast.Source{Name: "schema/root.graphql", Input: `type Query { """The default unnamend repository.""" @@ -2414,14 +2501,6 @@ type Color { B: Int! } -"""Label for a bug.""" -type Label { - """The name of the label.""" - name: String! - """Color of the label.""" - color: Color! -} - """Information about pagination in a connection.""" type PageInfo { """When paginating forwards, are there more items?""" @@ -2888,6 +2967,44 @@ func (ec *executionContext) field_Repository_identity_args(ctx context.Context, return args, nil } +func (ec *executionContext) field_Repository_validLabels_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["after"]; ok { + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg0 + var arg1 *string + if tmp, ok := rawArgs["before"]; ok { + arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["before"] = arg1 + var arg2 *int + if tmp, ok := rawArgs["first"]; ok { + arg2, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["first"] = arg2 + var arg3 *int + if tmp, ok := rawArgs["last"]; ok { + arg3, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["last"] = arg3 + return args, nil +} + func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -7002,6 +7119,228 @@ func (ec *executionContext) _LabelChangeTimelineItem_removed(ctx context.Context return ec.marshalNLabel2ᚕgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐLabel(ctx, field.Selections, res) } +func (ec *executionContext) _LabelConnection_edges(ctx context.Context, field graphql.CollectedField, obj *models.LabelConnection) (ret graphql.Marshaler) { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() + rctx := &graphql.ResolverContext{ + Object: "LabelConnection", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Edges, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*models.LabelEdge) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNLabelEdge2ᚕᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelEdge(ctx, field.Selections, res) +} + +func (ec *executionContext) _LabelConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *models.LabelConnection) (ret graphql.Marshaler) { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() + rctx := &graphql.ResolverContext{ + Object: "LabelConnection", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Nodes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]bug.Label) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNLabel2ᚕgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐLabel(ctx, field.Selections, res) +} + +func (ec *executionContext) _LabelConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *models.LabelConnection) (ret graphql.Marshaler) { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() + rctx := &graphql.ResolverContext{ + Object: "LabelConnection", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*models.PageInfo) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNPageInfo2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) _LabelConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *models.LabelConnection) (ret graphql.Marshaler) { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() + rctx := &graphql.ResolverContext{ + Object: "LabelConnection", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TotalCount, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) _LabelEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *models.LabelEdge) (ret graphql.Marshaler) { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() + rctx := &graphql.ResolverContext{ + Object: "LabelEdge", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + 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 { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _LabelEdge_node(ctx context.Context, field graphql.CollectedField, obj *models.LabelEdge) (ret graphql.Marshaler) { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() + rctx := &graphql.ResolverContext{ + Object: "LabelEdge", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Node, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bug.Label) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNLabel2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐLabel(ctx, field.Selections, res) +} + func (ec *executionContext) _Mutation_newBug(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { @@ -8310,10 +8649,17 @@ func (ec *executionContext) _Repository_validLabels(ctx context.Context, field g IsMethod: true, } ctx = graphql.WithResolverContext(ctx, rctx) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Repository_validLabels_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + rctx.Args = args ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Repository().ValidLabels(rctx, obj) + return ec.resolvers.Repository().ValidLabels(rctx, obj, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int)) }) if err != nil { ec.Error(ctx, err) @@ -8325,10 +8671,10 @@ func (ec *executionContext) _Repository_validLabels(ctx context.Context, field g } return graphql.Null } - res := resTmp.([]bug.Label) + res := resTmp.(*models.LabelConnection) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec.marshalNLabel2ᚕgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐLabel(ctx, field.Selections, res) + return ec.marshalNLabelConnection2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelConnection(ctx, field.Selections, res) } func (ec *executionContext) _SetStatusOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusOperation) (ret graphql.Marshaler) { @@ -12293,6 +12639,80 @@ func (ec *executionContext) _LabelChangeTimelineItem(ctx context.Context, sel as return out } +var labelConnectionImplementors = []string{"LabelConnection"} + +func (ec *executionContext) _LabelConnection(ctx context.Context, sel ast.SelectionSet, obj *models.LabelConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.RequestContext, sel, labelConnectionImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LabelConnection") + case "edges": + out.Values[i] = ec._LabelConnection_edges(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "nodes": + out.Values[i] = ec._LabelConnection_nodes(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "pageInfo": + out.Values[i] = ec._LabelConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "totalCount": + out.Values[i] = ec._LabelConnection_totalCount(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var labelEdgeImplementors = []string{"LabelEdge"} + +func (ec *executionContext) _LabelEdge(ctx context.Context, sel ast.SelectionSet, obj *models.LabelEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.RequestContext, sel, labelEdgeImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LabelEdge") + case "cursor": + out.Values[i] = ec._LabelEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "node": + out.Values[i] = ec._LabelEdge_node(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var mutationImplementors = []string{"Mutation"} func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { @@ -13987,6 +14407,71 @@ func (ec *executionContext) marshalNLabelChangeStatus2githubᚗcomᚋMichaelMure return v } +func (ec *executionContext) marshalNLabelConnection2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelConnection(ctx context.Context, sel ast.SelectionSet, v models.LabelConnection) graphql.Marshaler { + return ec._LabelConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNLabelConnection2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelConnection(ctx context.Context, sel ast.SelectionSet, v *models.LabelConnection) graphql.Marshaler { + if v == nil { + if !ec.HasError(graphql.GetResolverContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._LabelConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNLabelEdge2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelEdge(ctx context.Context, sel ast.SelectionSet, v models.LabelEdge) graphql.Marshaler { + return ec._LabelEdge(ctx, sel, &v) +} + +func (ec *executionContext) marshalNLabelEdge2ᚕᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelEdge(ctx context.Context, sel ast.SelectionSet, v []*models.LabelEdge) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + rctx := &graphql.ResolverContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithResolverContext(ctx, rctx) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNLabelEdge2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelEdge(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalNLabelEdge2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelEdge(ctx context.Context, sel ast.SelectionSet, v *models.LabelEdge) graphql.Marshaler { + if v == nil { + if !ec.HasError(graphql.GetResolverContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._LabelEdge(ctx, sel, v) +} + func (ec *executionContext) unmarshalNNewBugInput2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐNewBugInput(ctx context.Context, v interface{}) (models.NewBugInput, error) { return ec.unmarshalInputNewBugInput(ctx, v) } diff --git a/graphql/models/edges.go b/graphql/models/edges.go index 4bf10fd3..6a331e3e 100644 --- a/graphql/models/edges.go +++ b/graphql/models/edges.go @@ -24,3 +24,8 @@ func (e TimelineItemEdge) GetCursor() string { func (e IdentityEdge) GetCursor() string { return e.Cursor } + +// GetCursor return the cursor entry of an edge +func (e LabelEdge) GetCursor() string { + return e.Cursor +} diff --git a/graphql/models/gen_models.go b/graphql/models/gen_models.go index 3c142e24..5498960b 100644 --- a/graphql/models/gen_models.go +++ b/graphql/models/gen_models.go @@ -156,6 +156,18 @@ type IdentityEdge struct { Node identity.Interface `json:"node"` } +type LabelConnection struct { + Edges []*LabelEdge `json:"edges"` + Nodes []bug.Label `json:"nodes"` + PageInfo *PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` +} + +type LabelEdge struct { + Cursor string `json:"cursor"` + Node bug.Label `json:"node"` +} + type NewBugInput struct { // A unique identifier for the client performing the mutation. ClientMutationID *string `json:"clientMutationId"` diff --git a/graphql/resolvers/repo.go b/graphql/resolvers/repo.go index ac9c162f..5a37ae18 100644 --- a/graphql/resolvers/repo.go +++ b/graphql/resolvers/repo.go @@ -159,6 +159,29 @@ func (repoResolver) UserIdentity(ctx context.Context, obj *models.Repository) (i return i.Identity, nil } -func (repoResolver) ValidLabels(ctx context.Context, obj *models.Repository) ([]bug.Label, error) { - return obj.Repo.ValidLabels(), nil +func (resolver repoResolver) ValidLabels(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.LabelConnection, error) { + input := models.ConnectionInput{ + Before: before, + After: after, + First: first, + Last: last, + } + + edger := func(label bug.Label, offset int) connections.Edge { + return models.LabelEdge{ + Node: label, + Cursor: connections.OffsetToCursor(offset), + } + } + + conMaker := func(edges []*models.LabelEdge, nodes []bug.Label, info *models.PageInfo, totalCount int) (*models.LabelConnection, error) { + return &models.LabelConnection{ + Edges: edges, + Nodes: nodes, + PageInfo: info, + TotalCount: totalCount, + }, nil + } + + return connections.LabelCon(obj.Repo.ValidLabels(), edger, conMaker, input) } diff --git a/graphql/schema/label.graphql b/graphql/schema/label.graphql new file mode 100644 index 00000000..1205915c --- /dev/null +++ b/graphql/schema/label.graphql @@ -0,0 +1,19 @@ +"""Label for a bug.""" +type Label { + """The name of the label.""" + name: String! + """Color of the label.""" + color: Color! +} + +type LabelConnection { + edges: [LabelEdge!]! + nodes: [Label!]! + pageInfo: PageInfo! + totalCount: Int! +} + +type LabelEdge { + cursor: String! + node: Label! +} \ No newline at end of file diff --git a/graphql/schema/repository.graphql b/graphql/schema/repository.graphql index 0fb491e0..20a3cf0b 100644 --- a/graphql/schema/repository.graphql +++ b/graphql/schema/repository.graphql @@ -34,5 +34,14 @@ type Repository { userIdentity: Identity """List of valid labels.""" - validLabels: [Label!]! + validLabels( + """Returns the elements in the list that come after the specified cursor.""" + after: String + """Returns the elements in the list that come before the specified cursor.""" + before: String + """Returns the first _n_ elements from the list.""" + first: Int + """Returns the last _n_ elements from the list.""" + last: Int + ): LabelConnection! } \ No newline at end of file diff --git a/graphql/schema/types.graphql b/graphql/schema/types.graphql index fb94d1e8..0182885e 100644 --- a/graphql/schema/types.graphql +++ b/graphql/schema/types.graphql @@ -11,14 +11,6 @@ type Color { B: Int! } -"""Label for a bug.""" -type Label { - """The name of the label.""" - name: String! - """Color of the label.""" - color: Color! -} - """Information about pagination in a connection.""" type PageInfo { """When paginating forwards, are there more items?"""