diff options
author | Michael Muré <batolettre@gmail.com> | 2018-07-29 18:11:33 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2018-07-29 18:51:56 +0200 |
commit | 6363518c85cbd8247a5f6507b8a1dd3903cfb71d (patch) | |
tree | aa51652e9881196b3637247988cbd5155f42b5e2 /graphql2 | |
parent | ff2fd14e3f10a7206d4ec86f07e524cfa290e0fc (diff) | |
download | git-bug-6363518c85cbd8247a5f6507b8a1dd3903cfb71d.tar.gz |
relay connection working with gqlgen
Diffstat (limited to 'graphql2')
-rw-r--r-- | graphql2/gqlgen.yml | 11 | ||||
-rw-r--r-- | graphql2/handler.go | 18 | ||||
-rw-r--r-- | graphql2/relay.go | 39 | ||||
-rw-r--r-- | graphql2/resolvers.go | 82 | ||||
-rw-r--r-- | graphql2/resolvers/bug.go | 61 | ||||
-rw-r--r-- | graphql2/resolvers/generated_graph.go (renamed from graphql2/gen/graph.go) | 946 | ||||
-rw-r--r-- | graphql2/resolvers/generated_model.go (renamed from graphql2/gen/model.go) | 40 | ||||
-rw-r--r-- | graphql2/resolvers/operations.go | 54 | ||||
-rw-r--r-- | graphql2/resolvers/pager_bug.go | 225 | ||||
-rw-r--r-- | graphql2/resolvers/pager_comment.go | 225 | ||||
-rw-r--r-- | graphql2/resolvers/pager_operation.go | 225 | ||||
-rw-r--r-- | graphql2/resolvers/pagers.go | 51 | ||||
-rw-r--r-- | graphql2/resolvers/pagers_template.go | 224 | ||||
-rw-r--r-- | graphql2/resolvers/query.go | 36 | ||||
-rw-r--r-- | graphql2/resolvers/repo.go | 26 | ||||
-rw-r--r-- | graphql2/resolvers/root.go | 53 | ||||
-rw-r--r-- | graphql2/schema.graphql | 120 |
17 files changed, 1629 insertions, 807 deletions
diff --git a/graphql2/gqlgen.yml b/graphql2/gqlgen.yml index 60ea0c49..d7c096bf 100644 --- a/graphql2/gqlgen.yml +++ b/graphql2/gqlgen.yml @@ -1,10 +1,17 @@ schema: schema.graphql exec: - filename: gen/graph.go + filename: resolvers/generated_graph.go model: - filename: gen/model.go + filename: resolvers/generated_model.go models: + Repository: + fields: + bug: + resolver: true + allBugs: + resolver: true +# model: github.com/MichaelMure/git-bug/graphql2/resolvers.repoResolver Bug: model: github.com/MichaelMure/git-bug/bug.Snapshot Comment: diff --git a/graphql2/handler.go b/graphql2/handler.go new file mode 100644 index 00000000..2bf6df8c --- /dev/null +++ b/graphql2/handler.go @@ -0,0 +1,18 @@ +//go:generate gorunpkg github.com/vektah/gqlgen + +package graphql2 + +import ( + "github.com/MichaelMure/git-bug/graphql2/resolvers" + "github.com/MichaelMure/git-bug/repository" + "github.com/vektah/gqlgen/handler" + "net/http" +) + +func NewHandler(repo repository.Repo) http.Handler { + backend := resolvers.NewRootResolver() + + backend.RegisterDefaultRepository(repo) + + return handler.GraphQL(resolvers.NewExecutableSchema(backend)) +} diff --git a/graphql2/relay.go b/graphql2/relay.go new file mode 100644 index 00000000..b037f28b --- /dev/null +++ b/graphql2/relay.go @@ -0,0 +1,39 @@ +package graphql2 + +import ( + "encoding/base64" + "strings" +) + + +type ResolvedGlobalID struct { + Type string `json:"type"` + ID string `json:"id"` +} + +// Takes a type name and an ID specific to that type name, and returns a +// "global ID" that is unique among all types. +func ToGlobalID(ttype string, id string) string { + str := ttype + ":" + id + encStr := base64.StdEncoding.EncodeToString([]byte(str)) + return encStr +} + +// Takes the "global ID" created by toGlobalID, and returns the type name and ID +// used to create it. +func FromGlobalID(globalID string) *ResolvedGlobalID { + strID := "" + b, err := base64.StdEncoding.DecodeString(globalID) + if err == nil { + strID = string(b) + } + tokens := strings.Split(strID, ":") + if len(tokens) < 2 { + return nil + } + return &ResolvedGlobalID{ + Type: tokens[0], + ID: tokens[1], + } +} + diff --git a/graphql2/resolvers.go b/graphql2/resolvers.go deleted file mode 100644 index fa47f222..00000000 --- a/graphql2/resolvers.go +++ /dev/null @@ -1,82 +0,0 @@ -package graphql2 - -import ( - "context" - "fmt" - "github.com/MichaelMure/git-bug/bug" - "github.com/MichaelMure/git-bug/bug/operations" - "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/graphql2/gen" - "time" -) - -type Backend struct { - cache cache.RootCache -} - -func (*Backend) Bug_labels(ctx context.Context, obj *bug.Snapshot) ([]*bug.Label, error) { - return obj.Labels -} - -func (*Backend) LabelChangeOperation_added(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) { - panic("implement me") -} - -func (*Backend) LabelChangeOperation_removed(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) { - panic("implement me") -} - -func (*Backend) AddCommentOperation_date(ctx context.Context, obj *operations.AddCommentOperation) (time.Time, error) { - return obj.Time(), nil -} - -func (*Backend) Bug_status(ctx context.Context, obj *bug.Snapshot) (gen.Status, error) { - return convertStatus(obj.Status) -} - -func (*Backend) Bug_comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (gen.CommentConnection, error) { - panic("implement me") -} - -func (*Backend) Bug_operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (gen.OperationConnection, error) { - panic("implement me") -} - -func (*Backend) CreateOperation_date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error) { - return obj.Time(), nil -} - -func (*Backend) LabelChangeOperation_date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error) { - return obj.Time(), nil -} - -func (*Backend) RootQuery_allBugs(ctx context.Context, after *string, before *string, first *int, last *int, query *string) (gen.BugConnection, error) { - panic("implement me") -} - -func (*Backend) RootQuery_bug(ctx context.Context, id string) (*bug.Snapshot, error) { - panic("implement me") -} - -func (*Backend) SetStatusOperation_date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error) { - return obj.Time(), nil -} - -func (*Backend) SetStatusOperation_status(ctx context.Context, obj *operations.SetStatusOperation) (gen.Status, error) { - return convertStatus(obj.Status) -} - -func (*Backend) SetTitleOperation_date(ctx context.Context, obj *operations.SetTitleOperation) (time.Time, error) { - return obj.Time(), nil -} - -func convertStatus(status bug.Status) (gen.Status, error) { - switch status { - case bug.OpenStatus: - return gen.StatusOpen, nil - case bug.ClosedStatus: - return gen.StatusClosed, nil - } - - return "", fmt.Errorf("Unknown status") -} diff --git a/graphql2/resolvers/bug.go b/graphql2/resolvers/bug.go new file mode 100644 index 00000000..ad6c288b --- /dev/null +++ b/graphql2/resolvers/bug.go @@ -0,0 +1,61 @@ +package resolvers + +import ( + "context" + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/cache" +) + +type bugResolver struct { + cache cache.Cacher +} + +func (bugResolver) Status(ctx context.Context, obj *bug.Snapshot) (Status, error) { + return convertStatus(obj.Status) +} + +func (bugResolver) Comments(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (CommentConnection, error) { + var connection CommentConnection + + edger := func(comment bug.Comment, offset int) Edge { + return CommentEdge{ + Node: comment, + Cursor: offsetToCursor(offset), + } + } + + edges, pageInfo, err := BugCommentPaginate(obj.Comments, edger, input) + + if err != nil { + return connection, err + } + + connection.Edges = edges + connection.PageInfo = pageInfo + connection.TotalCount = len(obj.Comments) + + return connection, nil +} + +func (bugResolver) Operations(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (OperationConnection, error) { + var connection OperationConnection + + edger := func(op bug.Operation, offset int) Edge { + return OperationEdge{ + Node: op.(OperationUnion), + Cursor: offsetToCursor(offset), + } + } + + edges, pageInfo, err := BugOperationPaginate(obj.Operations, edger, input) + + if err != nil { + return connection, err + } + + connection.Edges = edges + connection.PageInfo = pageInfo + connection.TotalCount = len(obj.Operations) + + return connection, nil +} diff --git a/graphql2/gen/graph.go b/graphql2/resolvers/generated_graph.go index d5249dea..3d752ddc 100644 --- a/graphql2/gen/graph.go +++ b/graphql2/resolvers/generated_graph.go @@ -1,6 +1,6 @@ // Code generated by github.com/vektah/gqlgen, DO NOT EDIT. -package gen +package resolvers import ( "bytes" @@ -31,18 +31,19 @@ type Resolvers interface { AddCommentOperation_date(ctx context.Context, obj *operations.AddCommentOperation) (time.Time, error) Bug_status(ctx context.Context, obj *bug.Snapshot) (Status, error) - Bug_labels(ctx context.Context, obj *bug.Snapshot) ([]*bug.Label, error) - Bug_comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (CommentConnection, error) - Bug_operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (OperationConnection, error) + + Bug_comments(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (CommentConnection, error) + Bug_operations(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (OperationConnection, error) CreateOperation_date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error) LabelChangeOperation_date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error) - LabelChangeOperation_added(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) - LabelChangeOperation_removed(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) - RootQuery_allBugs(ctx context.Context, after *string, before *string, first *int, last *int, query *string) (BugConnection, error) - RootQuery_bug(ctx context.Context, id string) (*bug.Snapshot, error) + Query_defaultRepository(ctx context.Context) (*repoResolver, error) + Query_repository(ctx context.Context, id string) (*repoResolver, error) + + Repository_allBugs(ctx context.Context, obj *repoResolver, input ConnectionInput) (BugConnection, error) + Repository_bug(ctx context.Context, obj *repoResolver, prefix string) (*bug.Snapshot, error) SetStatusOperation_date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error) SetStatusOperation_status(ctx context.Context, obj *operations.SetStatusOperation) (Status, error) @@ -55,7 +56,8 @@ type ResolverRoot interface { Bug() BugResolver CreateOperation() CreateOperationResolver LabelChangeOperation() LabelChangeOperationResolver - RootQuery() RootQueryResolver + Query() QueryResolver + Repository() RepositoryResolver SetStatusOperation() SetStatusOperationResolver SetTitleOperation() SetTitleOperationResolver } @@ -64,21 +66,23 @@ type AddCommentOperationResolver interface { } type BugResolver interface { Status(ctx context.Context, obj *bug.Snapshot) (Status, error) - Labels(ctx context.Context, obj *bug.Snapshot) ([]*bug.Label, error) - Comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (CommentConnection, error) - Operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (OperationConnection, error) + + Comments(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (CommentConnection, error) + Operations(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (OperationConnection, error) } type CreateOperationResolver interface { Date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error) } type LabelChangeOperationResolver interface { Date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error) - Added(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) - Removed(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) } -type RootQueryResolver interface { - AllBugs(ctx context.Context, after *string, before *string, first *int, last *int, query *string) (BugConnection, error) - Bug(ctx context.Context, id string) (*bug.Snapshot, error) +type QueryResolver interface { + DefaultRepository(ctx context.Context) (*repoResolver, error) + Repository(ctx context.Context, id string) (*repoResolver, error) +} +type RepositoryResolver interface { + AllBugs(ctx context.Context, obj *repoResolver, input ConnectionInput) (BugConnection, error) + Bug(ctx context.Context, obj *repoResolver, prefix string) (*bug.Snapshot, error) } type SetStatusOperationResolver interface { Date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error) @@ -100,16 +104,12 @@ func (s shortMapper) Bug_status(ctx context.Context, obj *bug.Snapshot) (Status, return s.r.Bug().Status(ctx, obj) } -func (s shortMapper) Bug_labels(ctx context.Context, obj *bug.Snapshot) ([]*bug.Label, error) { - return s.r.Bug().Labels(ctx, obj) +func (s shortMapper) Bug_comments(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (CommentConnection, error) { + return s.r.Bug().Comments(ctx, obj, input) } -func (s shortMapper) Bug_comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (CommentConnection, error) { - return s.r.Bug().Comments(ctx, obj, after, before, first, last, query) -} - -func (s shortMapper) Bug_operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int, query *string) (OperationConnection, error) { - return s.r.Bug().Operations(ctx, obj, after, before, first, last, query) +func (s shortMapper) Bug_operations(ctx context.Context, obj *bug.Snapshot, input ConnectionInput) (OperationConnection, error) { + return s.r.Bug().Operations(ctx, obj, input) } func (s shortMapper) CreateOperation_date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error) { @@ -120,20 +120,20 @@ func (s shortMapper) LabelChangeOperation_date(ctx context.Context, obj *operati return s.r.LabelChangeOperation().Date(ctx, obj) } -func (s shortMapper) LabelChangeOperation_added(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) { - return s.r.LabelChangeOperation().Added(ctx, obj) +func (s shortMapper) Query_defaultRepository(ctx context.Context) (*repoResolver, error) { + return s.r.Query().DefaultRepository(ctx) } -func (s shortMapper) LabelChangeOperation_removed(ctx context.Context, obj *operations.LabelChangeOperation) ([]*bug.Label, error) { - return s.r.LabelChangeOperation().Removed(ctx, obj) +func (s shortMapper) Query_repository(ctx context.Context, id string) (*repoResolver, error) { + return s.r.Query().Repository(ctx, id) } -func (s shortMapper) RootQuery_allBugs(ctx context.Context, after *string, before *string, first *int, last *int, query *string) (BugConnection, error) { - return s.r.RootQuery().AllBugs(ctx, after, before, first, last, query) +func (s shortMapper) Repository_allBugs(ctx context.Context, obj *repoResolver, input ConnectionInput) (BugConnection, error) { + return s.r.Repository().AllBugs(ctx, obj, input) } -func (s shortMapper) RootQuery_bug(ctx context.Context, id string) (*bug.Snapshot, error) { - return s.r.RootQuery().Bug(ctx, id) +func (s shortMapper) Repository_bug(ctx context.Context, obj *repoResolver, prefix string) (*bug.Snapshot, error) { + return s.r.Repository().Bug(ctx, obj, prefix) } func (s shortMapper) SetStatusOperation_date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error) { @@ -160,7 +160,7 @@ func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *grap ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { - data := ec._RootQuery(ctx, op.Selections) + data := ec._Query(ctx, op.Selections) var buf bytes.Buffer data.MarshalGQL(&buf) return buf.Bytes() @@ -265,7 +265,7 @@ func (ec *executionContext) _AddCommentOperation_message(ctx context.Context, fi return graphql.MarshalString(res) } -var bugImplementors = []string{"Bug", "Authored", "Commentable"} +var bugImplementors = []string{"Bug"} // nolint: gocyclo, errcheck, gas, goconst func (ec *executionContext) _Bug(ctx context.Context, sel []query.Selection, obj *bug.Snapshot) graphql.Marshaler { @@ -364,124 +364,37 @@ func (ec *executionContext) _Bug_status(ctx context.Context, field graphql.Colle } func (ec *executionContext) _Bug_labels(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler { - ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Object: "Bug", - Args: nil, - Field: field, - }) - return graphql.Defer(func() (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - userErr := ec.Recover(ctx, r) - ec.Error(ctx, userErr) - ret = graphql.Null - } - }() - - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Bug_labels(ctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]*bug.Label) - arr1 := graphql.Array{} - for idx1 := range res { - arr1 = append(arr1, func() graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.PushIndex(idx1) - defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return *res[idx1] - }()) - } - return arr1 - }) + rctx := graphql.GetResolverContext(ctx) + rctx.Object = "Bug" + rctx.Args = nil + rctx.Field = field + rctx.PushField(field.Alias) + defer rctx.Pop() + res := obj.Labels + arr1 := graphql.Array{} + for idx1 := range res { + arr1 = append(arr1, func() graphql.Marshaler { + rctx := graphql.GetResolverContext(ctx) + rctx.PushIndex(idx1) + defer rctx.Pop() + return res[idx1] + }()) + } + return arr1 } func (ec *executionContext) _Bug_comments(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler { args := map[string]interface{}{} - var arg0 *string - if tmp, ok := field.Args["after"]; ok { + var arg0 ConnectionInput + if tmp, ok := field.Args["input"]; ok { var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg0 = &ptr1 - } - + arg0, err = UnmarshalConnectionInput(tmp) if err != nil { ec.Error(ctx, err) return graphql.Null } } - args["after"] = arg0 - var arg1 *string - if tmp, ok := field.Args["before"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg1 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["before"] = arg1 - var arg2 *int - if tmp, ok := field.Args["first"]; ok { - var err error - var ptr1 int - if tmp != nil { - ptr1, err = graphql.UnmarshalInt(tmp) - arg2 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["first"] = arg2 - var arg3 *int - if tmp, ok := field.Args["last"]; ok { - var err error - var ptr1 int - if tmp != nil { - ptr1, err = graphql.UnmarshalInt(tmp) - arg3 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["last"] = arg3 - var arg4 *string - if tmp, ok := field.Args["query"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg4 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["query"] = arg4 + args["input"] = arg0 ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ Object: "Bug", Args: args, @@ -497,7 +410,7 @@ func (ec *executionContext) _Bug_comments(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Bug_comments(ctx, obj, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int), args["query"].(*string)) + return ec.resolvers.Bug_comments(ctx, obj, args["input"].(ConnectionInput)) }) if err != nil { ec.Error(ctx, err) @@ -513,81 +426,16 @@ func (ec *executionContext) _Bug_comments(ctx context.Context, field graphql.Col func (ec *executionContext) _Bug_operations(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler { args := map[string]interface{}{} - var arg0 *string - if tmp, ok := field.Args["after"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg0 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["after"] = arg0 - var arg1 *string - if tmp, ok := field.Args["before"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg1 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["before"] = arg1 - var arg2 *int - if tmp, ok := field.Args["first"]; ok { - var err error - var ptr1 int - if tmp != nil { - ptr1, err = graphql.UnmarshalInt(tmp) - arg2 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["first"] = arg2 - var arg3 *int - if tmp, ok := field.Args["last"]; ok { - var err error - var ptr1 int - if tmp != nil { - ptr1, err = graphql.UnmarshalInt(tmp) - arg3 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["last"] = arg3 - var arg4 *string - if tmp, ok := field.Args["query"]; ok { + var arg0 ConnectionInput + if tmp, ok := field.Args["input"]; ok { var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg4 = &ptr1 - } - + arg0, err = UnmarshalConnectionInput(tmp) if err != nil { ec.Error(ctx, err) return graphql.Null } } - args["query"] = arg4 + args["input"] = arg0 ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ Object: "Bug", Args: args, @@ -603,7 +451,7 @@ func (ec *executionContext) _Bug_operations(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Bug_operations(ctx, obj, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int), args["query"].(*string)) + return ec.resolvers.Bug_operations(ctx, obj, args["input"].(ConnectionInput)) }) if err != nil { ec.Error(ctx, err) @@ -632,8 +480,6 @@ func (ec *executionContext) _BugConnection(ctx context.Context, sel []query.Sele out.Values[i] = graphql.MarshalString("BugConnection") case "edges": out.Values[i] = ec._BugConnection_edges(ctx, field, obj) - case "nodes": - out.Values[i] = ec._BugConnection_nodes(ctx, field, obj) case "pageInfo": out.Values[i] = ec._BugConnection_pageInfo(ctx, field, obj) case "totalCount": @@ -669,29 +515,6 @@ func (ec *executionContext) _BugConnection_edges(ctx context.Context, field grap return arr1 } -func (ec *executionContext) _BugConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *BugConnection) graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.Object = "BugConnection" - rctx.Args = nil - rctx.Field = field - rctx.PushField(field.Alias) - defer rctx.Pop() - res := obj.Nodes - arr1 := graphql.Array{} - for idx1 := range res { - arr1 = append(arr1, func() graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.PushIndex(idx1) - defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return ec._Bug(ctx, field.Selections, res[idx1]) - }()) - } - return arr1 -} - func (ec *executionContext) _BugConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *BugConnection) graphql.Marshaler { rctx := graphql.GetResolverContext(ctx) rctx.Object = "BugConnection" @@ -758,10 +581,7 @@ func (ec *executionContext) _BugEdge_node(ctx context.Context, field graphql.Col rctx.PushField(field.Alias) defer rctx.Pop() res := obj.Node - if res == nil { - return graphql.Null - } - return ec._Bug(ctx, field.Selections, res) + return ec._Bug(ctx, field.Selections, &res) } var commentImplementors = []string{"Comment", "Authored"} @@ -826,8 +646,6 @@ func (ec *executionContext) _CommentConnection(ctx context.Context, sel []query. out.Values[i] = graphql.MarshalString("CommentConnection") case "edges": out.Values[i] = ec._CommentConnection_edges(ctx, field, obj) - case "nodes": - out.Values[i] = ec._CommentConnection_nodes(ctx, field, obj) case "pageInfo": out.Values[i] = ec._CommentConnection_pageInfo(ctx, field, obj) case "totalCount": @@ -854,33 +672,7 @@ func (ec *executionContext) _CommentConnection_edges(ctx context.Context, field rctx := graphql.GetResolverContext(ctx) rctx.PushIndex(idx1) defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return ec._CommentEdge(ctx, field.Selections, res[idx1]) - }()) - } - return arr1 -} - -func (ec *executionContext) _CommentConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *CommentConnection) graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.Object = "CommentConnection" - rctx.Args = nil - rctx.Field = field - rctx.PushField(field.Alias) - defer rctx.Pop() - res := obj.Nodes - arr1 := graphql.Array{} - for idx1 := range res { - arr1 = append(arr1, func() graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.PushIndex(idx1) - defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return ec._Comment(ctx, field.Selections, res[idx1]) + return ec._CommentEdge(ctx, field.Selections, &res[idx1]) }()) } return arr1 @@ -1118,87 +910,43 @@ func (ec *executionContext) _LabelChangeOperation_date(ctx context.Context, fiel } func (ec *executionContext) _LabelChangeOperation_added(ctx context.Context, field graphql.CollectedField, obj *operations.LabelChangeOperation) graphql.Marshaler { - ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Object: "LabelChangeOperation", - Args: nil, - Field: field, - }) - return graphql.Defer(func() (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - userErr := ec.Recover(ctx, r) - ec.Error(ctx, userErr) - ret = graphql.Null - } - }() - - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.LabelChangeOperation_added(ctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]*bug.Label) - arr1 := graphql.Array{} - for idx1 := range res { - arr1 = append(arr1, func() graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.PushIndex(idx1) - defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return *res[idx1] - }()) - } - return arr1 - }) + rctx := graphql.GetResolverContext(ctx) + rctx.Object = "LabelChangeOperation" + rctx.Args = nil + rctx.Field = field + rctx.PushField(field.Alias) + defer rctx.Pop() + res := obj.Added + arr1 := graphql.Array{} + for idx1 := range res { + arr1 = append(arr1, func() graphql.Marshaler { + rctx := graphql.GetResolverContext(ctx) + rctx.PushIndex(idx1) + defer rctx.Pop() + return res[idx1] + }()) + } + return arr1 } func (ec *executionContext) _LabelChangeOperation_removed(ctx context.Context, field graphql.CollectedField, obj *operations.LabelChangeOperation) graphql.Marshaler { - ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Object: "LabelChangeOperation", - Args: nil, - Field: field, - }) - return graphql.Defer(func() (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - userErr := ec.Recover(ctx, r) - ec.Error(ctx, userErr) - ret = graphql.Null - } - }() - - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.LabelChangeOperation_removed(ctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]*bug.Label) - arr1 := graphql.Array{} - for idx1 := range res { - arr1 = append(arr1, func() graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.PushIndex(idx1) - defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return *res[idx1] - }()) - } - return arr1 - }) + rctx := graphql.GetResolverContext(ctx) + rctx.Object = "LabelChangeOperation" + rctx.Args = nil + rctx.Field = field + rctx.PushField(field.Alias) + defer rctx.Pop() + res := obj.Removed + arr1 := graphql.Array{} + for idx1 := range res { + arr1 = append(arr1, func() graphql.Marshaler { + rctx := graphql.GetResolverContext(ctx) + rctx.PushIndex(idx1) + defer rctx.Pop() + return res[idx1] + }()) + } + return arr1 } var operationConnectionImplementors = []string{"OperationConnection"} @@ -1216,8 +964,6 @@ func (ec *executionContext) _OperationConnection(ctx context.Context, sel []quer out.Values[i] = graphql.MarshalString("OperationConnection") case "edges": out.Values[i] = ec._OperationConnection_edges(ctx, field, obj) - case "nodes": - out.Values[i] = ec._OperationConnection_nodes(ctx, field, obj) case "pageInfo": out.Values[i] = ec._OperationConnection_pageInfo(ctx, field, obj) case "totalCount": @@ -1244,33 +990,7 @@ func (ec *executionContext) _OperationConnection_edges(ctx context.Context, fiel rctx := graphql.GetResolverContext(ctx) rctx.PushIndex(idx1) defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return ec._OperationEdge(ctx, field.Selections, res[idx1]) - }()) - } - return arr1 -} - -func (ec *executionContext) _OperationConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *OperationConnection) graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.Object = "OperationConnection" - rctx.Args = nil - rctx.Field = field - rctx.PushField(field.Alias) - defer rctx.Pop() - res := obj.Nodes - arr1 := graphql.Array{} - for idx1 := range res { - arr1 = append(arr1, func() graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.PushIndex(idx1) - defer rctx.Pop() - if res[idx1] == nil { - return graphql.Null - } - return ec._OperationUnion(ctx, field.Selections, res[idx1]) + return ec._OperationEdge(ctx, field.Selections, &res[idx1]) }()) } return arr1 @@ -1362,10 +1082,6 @@ func (ec *executionContext) _PageInfo(ctx context.Context, sel []query.Selection out.Values[i] = ec._PageInfo_hasNextPage(ctx, field, obj) case "hasPreviousPage": out.Values[i] = ec._PageInfo_hasPreviousPage(ctx, field, obj) - case "startCursor": - out.Values[i] = ec._PageInfo_startCursor(ctx, field, obj) - case "endCursor": - out.Values[i] = ec._PageInfo_endCursor(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -1396,34 +1112,6 @@ func (ec *executionContext) _PageInfo_hasPreviousPage(ctx context.Context, field return graphql.MarshalBoolean(res) } -func (ec *executionContext) _PageInfo_startCursor(ctx context.Context, field graphql.CollectedField, obj *PageInfo) graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.Object = "PageInfo" - rctx.Args = nil - rctx.Field = field - rctx.PushField(field.Alias) - defer rctx.Pop() - res := obj.StartCursor - if res == nil { - return graphql.Null - } - return graphql.MarshalString(*res) -} - -func (ec *executionContext) _PageInfo_endCursor(ctx context.Context, field graphql.CollectedField, obj *PageInfo) graphql.Marshaler { - rctx := graphql.GetResolverContext(ctx) - rctx.Object = "PageInfo" - rctx.Args = nil - rctx.Field = field - rctx.PushField(field.Alias) - defer rctx.Pop() - res := obj.EndCursor - if res == nil { - return graphql.Null - } - return graphql.MarshalString(*res) -} - var personImplementors = []string{"Person"} // nolint: gocyclo, errcheck, gas, goconst @@ -1471,14 +1159,14 @@ func (ec *executionContext) _Person_name(ctx context.Context, field graphql.Coll return graphql.MarshalString(res) } -var rootQueryImplementors = []string{"RootQuery"} +var queryImplementors = []string{"Query"} // nolint: gocyclo, errcheck, gas, goconst -func (ec *executionContext) _RootQuery(ctx context.Context, sel []query.Selection) graphql.Marshaler { - fields := graphql.CollectFields(ec.Doc, sel, rootQueryImplementors, ec.Variables) +func (ec *executionContext) _Query(ctx context.Context, sel []query.Selection) graphql.Marshaler { + fields := graphql.CollectFields(ec.Doc, sel, queryImplementors, ec.Variables) ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Object: "RootQuery", + Object: "Query", }) out := graphql.NewOrderedMap(len(fields)) @@ -1487,15 +1175,15 @@ func (ec *executionContext) _RootQuery(ctx context.Context, sel []query.Selectio switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("RootQuery") - case "allBugs": - out.Values[i] = ec._RootQuery_allBugs(ctx, field) - case "bug": - out.Values[i] = ec._RootQuery_bug(ctx, field) + out.Values[i] = graphql.MarshalString("Query") + case "defaultRepository": + out.Values[i] = ec._Query_defaultRepository(ctx, field) + case "repository": + out.Values[i] = ec._Query_repository(ctx, field) case "__schema": - out.Values[i] = ec._RootQuery___schema(ctx, field) + out.Values[i] = ec._Query___schema(ctx, field) case "__type": - out.Values[i] = ec._RootQuery___type(ctx, field) + out.Values[i] = ec._Query___type(ctx, field) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -1504,86 +1192,10 @@ func (ec *executionContext) _RootQuery(ctx context.Context, sel []query.Selectio return out } -func (ec *executionContext) _RootQuery_allBugs(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { - args := map[string]interface{}{} - var arg0 *string - if tmp, ok := field.Args["after"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg0 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["after"] = arg0 - var arg1 *string - if tmp, ok := field.Args["before"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg1 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["before"] = arg1 - var arg2 *int - if tmp, ok := field.Args["first"]; ok { - var err error - var ptr1 int - if tmp != nil { - ptr1, err = graphql.UnmarshalInt(tmp) - arg2 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["first"] = arg2 - var arg3 *int - if tmp, ok := field.Args["last"]; ok { - var err error - var ptr1 int - if tmp != nil { - ptr1, err = graphql.UnmarshalInt(tmp) - arg3 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["last"] = arg3 - var arg4 *string - if tmp, ok := field.Args["query"]; ok { - var err error - var ptr1 string - if tmp != nil { - ptr1, err = graphql.UnmarshalString(tmp) - arg4 = &ptr1 - } - - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - } - args["query"] = arg4 +func (ec *executionContext) _Query_defaultRepository(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Object: "RootQuery", - Args: args, + Object: "Query", + Args: nil, Field: field, }) return graphql.Defer(func() (ret graphql.Marshaler) { @@ -1596,7 +1208,7 @@ func (ec *executionContext) _RootQuery_allBugs(ctx context.Context, field graphq }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.RootQuery_allBugs(ctx, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int), args["query"].(*string)) + return ec.resolvers.Query_defaultRepository(ctx) }) if err != nil { ec.Error(ctx, err) @@ -1605,12 +1217,15 @@ func (ec *executionContext) _RootQuery_allBugs(ctx context.Context, field graphq if resTmp == nil { return graphql.Null } - res := resTmp.(BugConnection) - return ec._BugConnection(ctx, field.Selections, &res) + res := resTmp.(*repoResolver) + if res == nil { + return graphql.Null + } + return ec._Repository(ctx, field.Selections, res) }) } -func (ec *executionContext) _RootQuery_bug(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { +func (ec *executionContext) _Query_repository(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { args := map[string]interface{}{} var arg0 string if tmp, ok := field.Args["id"]; ok { @@ -1623,7 +1238,7 @@ func (ec *executionContext) _RootQuery_bug(ctx context.Context, field graphql.Co } args["id"] = arg0 ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Object: "RootQuery", + Object: "Query", Args: args, Field: field, }) @@ -1637,7 +1252,7 @@ func (ec *executionContext) _RootQuery_bug(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.RootQuery_bug(ctx, args["id"].(string)) + return ec.resolvers.Query_repository(ctx, args["id"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1646,17 +1261,17 @@ func (ec *executionContext) _RootQuery_bug(ctx context.Context, field graphql.Co if resTmp == nil { return graphql.Null } - res := resTmp.(*bug.Snapshot) + res := resTmp.(*repoResolver) if res == nil { return graphql.Null } - return ec._Bug(ctx, field.Selections, res) + return ec._Repository(ctx, field.Selections, res) }) } -func (ec *executionContext) _RootQuery___schema(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { rctx := graphql.GetResolverContext(ctx) - rctx.Object = "RootQuery" + rctx.Object = "Query" rctx.Args = nil rctx.Field = field rctx.PushField(field.Alias) @@ -1668,7 +1283,7 @@ func (ec *executionContext) _RootQuery___schema(ctx context.Context, field graph return ec.___Schema(ctx, field.Selections, res) } -func (ec *executionContext) _RootQuery___type(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { args := map[string]interface{}{} var arg0 string if tmp, ok := field.Args["name"]; ok { @@ -1681,7 +1296,7 @@ func (ec *executionContext) _RootQuery___type(ctx context.Context, field graphql } args["name"] = arg0 rctx := graphql.GetResolverContext(ctx) - rctx.Object = "RootQuery" + rctx.Object = "Query" rctx.Args = args rctx.Field = field rctx.PushField(field.Alias) @@ -1693,6 +1308,116 @@ func (ec *executionContext) _RootQuery___type(ctx context.Context, field graphql return ec.___Type(ctx, field.Selections, res) } +var repositoryImplementors = []string{"Repository"} + +// nolint: gocyclo, errcheck, gas, goconst +func (ec *executionContext) _Repository(ctx context.Context, sel []query.Selection, obj *repoResolver) graphql.Marshaler { + fields := graphql.CollectFields(ec.Doc, sel, repositoryImplementors, ec.Variables) + + out := graphql.NewOrderedMap(len(fields)) + for i, field := range fields { + out.Keys[i] = field.Alias + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Repository") + case "allBugs": + out.Values[i] = ec._Repository_allBugs(ctx, field, obj) + case "bug": + out.Values[i] = ec._Repository_bug(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + + return out +} + +func (ec *executionContext) _Repository_allBugs(ctx context.Context, field graphql.CollectedField, obj *repoResolver) graphql.Marshaler { + args := map[string]interface{}{} + var arg0 ConnectionInput + if tmp, ok := field.Args["input"]; ok { + var err error + arg0, err = UnmarshalConnectionInput(tmp) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + } + args["input"] = arg0 + ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ + Object: "Repository", + Args: args, + Field: field, + }) + return graphql.Defer(func() (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + userErr := ec.Recover(ctx, r) + ec.Error(ctx, userErr) + ret = graphql.Null + } + }() + + resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { + return ec.resolvers.Repository_allBugs(ctx, obj, args["input"].(ConnectionInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(BugConnection) + return ec._BugConnection(ctx, field.Selections, &res) + }) +} + +func (ec *executionContext) _Repository_bug(ctx context.Context, field graphql.CollectedField, obj *repoResolver) graphql.Marshaler { + args := map[string]interface{}{} + var arg0 string + if tmp, ok := field.Args["prefix"]; ok { + var err error + arg0, err = graphql.UnmarshalString(tmp) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + } + args["prefix"] = arg0 + ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ + Object: "Repository", + Args: args, + Field: field, + }) + return graphql.Defer(func() (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + userErr := ec.Recover(ctx, r) + ec.Error(ctx, userErr) + ret = graphql.Null + } + }() + + resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { + return ec.resolvers.Repository_bug(ctx, obj, args["prefix"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bug.Snapshot) + if res == nil { + return graphql.Null + } + return ec._Bug(ctx, field.Selections, res) + }) +} + var setStatusOperationImplementors = []string{"SetStatusOperation", "Operation", "Authored"} // nolint: gocyclo, errcheck, gas, goconst @@ -2588,23 +2313,6 @@ func (ec *executionContext) _Authored(ctx context.Context, sel []query.Selection return ec._LabelChangeOperation(ctx, sel, &obj) case *operations.LabelChangeOperation: return ec._LabelChangeOperation(ctx, sel, obj) - case bug.Snapshot: - return ec._Bug(ctx, sel, &obj) - case *bug.Snapshot: - return ec._Bug(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) _Commentable(ctx context.Context, sel []query.Selection, obj *Commentable) graphql.Marshaler { - switch obj := (*obj).(type) { - case nil: - return graphql.Null - case bug.Snapshot: - return ec._Bug(ctx, sel, &obj) - case *bug.Snapshot: - return ec._Bug(ctx, sel, obj) default: panic(fmt.Errorf("unexpected type %T", obj)) } @@ -2668,6 +2376,62 @@ func (ec *executionContext) _OperationUnion(ctx context.Context, sel []query.Sel } } +func UnmarshalConnectionInput(v interface{}) (ConnectionInput, error) { + var it ConnectionInput + var asMap = v.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "after": + var err error + var ptr1 string + if v != nil { + ptr1, err = graphql.UnmarshalString(v) + it.After = &ptr1 + } + + if err != nil { + return it, err + } + case "before": + var err error + var ptr1 string + if v != nil { + ptr1, err = graphql.UnmarshalString(v) + it.Before = &ptr1 + } + + if err != nil { + return it, err + } + case "first": + var err error + var ptr1 int + if v != nil { + ptr1, err = graphql.UnmarshalInt(v) + it.First = &ptr1 + } + + if err != nil { + return it, err + } + case "last": + var err error + var ptr1 int + if v != nil { + ptr1, err = graphql.UnmarshalInt(v) + it.Last = &ptr1 + } + + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) } @@ -2680,11 +2444,7 @@ func (ec *executionContext) introspectType(name string) *introspection.Type { return introspection.WrapType(t) } -var parsedSchema = schema.MustParse(`schema { - query: RootQuery -} - -scalar Time +var parsedSchema = schema.MustParse(`scalar Time scalar Label # Information about pagination in a connection. @@ -2696,10 +2456,24 @@ type PageInfo { hasPreviousPage: Boolean! # When paginating backwards, the cursor to continue. - startCursor: String +# startCursor: String # When paginating forwards, the cursor to continue. - endCursor: String +# endCursor: String +} + +input ConnectionInput { + # 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 } # Represents an person in a git object. @@ -2713,8 +2487,7 @@ type Person { type CommentConnection { - edges: [CommentEdge] - nodes: [Comment] + edges: [CommentEdge!]! pageInfo: PageInfo! totalCount: Int! } @@ -2724,23 +2497,6 @@ type CommentEdge { node: Comment! } -interface Commentable { - # A list of comments associated with the object. - comments( - # 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 - ): CommentConnection! -} - # Represents a comment on a bug. type Comment implements Authored { # The author of this comment. @@ -2762,15 +2518,14 @@ interface Authored { } type OperationConnection { - edges: [OperationEdge]! - nodes: [OperationUnion]! + edges: [OperationEdge!]! pageInfo: PageInfo! totalCount: Int! } type OperationEdge { cursor: String! - node: OperationUnion + node: OperationUnion! } # An operation applied to a bug. @@ -2815,8 +2570,8 @@ type LabelChangeOperation implements Operation, Authored { author: Person! date: Time! - added: [Label]! - removed: [Label]! + added: [Label!]! + removed: [Label!]! } union OperationUnion = @@ -2826,14 +2581,11 @@ union OperationUnion = | SetStatusOperation | LabelChangeOperation -# The connection type for Label. +# The connection type for Bug. type BugConnection { # A list of edges. edges: [BugEdge]! - # A list of nodes. - nodes: [Bug]! - # Information to aid in pagination. pageInfo: PageInfo! @@ -2847,70 +2599,30 @@ type BugEdge { cursor: String! # The item at the end of the edge. - node: Bug + node: Bug! } -type Bug implements Authored, Commentable { +type Bug { id: String! humanId: String! title: String! status: Status! # A list of labels associated with the repository. - labels: [Label]! - - comments( - # 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 - - # If provided, searches comments by name and description. - query: String - ): CommentConnection! + labels: [Label!]! - operations( - # Returns the elements in the list that come after the specified cursor. - after: String + comments(input: ConnectionInput!): CommentConnection! - # 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 - - # If provided, searches operations by name and description. - query: String - ): OperationConnection! + operations(input: ConnectionInput!): OperationConnection! } -type RootQuery { - allBugs( - # 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 +type Repository { + allBugs(input: ConnectionInput!): BugConnection! + bug(prefix: String!): Bug +} - # If provided, searches labels by name and description. - query: String - ): BugConnection! - bug(id: String!): Bug +type Query { + defaultRepository: Repository + repository(id: String!): Repository } `) diff --git a/graphql2/gen/model.go b/graphql2/resolvers/generated_model.go index 7609180a..f6d78471 100644 --- a/graphql2/gen/model.go +++ b/graphql2/resolvers/generated_model.go @@ -1,6 +1,6 @@ // Code generated by github.com/vektah/gqlgen, DO NOT EDIT. -package gen +package resolvers import ( fmt "fmt" @@ -12,32 +12,34 @@ import ( type Authored interface{} type BugConnection struct { - Edges []*BugEdge `json:"edges"` - Nodes []*bug.Snapshot `json:"nodes"` - PageInfo PageInfo `json:"pageInfo"` - TotalCount int `json:"totalCount"` + Edges []*BugEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` } type BugEdge struct { - Cursor string `json:"cursor"` - Node *bug.Snapshot `json:"node"` + Cursor string `json:"cursor"` + Node bug.Snapshot `json:"node"` } type CommentConnection struct { - Edges []*CommentEdge `json:"edges"` - Nodes []*bug.Comment `json:"nodes"` - PageInfo PageInfo `json:"pageInfo"` - TotalCount int `json:"totalCount"` + Edges []CommentEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` } type CommentEdge struct { Cursor string `json:"cursor"` Node bug.Comment `json:"node"` } -type Commentable interface{} +type ConnectionInput struct { + After *string `json:"after"` + Before *string `json:"before"` + First *int `json:"first"` + Last *int `json:"last"` +} type Operation interface{} type OperationConnection struct { - Edges []*OperationEdge `json:"edges"` - Nodes []*OperationUnion `json:"nodes"` - PageInfo PageInfo `json:"pageInfo"` - TotalCount int `json:"totalCount"` + Edges []OperationEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` } type OperationEdge struct { Cursor string `json:"cursor"` @@ -45,10 +47,8 @@ type OperationEdge struct { } type OperationUnion interface{} type PageInfo struct { - HasNextPage bool `json:"hasNextPage"` - HasPreviousPage bool `json:"hasPreviousPage"` - StartCursor *string `json:"startCursor"` - EndCursor *string `json:"endCursor"` + HasNextPage bool `json:"hasNextPage"` + HasPreviousPage bool `json:"hasPreviousPage"` } type Status string diff --git a/graphql2/resolvers/operations.go b/graphql2/resolvers/operations.go new file mode 100644 index 00000000..1279a1b4 --- /dev/null +++ b/graphql2/resolvers/operations.go @@ -0,0 +1,54 @@ +package resolvers + +import ( + "context" + "fmt" + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/bug/operations" + "time" +) + +type addCommentOperationResolver struct{} + +func (addCommentOperationResolver) Date(ctx context.Context, obj *operations.AddCommentOperation) (time.Time, error) { + return obj.Time(), nil +} + +type createOperationResolver struct{} + +func (createOperationResolver) Date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error) { + return obj.Time(), nil +} + +type labelChangeOperation struct{} + +func (labelChangeOperation) Date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error) { + return obj.Time(), nil +} + +type setStatusOperationResolver struct{} + +func (setStatusOperationResolver) Date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error) { + return obj.Time(), nil +} + +func (setStatusOperationResolver) Status(ctx context.Context, obj *operations.SetStatusOperation) (Status, error) { + return convertStatus(obj.Status) +} + +type setTitleOperationResolver struct{} + +func (setTitleOperationResolver) Date(ctx context.Context, obj *operations.SetTitleOperation) (time.Time, error) { + return obj.Time(), nil +} + +func convertStatus(status bug.Status) (Status, error) { + switch status { + case bug.OpenStatus: + return StatusOpen, nil + case bug.ClosedStatus: + return StatusClosed, nil + } + + return "", fmt.Errorf("Unknown status") +} diff --git a/graphql2/resolvers/pager_bug.go b/graphql2/resolvers/pager_bug.go new file mode 100644 index 00000000..55acfcc4 --- /dev/null +++ b/graphql2/resolvers/pager_bug.go @@ -0,0 +1,225 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package resolvers + +import ( + "fmt" + + "github.com/MichaelMure/git-bug/bug" +) + +type BugSnapshotEdger func(value bug.Snapshot, offset int) Edge + +func BugSnapshotPaginate(source []bug.Snapshot, edger BugSnapshotEdger, input ConnectionInput) ([]BugEdge, PageInfo, error) { + var result []BugEdge + var pageInfo PageInfo + + offset := 0 + + if input.After != nil { + for i, value := range source { + edge := edger(value, i) + if edge.GetCursor() == *input.After { + // remove all previous element including the "after" one + source = source[i+1:] + offset = i + 1 + break + } + } + } + + if input.Before != nil { + for i, value := range source { + edge := edger(value, i+offset) + + if edge.GetCursor() == *input.Before { + // remove all after element including the "before" one + break + } + + result = append(result, edge.(BugEdge)) + } + } else { + result = make([]BugEdge, len(source)) + + for i, value := range source { + result[i] = edger(value, i+offset).(BugEdge) + } + } + + if input.First != nil { + if *input.First < 0 { + return nil, PageInfo{}, fmt.Errorf("first less than zero") + } + + if len(result) > *input.First { + // Slice result to be of length first by removing edges from the end + result = result[:*input.First] + pageInfo.HasNextPage = true + } + } + + if input.Last != nil { + if *input.Last < 0 { + return nil, PageInfo{}, fmt.Errorf("last less than zero") + } + + if len(result) > *input.Last { + // Slice result to be of length last by removing edges from the start + result = result[len(result)-*input.Last:] + pageInfo.HasPreviousPage = true + } + } + + return result, pageInfo, nil +} + +// Apply the before/after cursor params to the source and return an array of edges +//func ApplyCursorToEdges(source []interface{}, edger Edger, input ConnectionInput) []Edge { +// var result []Edge +// +// if input.After != nil { +// for i, value := range source { +// edge := edger(value) +// if edge.Cursor() == *input.After { +// // remove all previous element including the "after" one +// source = source[i+1:] +// break +// } +// } +// } +// +// if input.Before != nil { +// for _, value := range source { +// edge := edger(value) +// +// if edge.Cursor() == *input.Before { +// // remove all after element including the "before" one +// break +// } +// +// result = append(result, edge) +// } +// } else { +// result = make([]Edge, len(source)) +// +// for i, value := range source { +// result[i] = edger(value) +// } +// } +// +// return result +//} + +// Apply the first/last cursor params to the edges +//func EdgesToReturn(edges []Edge, input ConnectionInput) ([]Edge, PageInfo, error) { +// hasPreviousPage := false +// hasNextPage := false +// +// if input.First != nil { +// if *input.First < 0 { +// return nil, nil, 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] +// hasNextPage = true +// } +// } +// +// if input.Last != nil { +// if *input.Last < 0 { +// return nil, nil, 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:] +// hasPreviousPage = true +// } +// } +// +// pageInfo := PageInfo{ +// HasNextPage: hasNextPage, +// HasPreviousPage: hasPreviousPage, +// } +// +// return edges, pageInfo, nil +//} + +//func EdgesToReturn(allEdges []Edge, before *cursor, after *cursor, first *int, last *int) ([]Edge, error) { +// result := ApplyCursorToEdges(allEdges, before, after) +// +// if first != nil { +// if *first < 0 { +// return nil, fmt.Errorf("first less than zero") +// } +// +// if len(result) > *first { +// // Slice result to be of length first by removing edges from the end +// result = result[:*first] +// } +// } +// +// if last != nil { +// if *last < 0 { +// return nil, fmt.Errorf("last less than zero") +// } +// +// if len(result) > *last { +// // Slice result to be of length last by removing edges from the start +// result = result[len(result)-*last:] +// } +// } +// +// return result, nil +//} + +//func ApplyCursorToEdges(allEdges []Edge, before *cursor, after *cursor) []Edge { +// result := allEdges +// +// if after != nil { +// for i, edge := range result { +// if edge.Cursor() == *after { +// // remove all previous element including the "after" one +// result = result[i+1:] +// break +// } +// } +// } +// +// if before != nil { +// for i, edge := range result { +// if edge.Cursor() == *before { +// // remove all after element including the "before" one +// result = result[:i] +// } +// } +// } +// +// return result +//} + +//func HasPreviousPage(allEdges []Edge, before *cursor, after *cursor, last *int) bool { +// if last != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *last +// } +// +// // TODO: handle "after", but according to the spec it's ok to return false +// +// return false +//} +// +//func HasNextPage(allEdges []Edge, before *cursor, after *cursor, first *int) bool { +// if first != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *first +// } +// +// // TODO: handle "before", but according to the spec it's ok to return false +// +// return false diff --git a/graphql2/resolvers/pager_comment.go b/graphql2/resolvers/pager_comment.go new file mode 100644 index 00000000..3dd11757 --- /dev/null +++ b/graphql2/resolvers/pager_comment.go @@ -0,0 +1,225 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package resolvers + +import ( + "fmt" + + "github.com/MichaelMure/git-bug/bug" +) + +type BugCommentEdger func(value bug.Comment, offset int) Edge + +func BugCommentPaginate(source []bug.Comment, edger BugCommentEdger, input ConnectionInput) ([]CommentEdge, PageInfo, error) { + var result []CommentEdge + var pageInfo PageInfo + + offset := 0 + + if input.After != nil { + for i, value := range source { + edge := edger(value, i) + if edge.GetCursor() == *input.After { + // remove all previous element including the "after" one + source = source[i+1:] + offset = i + 1 + break + } + } + } + + if input.Before != nil { + for i, value := range source { + edge := edger(value, i+offset) + + if edge.GetCursor() == *input.Before { + // remove all after element including the "before" one + break + } + + result = append(result, edge.(CommentEdge)) + } + } else { + result = make([]CommentEdge, len(source)) + + for i, value := range source { + result[i] = edger(value, i+offset).(CommentEdge) + } + } + + if input.First != nil { + if *input.First < 0 { + return nil, PageInfo{}, fmt.Errorf("first less than zero") + } + + if len(result) > *input.First { + // Slice result to be of length first by removing edges from the end + result = result[:*input.First] + pageInfo.HasNextPage = true + } + } + + if input.Last != nil { + if *input.Last < 0 { + return nil, PageInfo{}, fmt.Errorf("last less than zero") + } + + if len(result) > *input.Last { + // Slice result to be of length last by removing edges from the start + result = result[len(result)-*input.Last:] + pageInfo.HasPreviousPage = true + } + } + + return result, pageInfo, nil +} + +// Apply the before/after cursor params to the source and return an array of edges +//func ApplyCursorToEdges(source []interface{}, edger Edger, input ConnectionInput) []Edge { +// var result []Edge +// +// if input.After != nil { +// for i, value := range source { +// edge := edger(value) +// if edge.Cursor() == *input.After { +// // remove all previous element including the "after" one +// source = source[i+1:] +// break +// } +// } +// } +// +// if input.Before != nil { +// for _, value := range source { +// edge := edger(value) +// +// if edge.Cursor() == *input.Before { +// // remove all after element including the "before" one +// break +// } +// +// result = append(result, edge) +// } +// } else { +// result = make([]Edge, len(source)) +// +// for i, value := range source { +// result[i] = edger(value) +// } +// } +// +// return result +//} + +// Apply the first/last cursor params to the edges +//func EdgesToReturn(edges []Edge, input ConnectionInput) ([]Edge, PageInfo, error) { +// hasPreviousPage := false +// hasNextPage := false +// +// if input.First != nil { +// if *input.First < 0 { +// return nil, nil, 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] +// hasNextPage = true +// } +// } +// +// if input.Last != nil { +// if *input.Last < 0 { +// return nil, nil, 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:] +// hasPreviousPage = true +// } +// } +// +// pageInfo := PageInfo{ +// HasNextPage: hasNextPage, +// HasPreviousPage: hasPreviousPage, +// } +// +// return edges, pageInfo, nil +//} + +//func EdgesToReturn(allEdges []Edge, before *cursor, after *cursor, first *int, last *int) ([]Edge, error) { +// result := ApplyCursorToEdges(allEdges, before, after) +// +// if first != nil { +// if *first < 0 { +// return nil, fmt.Errorf("first less than zero") +// } +// +// if len(result) > *first { +// // Slice result to be of length first by removing edges from the end +// result = result[:*first] +// } +// } +// +// if last != nil { +// if *last < 0 { +// return nil, fmt.Errorf("last less than zero") +// } +// +// if len(result) > *last { +// // Slice result to be of length last by removing edges from the start +// result = result[len(result)-*last:] +// } +// } +// +// return result, nil +//} + +//func ApplyCursorToEdges(allEdges []Edge, before *cursor, after *cursor) []Edge { +// result := allEdges +// +// if after != nil { +// for i, edge := range result { +// if edge.Cursor() == *after { +// // remove all previous element including the "after" one +// result = result[i+1:] +// break +// } +// } +// } +// +// if before != nil { +// for i, edge := range result { +// if edge.Cursor() == *before { +// // remove all after element including the "before" one +// result = result[:i] +// } +// } +// } +// +// return result +//} + +//func HasPreviousPage(allEdges []Edge, before *cursor, after *cursor, last *int) bool { +// if last != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *last +// } +// +// // TODO: handle "after", but according to the spec it's ok to return false +// +// return false +//} +// +//func HasNextPage(allEdges []Edge, before *cursor, after *cursor, first *int) bool { +// if first != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *first +// } +// +// // TODO: handle "before", but according to the spec it's ok to return false +// +// return false diff --git a/graphql2/resolvers/pager_operation.go b/graphql2/resolvers/pager_operation.go new file mode 100644 index 00000000..fe4eebc2 --- /dev/null +++ b/graphql2/resolvers/pager_operation.go @@ -0,0 +1,225 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package resolvers + +import ( + "fmt" + + "github.com/MichaelMure/git-bug/bug" +) + +type BugOperationEdger func(value bug.Operation, offset int) Edge + +func BugOperationPaginate(source []bug.Operation, edger BugOperationEdger, input ConnectionInput) ([]OperationEdge, PageInfo, error) { + var result []OperationEdge + var pageInfo PageInfo + + offset := 0 + + if input.After != nil { + for i, value := range source { + edge := edger(value, i) + if edge.GetCursor() == *input.After { + // remove all previous element including the "after" one + source = source[i+1:] + offset = i + 1 + break + } + } + } + + if input.Before != nil { + for i, value := range source { + edge := edger(value, i+offset) + + if edge.GetCursor() == *input.Before { + // remove all after element including the "before" one + break + } + + result = append(result, edge.(OperationEdge)) + } + } else { + result = make([]OperationEdge, len(source)) + + for i, value := range source { + result[i] = edger(value, i+offset).(OperationEdge) + } + } + + if input.First != nil { + if *input.First < 0 { + return nil, PageInfo{}, fmt.Errorf("first less than zero") + } + + if len(result) > *input.First { + // Slice result to be of length first by removing edges from the end + result = result[:*input.First] + pageInfo.HasNextPage = true + } + } + + if input.Last != nil { + if *input.Last < 0 { + return nil, PageInfo{}, fmt.Errorf("last less than zero") + } + + if len(result) > *input.Last { + // Slice result to be of length last by removing edges from the start + result = result[len(result)-*input.Last:] + pageInfo.HasPreviousPage = true + } + } + + return result, pageInfo, nil +} + +// Apply the before/after cursor params to the source and return an array of edges +//func ApplyCursorToEdges(source []interface{}, edger Edger, input ConnectionInput) []Edge { +// var result []Edge +// +// if input.After != nil { +// for i, value := range source { +// edge := edger(value) +// if edge.Cursor() == *input.After { +// // remove all previous element including the "after" one +// source = source[i+1:] +// break +// } +// } +// } +// +// if input.Before != nil { +// for _, value := range source { +// edge := edger(value) +// +// if edge.Cursor() == *input.Before { +// // remove all after element including the "before" one +// break +// } +// +// result = append(result, edge) +// } +// } else { +// result = make([]Edge, len(source)) +// +// for i, value := range source { +// result[i] = edger(value) +// } +// } +// +// return result +//} + +// Apply the first/last cursor params to the edges +//func EdgesToReturn(edges []Edge, input ConnectionInput) ([]Edge, PageInfo, error) { +// hasPreviousPage := false +// hasNextPage := false +// +// if input.First != nil { +// if *input.First < 0 { +// return nil, nil, 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] +// hasNextPage = true +// } +// } +// +// if input.Last != nil { +// if *input.Last < 0 { +// return nil, nil, 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:] +// hasPreviousPage = true +// } +// } +// +// pageInfo := PageInfo{ +// HasNextPage: hasNextPage, +// HasPreviousPage: hasPreviousPage, +// } +// +// return edges, pageInfo, nil +//} + +//func EdgesToReturn(allEdges []Edge, before *cursor, after *cursor, first *int, last *int) ([]Edge, error) { +// result := ApplyCursorToEdges(allEdges, before, after) +// +// if first != nil { +// if *first < 0 { +// return nil, fmt.Errorf("first less than zero") +// } +// +// if len(result) > *first { +// // Slice result to be of length first by removing edges from the end +// result = result[:*first] +// } +// } +// +// if last != nil { +// if *last < 0 { +// return nil, fmt.Errorf("last less than zero") +// } +// +// if len(result) > *last { +// // Slice result to be of length last by removing edges from the start +// result = result[len(result)-*last:] +// } +// } +// +// return result, nil +//} + +//func ApplyCursorToEdges(allEdges []Edge, before *cursor, after *cursor) []Edge { +// result := allEdges +// +// if after != nil { +// for i, edge := range result { +// if edge.Cursor() == *after { +// // remove all previous element including the "after" one +// result = result[i+1:] +// break +// } +// } +// } +// +// if before != nil { +// for i, edge := range result { +// if edge.Cursor() == *before { +// // remove all after element including the "before" one +// result = result[:i] +// } +// } +// } +// +// return result +//} + +//func HasPreviousPage(allEdges []Edge, before *cursor, after *cursor, last *int) bool { +// if last != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *last +// } +// +// // TODO: handle "after", but according to the spec it's ok to return false +// +// return false +//} +// +//func HasNextPage(allEdges []Edge, before *cursor, after *cursor, first *int) bool { +// if first != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *first +// } +// +// // TODO: handle "before", but according to the spec it's ok to return false +// +// return false diff --git a/graphql2/resolvers/pagers.go b/graphql2/resolvers/pagers.go new file mode 100644 index 00000000..378dcdbf --- /dev/null +++ b/graphql2/resolvers/pagers.go @@ -0,0 +1,51 @@ +//go:generate genny -in=pagers_template.go -out=pager_bug.go gen "NodeType=bug.Snapshot EdgeType=BugEdge" +//go:generate genny -in=pagers_template.go -out=pager_operation.go gen "NodeType=bug.Operation EdgeType=OperationEdge" +//go:generate genny -in=pagers_template.go -out=pager_comment.go gen "NodeType=bug.Comment EdgeType=CommentEdge" + +package resolvers + +import ( + "encoding/base64" + "fmt" + "strconv" + "strings" +) + +const cursorPrefix = "cursor:" + +type Edge interface { + GetCursor() string +} + +// Creates the cursor string from an offset +func offsetToCursor(offset int) string { + str := fmt.Sprintf("%v%v", cursorPrefix, offset) + return base64.StdEncoding.EncodeToString([]byte(str)) +} + +// Re-derives the offset from the cursor string. +func cursorToOffset(cursor string) (int, error) { + str := "" + b, err := base64.StdEncoding.DecodeString(cursor) + if err == nil { + str = string(b) + } + str = strings.Replace(str, cursorPrefix, "", -1) + offset, err := strconv.Atoi(str) + if err != nil { + return 0, fmt.Errorf("Invalid cursor") + } + return offset, nil +} + +func (e OperationEdge) GetCursor() string { + return e.Cursor +} + +func (e BugEdge) GetCursor() string { + return e.Cursor +} + +func (e CommentEdge) GetCursor() string { + return e.Cursor +} diff --git a/graphql2/resolvers/pagers_template.go b/graphql2/resolvers/pagers_template.go new file mode 100644 index 00000000..0ca7de75 --- /dev/null +++ b/graphql2/resolvers/pagers_template.go @@ -0,0 +1,224 @@ +package resolvers + +import ( + "fmt" + "github.com/cheekybits/genny/generic" +) + +type NodeType generic.Type +type EdgeType generic.Type + +type NodeTypeEdger func(value NodeType, offset int) Edge + +func NodeTypePaginate(source []NodeType, edger NodeTypeEdger, input ConnectionInput) ([]EdgeType, PageInfo, error) { + var result []EdgeType + var pageInfo PageInfo + + offset := 0 + + if input.After != nil { + for i, value := range source { + edge := edger(value, i) + if edge.GetCursor() == *input.After { + // remove all previous element including the "after" one + source = source[i+1:] + offset = i + 1 + break + } + } + } + + if input.Before != nil { + for i, value := range source { + edge := edger(value, i+offset) + + if edge.GetCursor() == *input.Before { + // remove all after element including the "before" one + break + } + + result = append(result, edge.(EdgeType)) + } + } else { + result = make([]EdgeType, len(source)) + + for i, value := range source { + result[i] = edger(value, i+offset).(EdgeType) + } + } + + if input.First != nil { + if *input.First < 0 { + return nil, PageInfo{}, fmt.Errorf("first less than zero") + } + + if len(result) > *input.First { + // Slice result to be of length first by removing edges from the end + result = result[:*input.First] + pageInfo.HasNextPage = true + } + } + + if input.Last != nil { + if *input.Last < 0 { + return nil, PageInfo{}, fmt.Errorf("last less than zero") + } + + if len(result) > *input.Last { + // Slice result to be of length last by removing edges from the start + result = result[len(result)-*input.Last:] + pageInfo.HasPreviousPage = true + } + } + + return result, pageInfo, nil +} + +// Apply the before/after cursor params to the source and return an array of edges +//func ApplyCursorToEdges(source []interface{}, edger Edger, input ConnectionInput) []Edge { +// var result []Edge +// +// if input.After != nil { +// for i, value := range source { +// edge := edger(value) +// if edge.Cursor() == *input.After { +// // remove all previous element including the "after" one +// source = source[i+1:] +// break +// } +// } +// } +// +// if input.Before != nil { +// for _, value := range source { +// edge := edger(value) +// +// if edge.Cursor() == *input.Before { +// // remove all after element including the "before" one +// break +// } +// +// result = append(result, edge) +// } +// } else { +// result = make([]Edge, len(source)) +// +// for i, value := range source { +// result[i] = edger(value) +// } +// } +// +// return result +//} + +// Apply the first/last cursor params to the edges +//func EdgesToReturn(edges []Edge, input ConnectionInput) ([]Edge, PageInfo, error) { +// hasPreviousPage := false +// hasNextPage := false +// +// if input.First != nil { +// if *input.First < 0 { +// return nil, nil, 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] +// hasNextPage = true +// } +// } +// +// if input.Last != nil { +// if *input.Last < 0 { +// return nil, nil, 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:] +// hasPreviousPage = true +// } +// } +// +// pageInfo := PageInfo{ +// HasNextPage: hasNextPage, +// HasPreviousPage: hasPreviousPage, +// } +// +// return edges, pageInfo, nil +//} + +//func EdgesToReturn(allEdges []Edge, before *cursor, after *cursor, first *int, last *int) ([]Edge, error) { +// result := ApplyCursorToEdges(allEdges, before, after) +// +// if first != nil { +// if *first < 0 { +// return nil, fmt.Errorf("first less than zero") +// } +// +// if len(result) > *first { +// // Slice result to be of length first by removing edges from the end +// result = result[:*first] +// } +// } +// +// if last != nil { +// if *last < 0 { +// return nil, fmt.Errorf("last less than zero") +// } +// +// if len(result) > *last { +// // Slice result to be of length last by removing edges from the start +// result = result[len(result)-*last:] +// } +// } +// +// return result, nil +//} + +//func ApplyCursorToEdges(allEdges []Edge, before *cursor, after *cursor) []Edge { +// result := allEdges +// +// if after != nil { +// for i, edge := range result { +// if edge.Cursor() == *after { +// // remove all previous element including the "after" one +// result = result[i+1:] +// break +// } +// } +// } +// +// if before != nil { +// for i, edge := range result { +// if edge.Cursor() == *before { +// // remove all after element including the "before" one +// result = result[:i] +// } +// } +// } +// +// return result +//} + +//func HasPreviousPage(allEdges []Edge, before *cursor, after *cursor, last *int) bool { +// if last != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *last +// } +// +// // TODO: handle "after", but according to the spec it's ok to return false +// +// return false +//} +// +//func HasNextPage(allEdges []Edge, before *cursor, after *cursor, first *int) bool { +// if first != nil { +// edges := ApplyCursorToEdges(allEdges, before, after) +// return len(edges) > *first +// } +// +// // TODO: handle "before", but according to the spec it's ok to return false +// +// return false +//} diff --git a/graphql2/resolvers/query.go b/graphql2/resolvers/query.go new file mode 100644 index 00000000..cceca334 --- /dev/null +++ b/graphql2/resolvers/query.go @@ -0,0 +1,36 @@ +package resolvers + +import ( + "context" + "github.com/MichaelMure/git-bug/cache" +) + +type rootQueryResolver struct { + cache cache.Cacher +} + +func (r rootQueryResolver) DefaultRepository(ctx context.Context) (*repoResolver, error) { + repo, err := r.cache.DefaultRepo() + + if err != nil { + return nil, err + } + + return &repoResolver{ + cache: r.cache, + repo: repo, + }, nil +} + +func (r rootQueryResolver) Repository(ctx context.Context, id string) (*repoResolver, error) { + repo, err := r.cache.ResolveRepo(id) + + if err != nil { + return nil, err + } + + return &repoResolver{ + cache: r.cache, + repo: repo, + }, nil +} diff --git a/graphql2/resolvers/repo.go b/graphql2/resolvers/repo.go new file mode 100644 index 00000000..14019b65 --- /dev/null +++ b/graphql2/resolvers/repo.go @@ -0,0 +1,26 @@ +package resolvers + +import ( + "context" + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/cache" +) + +type repoResolver struct { + cache cache.Cacher + repo cache.RepoCacher +} + +func (repoResolver) AllBugs(ctx context.Context, obj *repoResolver, input ConnectionInput) (BugConnection, error) { + panic("implement me") +} + +func (repoResolver) Bug(ctx context.Context, obj *repoResolver, prefix string) (*bug.Snapshot, error) { + b, err := obj.repo.ResolveBugPrefix(prefix) + + if err != nil { + return nil, err + } + + return b.Snapshot(), nil +} diff --git a/graphql2/resolvers/root.go b/graphql2/resolvers/root.go new file mode 100644 index 00000000..e5f83060 --- /dev/null +++ b/graphql2/resolvers/root.go @@ -0,0 +1,53 @@ +package resolvers + +import ( + "github.com/MichaelMure/git-bug/cache" +) + +type RootResolver struct { + cache.RootCache +} + +func NewRootResolver() *RootResolver { + return &RootResolver{ + RootCache: cache.NewCache(), + } +} + +func (r RootResolver) Query() QueryResolver { + return &rootQueryResolver{ + cache: &r.RootCache, + } +} + +func (RootResolver) AddCommentOperation() AddCommentOperationResolver { + return &addCommentOperationResolver{} +} + +func (r RootResolver) Bug() BugResolver { + return &bugResolver{ + cache: &r.RootCache, + } +} + +func (RootResolver) CreateOperation() CreateOperationResolver { + return &createOperationResolver{} +} + +func (RootResolver) LabelChangeOperation() LabelChangeOperationResolver { + return &labelChangeOperation{} +} + +func (r RootResolver) Repository() RepositoryResolver { + return &repoResolver{ + cache: &r.RootCache, + } +} + +func (RootResolver) SetStatusOperation() SetStatusOperationResolver { + return &setStatusOperationResolver{} +} + +func (RootResolver) SetTitleOperation() SetTitleOperationResolver { + return &setTitleOperationResolver{} +} diff --git a/graphql2/schema.graphql b/graphql2/schema.graphql index 3c24c746..47716488 100644 --- a/graphql2/schema.graphql +++ b/graphql2/schema.graphql @@ -1,7 +1,3 @@ -schema { - query: RootQuery -} - scalar Time scalar Label @@ -14,10 +10,24 @@ type PageInfo { hasPreviousPage: Boolean! # When paginating backwards, the cursor to continue. - startCursor: String +# startCursor: String # When paginating forwards, the cursor to continue. - endCursor: String +# endCursor: String +} + +input ConnectionInput { + # 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 } # Represents an person in a git object. @@ -31,8 +41,7 @@ type Person { type CommentConnection { - edges: [CommentEdge] - nodes: [Comment] + edges: [CommentEdge!]! pageInfo: PageInfo! totalCount: Int! } @@ -42,23 +51,6 @@ type CommentEdge { node: Comment! } -interface Commentable { - # A list of comments associated with the object. - comments( - # 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 - ): CommentConnection! -} - # Represents a comment on a bug. type Comment implements Authored { # The author of this comment. @@ -80,15 +72,14 @@ interface Authored { } type OperationConnection { - edges: [OperationEdge]! - nodes: [OperationUnion]! + edges: [OperationEdge!]! pageInfo: PageInfo! totalCount: Int! } type OperationEdge { cursor: String! - node: OperationUnion + node: OperationUnion! } # An operation applied to a bug. @@ -133,8 +124,8 @@ type LabelChangeOperation implements Operation, Authored { author: Person! date: Time! - added: [Label]! - removed: [Label]! + added: [Label!]! + removed: [Label!]! } union OperationUnion = @@ -144,14 +135,11 @@ union OperationUnion = | SetStatusOperation | LabelChangeOperation -# The connection type for Label. +# The connection type for Bug. type BugConnection { # A list of edges. edges: [BugEdge]! - # A list of nodes. - nodes: [Bug]! - # Information to aid in pagination. pageInfo: PageInfo! @@ -165,69 +153,29 @@ type BugEdge { cursor: String! # The item at the end of the edge. - node: Bug + node: Bug! } -type Bug implements Authored, Commentable { +type Bug { id: String! humanId: String! title: String! status: Status! # A list of labels associated with the repository. - labels: [Label]! + labels: [Label!]! - comments( - # Returns the elements in the list that come after the specified cursor. - after: String + comments(input: ConnectionInput!): CommentConnection! - # 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 - - # If provided, searches comments by name and description. - query: String - ): CommentConnection! - - operations( - # 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 - - # If provided, searches operations by name and description. - query: String - ): OperationConnection! + operations(input: ConnectionInput!): OperationConnection! } -type RootQuery { - allBugs( - # 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 +type Repository { + allBugs(input: ConnectionInput!): BugConnection! + bug(prefix: String!): Bug +} - # If provided, searches labels by name and description. - query: String - ): BugConnection! - bug(id: String!): Bug +type Query { + defaultRepository: Repository + repository(id: String!): Repository } |