chore: handle push of unchanged schema

This commit is contained in:
2022-10-14 22:41:56 +02:00
parent eb41e24002
commit b1124d6350
10 changed files with 866 additions and 61 deletions
+1
View File
@@ -4,3 +4,4 @@
coverage.html
/exported
/release
/schemactl
+9 -2
View File
@@ -2,6 +2,7 @@ package cache
import (
"fmt"
"time"
"github.com/apex/log"
"github.com/sparetimecoders/goamqp"
@@ -14,15 +15,18 @@ const subGraphKey = "%s<->%s"
type Cache struct {
services map[string]map[string]struct{}
subGraphs map[string]string
lastUpdate map[string]string
logger log.Interface
}
func (c *Cache) Services(ref string) []string {
func (c *Cache) Services(ref, lastUpdate string) ([]string, string) {
var services []string
if lastUpdate == "" || c.lastUpdate[ref] > lastUpdate {
for k := range c.services[ref] {
services = append(services, k)
}
return services
}
return services, c.lastUpdate[ref]
}
func (c *Cache) SubGraphId(ref, service string) string {
@@ -37,12 +41,14 @@ func (c *Cache) Update(msg any, _ goamqp.Headers) (any, error) {
}
c.services[m.Ref][m.ID.String()] = struct{}{}
c.subGraphs[fmt.Sprintf(subGraphKey, m.Ref, m.Service)] = m.ID.String()
c.lastUpdate[m.Ref] = m.Time.Format(time.RFC3339Nano)
case *domain.SubGraph:
if _, exists := c.services[m.Ref]; !exists {
c.services[m.Ref] = make(map[string]struct{})
}
c.services[m.Ref][m.ID.String()] = struct{}{}
c.subGraphs[fmt.Sprintf(subGraphKey, m.Ref, m.Service)] = m.ID.String()
c.lastUpdate[m.Ref] = m.ChangedAt.Format(time.RFC3339Nano)
default:
c.logger.Warnf("unexpected message received: %+v", msg)
}
@@ -53,6 +59,7 @@ func New(logger log.Interface) *Cache {
return &Cache{
subGraphs: make(map[string]string),
services: make(map[string]map[string]struct{}),
lastUpdate: make(map[string]string),
logger: logger,
}
}
+5 -1
View File
@@ -1,5 +1,7 @@
query SubGraphs($ref: String!) {
subGraphs(ref: $ref) {
supergraph(ref: $ref) {
... on SubGraphs {
subGraphs {
service
url
wsUrl
@@ -7,3 +9,5 @@ query SubGraphs($ref: String!) {
changedAt
}
}
}
}
+7 -2
View File
@@ -2,6 +2,7 @@ package ctl
import (
"context"
"fmt"
"net/http"
"net/url"
@@ -47,8 +48,10 @@ func List(apiKey, schemaRef, service string, schemasUrl url.URL) ([]*SubGraph, e
if err != nil {
return nil, err
}
subGraphs := make([]*SubGraph, len(response.SubGraphs))
for i, subGraph := range response.SubGraphs {
var subGraphs []*SubGraph
if s, ok := response.Supergraph.(*SubGraphsSupergraphSubGraphs); ok {
subGraphs = make([]*SubGraph, len(s.SubGraphs))
for i, subGraph := range s.SubGraphs {
subGraphs[i] = &SubGraph{
Service: subGraph.Service,
URL: subGraph.Url,
@@ -59,3 +62,5 @@ func List(apiKey, schemaRef, service string, schemasUrl url.URL) ([]*SubGraph, e
}
return subGraphs, nil
}
return nil, fmt.Errorf("unexpected response type")
}
+177 -16
View File
@@ -4,6 +4,8 @@ package ctl
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/Khan/genqlient/graphql"
@@ -34,14 +36,160 @@ func (v *InputSubGraph) GetSdl() string { return v.Sdl }
// SubGraphsResponse is returned by SubGraphs on success.
type SubGraphsResponse struct {
SubGraphs []*SubGraphsSubGraphsSubGraph `json:"subGraphs"`
Supergraph SubGraphsSupergraph `json:"-"`
}
// GetSubGraphs returns SubGraphsResponse.SubGraphs, and is useful for accessing the field via an interface.
func (v *SubGraphsResponse) GetSubGraphs() []*SubGraphsSubGraphsSubGraph { return v.SubGraphs }
// GetSupergraph returns SubGraphsResponse.Supergraph, and is useful for accessing the field via an interface.
func (v *SubGraphsResponse) GetSupergraph() SubGraphsSupergraph { return v.Supergraph }
// SubGraphsSubGraphsSubGraph includes the requested fields of the GraphQL type SubGraph.
type SubGraphsSubGraphsSubGraph struct {
func (v *SubGraphsResponse) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
return nil
}
var firstPass struct {
*SubGraphsResponse
Supergraph json.RawMessage `json:"supergraph"`
graphql.NoUnmarshalJSON
}
firstPass.SubGraphsResponse = v
err := json.Unmarshal(b, &firstPass)
if err != nil {
return err
}
{
dst := &v.Supergraph
src := firstPass.Supergraph
if len(src) != 0 && string(src) != "null" {
err = __unmarshalSubGraphsSupergraph(
src, dst)
if err != nil {
return fmt.Errorf(
"unable to unmarshal SubGraphsResponse.Supergraph: %w", err)
}
}
}
return nil
}
type __premarshalSubGraphsResponse struct {
Supergraph json.RawMessage `json:"supergraph"`
}
func (v *SubGraphsResponse) MarshalJSON() ([]byte, error) {
premarshaled, err := v.__premarshalJSON()
if err != nil {
return nil, err
}
return json.Marshal(premarshaled)
}
func (v *SubGraphsResponse) __premarshalJSON() (*__premarshalSubGraphsResponse, error) {
var retval __premarshalSubGraphsResponse
{
dst := &retval.Supergraph
src := v.Supergraph
var err error
*dst, err = __marshalSubGraphsSupergraph(
&src)
if err != nil {
return nil, fmt.Errorf(
"unable to marshal SubGraphsResponse.Supergraph: %w", err)
}
}
return &retval, nil
}
// SubGraphsSupergraph includes the requested fields of the GraphQL interface Supergraph.
//
// SubGraphsSupergraph is implemented by the following types:
// SubGraphsSupergraphSubGraphs
// SubGraphsSupergraphUnchanged
type SubGraphsSupergraph interface {
implementsGraphQLInterfaceSubGraphsSupergraph()
// GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values).
GetTypename() *string
}
func (v *SubGraphsSupergraphSubGraphs) implementsGraphQLInterfaceSubGraphsSupergraph() {}
func (v *SubGraphsSupergraphUnchanged) implementsGraphQLInterfaceSubGraphsSupergraph() {}
func __unmarshalSubGraphsSupergraph(b []byte, v *SubGraphsSupergraph) error {
if string(b) == "null" {
return nil
}
var tn struct {
TypeName string `json:"__typename"`
}
err := json.Unmarshal(b, &tn)
if err != nil {
return err
}
switch tn.TypeName {
case "SubGraphs":
*v = new(SubGraphsSupergraphSubGraphs)
return json.Unmarshal(b, *v)
case "Unchanged":
*v = new(SubGraphsSupergraphUnchanged)
return json.Unmarshal(b, *v)
case "":
return fmt.Errorf(
"response was missing Supergraph.__typename")
default:
return fmt.Errorf(
`unexpected concrete type for SubGraphsSupergraph: "%v"`, tn.TypeName)
}
}
func __marshalSubGraphsSupergraph(v *SubGraphsSupergraph) ([]byte, error) {
var typename string
switch v := (*v).(type) {
case *SubGraphsSupergraphSubGraphs:
typename = "SubGraphs"
result := struct {
TypeName string `json:"__typename"`
*SubGraphsSupergraphSubGraphs
}{typename, v}
return json.Marshal(result)
case *SubGraphsSupergraphUnchanged:
typename = "Unchanged"
result := struct {
TypeName string `json:"__typename"`
*SubGraphsSupergraphUnchanged
}{typename, v}
return json.Marshal(result)
case nil:
return []byte("null"), nil
default:
return nil, fmt.Errorf(
`unexpected concrete type for SubGraphsSupergraph: "%T"`, v)
}
}
// SubGraphsSupergraphSubGraphs includes the requested fields of the GraphQL type SubGraphs.
type SubGraphsSupergraphSubGraphs struct {
Typename *string `json:"__typename"`
SubGraphs []*SubGraphsSupergraphSubGraphsSubGraphsSubGraph `json:"subGraphs"`
}
// GetTypename returns SubGraphsSupergraphSubGraphs.Typename, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphs) GetTypename() *string { return v.Typename }
// GetSubGraphs returns SubGraphsSupergraphSubGraphs.SubGraphs, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphs) GetSubGraphs() []*SubGraphsSupergraphSubGraphsSubGraphsSubGraph {
return v.SubGraphs
}
// SubGraphsSupergraphSubGraphsSubGraphsSubGraph includes the requested fields of the GraphQL type SubGraph.
type SubGraphsSupergraphSubGraphsSubGraphsSubGraph struct {
Service string `json:"service"`
Url *string `json:"url"`
WsUrl *string `json:"wsUrl"`
@@ -49,20 +197,28 @@ type SubGraphsSubGraphsSubGraph struct {
ChangedAt time.Time `json:"changedAt"`
}
// GetService returns SubGraphsSubGraphsSubGraph.Service, and is useful for accessing the field via an interface.
func (v *SubGraphsSubGraphsSubGraph) GetService() string { return v.Service }
// GetService returns SubGraphsSupergraphSubGraphsSubGraphsSubGraph.Service, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphsSubGraphsSubGraph) GetService() string { return v.Service }
// GetUrl returns SubGraphsSubGraphsSubGraph.Url, and is useful for accessing the field via an interface.
func (v *SubGraphsSubGraphsSubGraph) GetUrl() *string { return v.Url }
// GetUrl returns SubGraphsSupergraphSubGraphsSubGraphsSubGraph.Url, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphsSubGraphsSubGraph) GetUrl() *string { return v.Url }
// GetWsUrl returns SubGraphsSubGraphsSubGraph.WsUrl, and is useful for accessing the field via an interface.
func (v *SubGraphsSubGraphsSubGraph) GetWsUrl() *string { return v.WsUrl }
// GetWsUrl returns SubGraphsSupergraphSubGraphsSubGraphsSubGraph.WsUrl, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphsSubGraphsSubGraph) GetWsUrl() *string { return v.WsUrl }
// GetChangedBy returns SubGraphsSubGraphsSubGraph.ChangedBy, and is useful for accessing the field via an interface.
func (v *SubGraphsSubGraphsSubGraph) GetChangedBy() string { return v.ChangedBy }
// GetChangedBy returns SubGraphsSupergraphSubGraphsSubGraphsSubGraph.ChangedBy, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphsSubGraphsSubGraph) GetChangedBy() string { return v.ChangedBy }
// GetChangedAt returns SubGraphsSubGraphsSubGraph.ChangedAt, and is useful for accessing the field via an interface.
func (v *SubGraphsSubGraphsSubGraph) GetChangedAt() time.Time { return v.ChangedAt }
// GetChangedAt returns SubGraphsSupergraphSubGraphsSubGraphsSubGraph.ChangedAt, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphSubGraphsSubGraphsSubGraph) GetChangedAt() time.Time { return v.ChangedAt }
// SubGraphsSupergraphUnchanged includes the requested fields of the GraphQL type Unchanged.
type SubGraphsSupergraphUnchanged struct {
Typename *string `json:"__typename"`
}
// GetTypename returns SubGraphsSupergraphUnchanged.Typename, and is useful for accessing the field via an interface.
func (v *SubGraphsSupergraphUnchanged) GetTypename() *string { return v.Typename }
// UpdateSubGraphResponse is returned by UpdateSubGraph on success.
type UpdateSubGraphResponse struct {
@@ -123,7 +279,10 @@ func SubGraphs(
OpName: "SubGraphs",
Query: `
query SubGraphs ($ref: String!) {
subGraphs(ref: $ref) {
supergraph(ref: $ref) {
__typename
... on SubGraphs {
subGraphs {
service
url
wsUrl
@@ -131,6 +290,8 @@ query SubGraphs ($ref: String!) {
changedAt
}
}
}
}
`,
Variables: &__SubGraphsInput{
Ref: ref,
+558 -1
View File
@@ -52,6 +52,7 @@ type ComplexityRoot struct {
Query struct {
SubGraphs func(childComplexity int, ref string) int
Supergraph func(childComplexity int, ref string, isAfter *string) int
}
SubGraph struct {
@@ -63,6 +64,17 @@ type ComplexityRoot struct {
URL func(childComplexity int) int
WsURL func(childComplexity int) int
}
SubGraphs struct {
ID func(childComplexity int) int
MinDelaySeconds func(childComplexity int) int
SubGraphs func(childComplexity int) int
}
Unchanged struct {
ID func(childComplexity int) int
MinDelaySeconds func(childComplexity int) int
}
}
type MutationResolver interface {
@@ -70,6 +82,7 @@ type MutationResolver interface {
}
type QueryResolver interface {
SubGraphs(ctx context.Context, ref string) ([]*model.SubGraph, error)
Supergraph(ctx context.Context, ref string, isAfter *string) (model.Supergraph, error)
}
type executableSchema struct {
@@ -111,6 +124,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Query.SubGraphs(childComplexity, args["ref"].(string)), true
case "Query.supergraph":
if e.complexity.Query.Supergraph == nil {
break
}
args, err := ec.field_Query_supergraph_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Query.Supergraph(childComplexity, args["ref"].(string), args["isAfter"].(*string)), true
case "SubGraph.changedAt":
if e.complexity.SubGraph.ChangedAt == nil {
break
@@ -160,6 +185,41 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.SubGraph.WsURL(childComplexity), true
case "SubGraphs.id":
if e.complexity.SubGraphs.ID == nil {
break
}
return e.complexity.SubGraphs.ID(childComplexity), true
case "SubGraphs.minDelaySeconds":
if e.complexity.SubGraphs.MinDelaySeconds == nil {
break
}
return e.complexity.SubGraphs.MinDelaySeconds(childComplexity), true
case "SubGraphs.subGraphs":
if e.complexity.SubGraphs.SubGraphs == nil {
break
}
return e.complexity.SubGraphs.SubGraphs(childComplexity), true
case "Unchanged.id":
if e.complexity.Unchanged.ID == nil {
break
}
return e.complexity.Unchanged.ID(childComplexity), true
case "Unchanged.minDelaySeconds":
if e.complexity.Unchanged.MinDelaySeconds == nil {
break
}
return e.complexity.Unchanged.MinDelaySeconds(childComplexity), true
}
return 0, false
}
@@ -230,13 +290,27 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er
var sources = []*ast.Source{
{Name: "../schema.graphqls", Input: `type Query {
subGraphs(ref: String!): [SubGraph!]! @hasApiKey
subGraphs(ref: String!): [SubGraph!]! @hasApiKey @deprecated(reason: "Use supergraph instead")
supergraph(ref: String!, isAfter: String): Supergraph! @hasApiKey
}
type Mutation {
updateSubGraph(input: InputSubGraph!): SubGraph! @hasApiKey
}
union Supergraph = Unchanged | SubGraphs
type Unchanged {
id: ID!
minDelaySeconds: Int!
}
type SubGraphs {
id: ID!
minDelaySeconds: Int!
subGraphs: [SubGraph!]!
}
type SubGraph {
id: ID!
service: String!
@@ -311,6 +385,30 @@ func (ec *executionContext) field_Query_subGraphs_args(ctx context.Context, rawA
return args, nil
}
func (ec *executionContext) field_Query_supergraph_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["ref"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ref"))
arg0, err = ec.unmarshalNString2string(ctx, tmp)
if err != nil {
return nil, err
}
}
args["ref"] = arg0
var arg1 *string
if tmp, ok := rawArgs["isAfter"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isAfter"))
arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
if err != nil {
return nil, err
}
}
args["isAfter"] = arg1
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{}{}
@@ -531,6 +629,81 @@ func (ec *executionContext) fieldContext_Query_subGraphs(ctx context.Context, fi
return fc, nil
}
func (ec *executionContext) _Query_supergraph(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_supergraph(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
directive0 := func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().Supergraph(rctx, fc.Args["ref"].(string), fc.Args["isAfter"].(*string))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.HasApiKey == nil {
return nil, errors.New("directive hasApiKey is not implemented")
}
return ec.directives.HasApiKey(ctx, nil, directive0)
}
tmp, err := directive1(rctx)
if err != nil {
return nil, graphql.ErrorOnPath(ctx, err)
}
if tmp == nil {
return nil, nil
}
if data, ok := tmp.(model.Supergraph); ok {
return data, nil
}
return nil, fmt.Errorf(`unexpected type %T from directive, should be gitlab.com/unboundsoftware/schemas/graph/model.Supergraph`, tmp)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(model.Supergraph)
fc.Result = res
return ec.marshalNSupergraph2gitlabᚗcomᚋunboundsoftwareᚋschemasᚋgraphᚋmodelᚐSupergraph(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Query_supergraph(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Query",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Supergraph does not have child fields")
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Query_supergraph_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return
}
return fc, nil
}
func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query___type(ctx, field)
if err != nil {
@@ -962,6 +1135,242 @@ func (ec *executionContext) fieldContext_SubGraph_changedAt(ctx context.Context,
return fc, nil
}
func (ec *executionContext) _SubGraphs_id(ctx context.Context, field graphql.CollectedField, obj *model.SubGraphs) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_SubGraphs_id(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNID2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_SubGraphs_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "SubGraphs",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ID does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _SubGraphs_minDelaySeconds(ctx context.Context, field graphql.CollectedField, obj *model.SubGraphs) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_SubGraphs_minDelaySeconds(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.MinDelaySeconds, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(int)
fc.Result = res
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_SubGraphs_minDelaySeconds(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "SubGraphs",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Int does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _SubGraphs_subGraphs(ctx context.Context, field graphql.CollectedField, obj *model.SubGraphs) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_SubGraphs_subGraphs(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.SubGraphs, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]*model.SubGraph)
fc.Result = res
return ec.marshalNSubGraph2ᚕᚖgitlabᚗcomᚋunboundsoftwareᚋschemasᚋgraphᚋmodelᚐSubGraphᚄ(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_SubGraphs_subGraphs(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "SubGraphs",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_SubGraph_id(ctx, field)
case "service":
return ec.fieldContext_SubGraph_service(ctx, field)
case "url":
return ec.fieldContext_SubGraph_url(ctx, field)
case "wsUrl":
return ec.fieldContext_SubGraph_wsUrl(ctx, field)
case "sdl":
return ec.fieldContext_SubGraph_sdl(ctx, field)
case "changedBy":
return ec.fieldContext_SubGraph_changedBy(ctx, field)
case "changedAt":
return ec.fieldContext_SubGraph_changedAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type SubGraph", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _Unchanged_id(ctx context.Context, field graphql.CollectedField, obj *model.Unchanged) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Unchanged_id(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNID2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Unchanged_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Unchanged",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ID does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Unchanged_minDelaySeconds(ctx context.Context, field graphql.CollectedField, obj *model.Unchanged) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Unchanged_minDelaySeconds(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.MinDelaySeconds, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(int)
fc.Result = res
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Unchanged_minDelaySeconds(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Unchanged",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Int does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
fc, err := ec.fieldContext___Directive_name(ctx, field)
if err != nil {
@@ -2799,6 +3208,29 @@ func (ec *executionContext) unmarshalInputInputSubGraph(ctx context.Context, obj
// region ************************** interface.gotpl ***************************
func (ec *executionContext) _Supergraph(ctx context.Context, sel ast.SelectionSet, obj model.Supergraph) graphql.Marshaler {
switch obj := (obj).(type) {
case nil:
return graphql.Null
case model.Unchanged:
return ec._Unchanged(ctx, sel, &obj)
case *model.Unchanged:
if obj == nil {
return graphql.Null
}
return ec._Unchanged(ctx, sel, obj)
case model.SubGraphs:
return ec._SubGraphs(ctx, sel, &obj)
case *model.SubGraphs:
if obj == nil {
return graphql.Null
}
return ec._SubGraphs(ctx, sel, obj)
default:
panic(fmt.Errorf("unexpected type %T", obj))
}
}
// endregion ************************** interface.gotpl ***************************
// region **************************** object.gotpl ****************************
@@ -2881,6 +3313,29 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
}
out.Concurrently(i, func() graphql.Marshaler {
return rrm(innerCtx)
})
case "supergraph":
field := field
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Query_supergraph(ctx, field)
if res == graphql.Null {
atomic.AddUint32(&invalids, 1)
}
return res
}
rrm := func(ctx context.Context) graphql.Marshaler {
return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
}
out.Concurrently(i, func() graphql.Marshaler {
return rrm(innerCtx)
})
@@ -2971,6 +3426,83 @@ func (ec *executionContext) _SubGraph(ctx context.Context, sel ast.SelectionSet,
return out
}
var subGraphsImplementors = []string{"SubGraphs", "Supergraph"}
func (ec *executionContext) _SubGraphs(ctx context.Context, sel ast.SelectionSet, obj *model.SubGraphs) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, subGraphsImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("SubGraphs")
case "id":
out.Values[i] = ec._SubGraphs_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "minDelaySeconds":
out.Values[i] = ec._SubGraphs_minDelaySeconds(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "subGraphs":
out.Values[i] = ec._SubGraphs_subGraphs(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 unchangedImplementors = []string{"Unchanged", "Supergraph"}
func (ec *executionContext) _Unchanged(ctx context.Context, sel ast.SelectionSet, obj *model.Unchanged) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, unchangedImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("Unchanged")
case "id":
out.Values[i] = ec._Unchanged_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "minDelaySeconds":
out.Values[i] = ec._Unchanged_minDelaySeconds(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 __DirectiveImplementors = []string{"__Directive"}
func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler {
@@ -3324,6 +3856,21 @@ func (ec *executionContext) unmarshalNInputSubGraph2gitlabᚗcomᚋunboundsoftwa
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) {
res, err := graphql.UnmarshalInt(v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler {
res := graphql.MarshalInt(v)
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
}
return res
}
func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) {
res, err := graphql.UnmarshalString(v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -3397,6 +3944,16 @@ func (ec *executionContext) marshalNSubGraph2ᚖgitlabᚗcomᚋunboundsoftware
return ec._SubGraph(ctx, sel, v)
}
func (ec *executionContext) marshalNSupergraph2gitlabᚗcomᚋunboundsoftwareᚋschemasᚋgraphᚋmodelᚐSupergraph(ctx context.Context, sel ast.SelectionSet, v model.Supergraph) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._Supergraph(ctx, sel, v)
}
func (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) {
res, err := graphql.UnmarshalTime(v)
return res, graphql.ErrorOnPath(ctx, err)
+19
View File
@@ -6,6 +6,10 @@ import (
"time"
)
type Supergraph interface {
IsSupergraph()
}
type InputSubGraph struct {
Ref string `json:"ref"`
Service string `json:"service"`
@@ -23,3 +27,18 @@ type SubGraph struct {
ChangedBy string `json:"changedBy"`
ChangedAt time.Time `json:"changedAt"`
}
type SubGraphs struct {
ID string `json:"id"`
MinDelaySeconds int `json:"minDelaySeconds"`
SubGraphs []*SubGraph `json:"subGraphs"`
}
func (SubGraphs) IsSupergraph() {}
type Unchanged struct {
ID string `json:"id"`
MinDelaySeconds int `json:"minDelaySeconds"`
}
func (Unchanged) IsSupergraph() {}
+15 -1
View File
@@ -1,11 +1,25 @@
type Query {
subGraphs(ref: String!): [SubGraph!]! @hasApiKey
subGraphs(ref: String!): [SubGraph!]! @hasApiKey @deprecated(reason: "Use supergraph instead")
supergraph(ref: String!, isAfter: String): Supergraph! @hasApiKey
}
type Mutation {
updateSubGraph(input: InputSubGraph!): SubGraph! @hasApiKey
}
union Supergraph = Unchanged | SubGraphs
type Unchanged {
id: ID!
minDelaySeconds: Int!
}
type SubGraphs {
id: ID!
minDelaySeconds: Int!
subGraphs: [SubGraph!]!
}
type SubGraph {
id: ID!
service: String!
+13
View File
@@ -4,6 +4,7 @@ import (
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
"gitlab.com/unboundsoftware/schemas/domain"
"gitlab.com/unboundsoftware/schemas/graph/model"
)
func (r *Resolver) fetchSubGraph(subGraphId string) (*domain.SubGraph, error) {
@@ -14,3 +15,15 @@ func (r *Resolver) fetchSubGraph(subGraphId string) (*domain.SubGraph, error) {
}
return subGraph, nil
}
func (r *Resolver) toGqlSubGraph(subGraph *domain.SubGraph) *model.SubGraph {
return &model.SubGraph{
ID: subGraph.ID.String(),
Service: subGraph.Service,
URL: subGraph.Url,
WsURL: subGraph.WSUrl,
Sdl: subGraph.Sdl,
ChangedBy: subGraph.ChangedBy,
ChangedAt: subGraph.ChangedAt,
}
}
+36 -12
View File
@@ -5,6 +5,8 @@ package graph
import (
"context"
"fmt"
"strings"
"github.com/wundergraph/graphql-go-tools/pkg/federation/sdlmerge"
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
@@ -25,8 +27,12 @@ func (r *mutationResolver) UpdateSubGraph(ctx context.Context, input model.Input
if err != nil {
return nil, err
}
if strings.TrimSpace(input.Sdl) == strings.TrimSpace(subGraph.Sdl) {
return r.toGqlSubGraph(subGraph), nil
}
serviceSDLs := []string{input.Sdl}
for _, id := range r.Cache.Services(input.Ref) {
services, _ := r.Cache.Services(input.Ref, "")
for _, id := range services {
sg, err := r.fetchSubGraph(id)
if err != nil {
return nil, err
@@ -50,20 +56,34 @@ func (r *mutationResolver) UpdateSubGraph(ctx context.Context, input model.Input
if err != nil {
return nil, err
}
return &model.SubGraph{
ID: subGraph.ID.String(),
Service: subGraph.Service,
URL: subGraph.Url,
WsURL: subGraph.WSUrl,
Sdl: subGraph.Sdl,
ChangedBy: subGraph.ChangedBy,
ChangedAt: subGraph.ChangedAt,
}, nil
return r.toGqlSubGraph(subGraph), nil
}
// SubGraphs is the resolver for the subGraphs field.
func (r *queryResolver) SubGraphs(ctx context.Context, ref string) ([]*model.SubGraph, error) {
services := r.Cache.Services(ref)
res, err := r.Supergraph(ctx, ref, nil)
if err != nil {
return nil, err
}
if s, ok := res.(*model.SubGraphs); ok {
return s.SubGraphs, nil
}
return nil, fmt.Errorf("unexpected response")
}
// Supergraph is the resolver for the supergraph field.
func (r *queryResolver) Supergraph(ctx context.Context, ref string, isAfter *string) (model.Supergraph, error) {
after := ""
if isAfter != nil {
after = *isAfter
}
services, lastUpdate := r.Cache.Services(ref, after)
if after == lastUpdate {
return &model.Unchanged{
ID: lastUpdate,
MinDelaySeconds: 10,
}, nil
}
subGraphs := make([]*model.SubGraph, len(services))
for i, id := range services {
sg, err := r.fetchSubGraph(id)
@@ -80,7 +100,11 @@ func (r *queryResolver) SubGraphs(ctx context.Context, ref string) ([]*model.Sub
ChangedAt: sg.ChangedAt,
}
}
return subGraphs, nil
return &model.SubGraphs{
ID: lastUpdate,
SubGraphs: subGraphs,
MinDelaySeconds: 10,
}, nil
}
// Mutation returns generated.MutationResolver implementation.