Skip to content

Commit

Permalink
Fix/planning interfaces with entity implementations (#624)
Browse files Browse the repository at this point in the history
  • Loading branch information
devsergiy authored Oct 25, 2023
2 parents 4053758 + 3f24929 commit b4e3ab1
Show file tree
Hide file tree
Showing 33 changed files with 5,005 additions and 1,613 deletions.
7 changes: 7 additions & 0 deletions v2/pkg/ast/ast_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,10 @@ func (d *Document) FieldsAreEqualFlat(left, right int) bool {
d.ArgumentSetsAreEquals(d.FieldArguments(left), d.FieldArguments(right)) && // arguments
d.DirectiveSetsAreEqual(d.FieldDirectives(left), d.FieldDirectives(right)) // directives
}

func (d *Document) FieldSelectionSet(ref int) (selectionSetRef int, ok bool) {
if !d.Fields[ref].HasSelections {
return InvalidRef, false
}
return d.Fields[ref].SelectionSet, true
}
4 changes: 4 additions & 0 deletions v2/pkg/ast/ast_field_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ func (d *Document) FieldDefinitionTypeNameString(ref int) string {
return d.ResolveTypeNameString(d.FieldDefinitions[ref].Type)
}

func (d *Document) FieldDefinitionTypeNameBytes(ref int) ByteSlice {
return d.ResolveTypeNameBytes(d.FieldDefinitions[ref].Type)
}

func (d *Document) FieldDefinitionTypeNode(ref int) Node {
typeName := d.ResolveTypeNameBytes(d.FieldDefinitions[ref].Type)
node, _ := d.Index.FirstNodeByNameBytes(typeName)
Expand Down
7 changes: 7 additions & 0 deletions v2/pkg/ast/ast_inline_fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,10 @@ func (d *Document) AddInlineFragment(fragment InlineFragment) int {
func (d *Document) InlineFragmentIsOfTheSameType(ref int) bool {
return d.InlineFragments[ref].IsOfTheSameType
}

func (d *Document) InlineFragmentSelectionSet(ref int) (selectionSetRef int, ok bool) {
if !d.InlineFragments[ref].HasSelections {
return InvalidRef, false
}
return d.InlineFragments[ref].SelectionSet, true
}
20 changes: 20 additions & 0 deletions v2/pkg/ast/ast_interface_type_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,23 @@ func (d *Document) InterfaceTypeDefinitionFieldWithName(ref int, fieldName []byt
}
return InvalidRef, false
}

func (d *Document) InterfaceTypeDefinitionImplementedByObjectWithNames(interfaceDefRef int) (typeNames []string, ok bool) {
implementedByNodes := d.InterfaceTypeDefinitionImplementedByRootNodes(interfaceDefRef)

typeNames = make([]string, 0, len(implementedByNodes))
for _, implementedByNode := range implementedByNodes {
if implementedByNode.Kind != NodeKindObjectTypeDefinition {
continue
}

typeNames = append(typeNames, implementedByNode.NameString(d))
}

if len(typeNames) > 0 {
return typeNames, true

}

return nil, false
}
35 changes: 35 additions & 0 deletions v2/pkg/ast/ast_selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ func (d *Document) AddSelection(set int, selection Selection) {
d.SelectionSets[set].SelectionRefs = append(d.SelectionSets[set].SelectionRefs, d.AddSelectionToDocument(selection))
}

func (d *Document) AddSelectionRefToSelectionSet(set int, selectionRef int) {
d.SelectionSets[set].SelectionRefs = append(d.SelectionSets[set].SelectionRefs, selectionRef)
}

func (d *Document) EmptySelectionSet(ref int) {
d.SelectionSets[ref].SelectionRefs = d.SelectionSets[ref].SelectionRefs[:0]
}
Expand Down Expand Up @@ -202,3 +206,34 @@ func (d *Document) SelectionSetHasFieldSelectionWithExactName(set int, name []by
}
return false, InvalidRef
}

func (d *Document) SelectionSetFieldSelections(set int) (refs []int) {
for _, selectionRef := range d.SelectionSets[set].SelectionRefs {
if d.Selections[selectionRef].Kind == SelectionKindField {
refs = append(refs, selectionRef)
}
}
return
}

func (d *Document) SelectionSetInlineFragmentSelections(set int) (refs []int) {
for _, selectionRef := range d.SelectionSets[set].SelectionRefs {
if d.Selections[selectionRef].Kind == SelectionKindInlineFragment {
refs = append(refs, selectionRef)
}
}
return
}

func (d *Document) SelectionKind(ref int) SelectionKind {
return d.Selections[ref].Kind
}

func (d *Document) SelectionSetFieldNames(set int) (fieldNames []string) {
fieldSelections := d.SelectionSetFieldSelections(set)
fieldNames = make([]string, 0, len(fieldSelections))
for _, fieldSelectionRef := range fieldSelections {
fieldNames = append(fieldNames, d.FieldNameString(d.Selections[fieldSelectionRef].Ref))
}
return
}
12 changes: 12 additions & 0 deletions v2/pkg/ast/ast_union_type_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,15 @@ func (d *Document) ImportUnionTypeDefinitionWithDirectives(name, description str

return
}

func (d *Document) UnionTypeDefinitionMemberTypeNames(ref int) (typeNames []string, ok bool) {
if !d.UnionTypeDefinitions[ref].HasUnionMemberTypes {
return nil, false
}

typeNames = make([]string, 0, len(d.UnionTypeDefinitions[ref].UnionMemberTypes.Refs))
for _, typeRef := range d.UnionTypeDefinitions[ref].UnionMemberTypes.Refs {
typeNames = append(typeNames, d.TypeNameString(typeRef))
}
return typeNames, true
}
74 changes: 58 additions & 16 deletions v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,58 @@ type Planner struct {
addedInlineFragments map[onTypeInlineFragment]struct{}
hasFederationRoot bool
extractEntities bool

// tmp
upstreamSchema *ast.Document
}

type onTypeInlineFragment struct {
TypeCondition string
SelectionSet int
}

func (p *Planner) UpstreamSchema(dataSourceConfig plan.DataSourceConfiguration) *ast.Document {
if p.upstreamSchema != nil {
return p.upstreamSchema
}

var config Configuration

err := json.Unmarshal(dataSourceConfig.Custom, &config)
if err != nil {
panic(err)
}

definition := ast.NewDocument()
definitionParser := astparser.NewParser()
report := &operationreport.Report{}

if config.Federation.Enabled {
federationSchema, err := federation.BuildFederationSchema(config.UpstreamSchema, config.Federation.ServiceSDL)
if err != nil {
panic(err)
}
definition.Input.ResetInputString(federationSchema)
definitionParser.Parse(definition, report)
if report.HasErrors() {
panic(report)
}
} else {
definition.Input.ResetInputString(config.UpstreamSchema)
definitionParser.Parse(definition, report)
if report.HasErrors() {
panic(report)
}

if err := asttransform.MergeDefinitionWithBaseSchema(definition); err != nil {
panic(fmt.Errorf("unable to merge upstream schema with base schema: %v", err))
}
}

p.upstreamSchema = definition
return definition
}

func (p *Planner) SetID(id int) {
p.id = id
}
Expand Down Expand Up @@ -318,7 +363,7 @@ func (p *Planner) Register(visitor *plan.Visitor, configuration plan.DataSourceC
return nil
}

func (p *Planner) ConfigureFetch() plan.FetchConfiguration {
func (p *Planner) ConfigureFetch() resolve.FetchConfiguration {
var input []byte
input = httpclient.SetInputBodyWithPath(input, p.upstreamVariables, "variables")
input = httpclient.SetInputBodyWithPath(input, p.printOperation(), "query")
Expand All @@ -344,15 +389,16 @@ func (p *Planner) ConfigureFetch() plan.FetchConfiguration {
}
}

return plan.FetchConfiguration{
return resolve.FetchConfiguration{
Input: string(input),
DataSource: &Source{
httpClient: p.fetchClient,
},
Variables: p.variables,
DisallowSingleFlight: p.disallowSingleFlight,
RequiresSerialFetch: p.requiresSerialFetch(),
RequiresBatchFetch: p.requiresBatchFetch(),
RequiresEntityFetch: p.requiresEntityFetch(),
RequiresEntityBatchFetch: p.requiresEntityBatchFetch(),
PostProcessing: postProcessing,
SetTemplateOutputToNullOnVariableNull: p.extractEntities,
}
Expand All @@ -378,12 +424,12 @@ func (p *Planner) requiresSerialFetch() bool {
return false
}

func (p *Planner) requiresBatchFetch() bool {
if !p.dataSourcePlannerConfig.HasRequiredFields() {
return false
}
func (p *Planner) requiresEntityFetch() bool {
return p.dataSourcePlannerConfig.HasRequiredFields() && p.dataSourcePlannerConfig.PathType == plan.PlannerPathObject
}

return p.dataSourcePlannerConfig.PathType != plan.PlannerPathObject
func (p *Planner) requiresEntityBatchFetch() bool {
return p.dataSourcePlannerConfig.HasRequiredFields() && p.dataSourcePlannerConfig.PathType != plan.PlannerPathObject
}

func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration {
Expand Down Expand Up @@ -750,16 +796,9 @@ func (p *Planner) addRepresentationsVariable() {
}

func (p *Planner) buildRepresentationsVariable() resolve.Variable {
isArrayItems := p.dataSourcePlannerConfig.PathType != plan.PlannerPathObject

uniqTypes := p.dataSourcePlannerConfig.RequiredFields.UniqueTypes()
if len(uniqTypes) > 1 && !isArrayItems {
p.stopWithError("unhandled case: more than one type requirements for non-array path type")
}

objects := make([]*resolve.Object, 0, len(p.dataSourcePlannerConfig.RequiredFields))
for _, cfg := range p.dataSourcePlannerConfig.RequiredFields {
node, err := buildRepresentationVariableNode(cfg, p.visitor.Definition, false, isArrayItems)
node, err := buildRepresentationVariableNode(cfg, p.visitor.Definition)
if err != nil {
p.visitor.Walker.StopWithInternalErr(err)
return nil
Expand Down Expand Up @@ -1269,6 +1308,9 @@ func (p *Planner) printQueryPlan(operation *ast.Document) {

args := []interface{}{
"Execution plan:\n",
"Planner path: ",
p.dataSourcePlannerConfig.ParentPath,
"\n",
}

if len(p.upstreamVariables) > 0 {
Expand Down
Loading

0 comments on commit b4e3ab1

Please sign in to comment.