Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/EntityGraphQL/Compiler/EntityGraphQLQueryWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,40 @@ protected override void VisitFragmentDefinition(FragmentDefinitionNode node, IGr
base.VisitFragmentDefinition(node, fragDef);
}

protected override void VisitInlineFragment(InlineFragmentNode node, IGraphQLNode? context)
{
if (context == null)
throw new EntityGraphQLCompilerException("context should not be null visiting inline fragment");

if (node.TypeCondition is not null && context is not null)
{
var type = schemaProvider.GetSchemaType(node.TypeCondition.Name.Value, requestContext);
if (type != null)
{
var fragParameter = Expression.Parameter(type.TypeDotnet, $"frag_{type.Name}");
var newContext = new GraphQLListSelectionField((GraphQLListSelectionField)context!, fragParameter);
base.VisitInlineFragment(node, newContext);

//copy the fragment fields over to the select context and cast the type so we can access the property
foreach (var queryField in newContext.QueryFields)
{
var resolveExpression = Expression.Condition(
test: Expression.TypeIs(context.NextFieldContext, type.TypeDotnet),
ifTrue: Expression.Property(Expression.Convert(context.NextFieldContext, type.TypeDotnet), queryField.Name),
ifFalse: Expression.Default(queryField.NextFieldContext?.Type)
);

var fieldResult = new GraphQLScalarField(schemaProvider, queryField.Field, queryField.Name, resolveExpression!, queryField.NextFieldContext as ParameterExpression ?? context.RootParameter, context, queryField.Arguments as Dictionary<string, object>);
context.AddField(fieldResult);
}
}
else
{
base.VisitInlineFragment(node, context);
}
}
}

protected override void VisitFragmentSpread(FragmentSpreadNode node, IGraphQLNode? context)
{
if (context == null)
Expand Down
11 changes: 11 additions & 0 deletions src/EntityGraphQL/Compiler/GqlNodes/BaseGraphQLField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ public BaseGraphQLField(ISchemaProvider schema, IField? field, string name, Expr
Field = field;
}

public BaseGraphQLField(BaseGraphQLField context, Expression? nextFieldContext)
{
Name = context.Name;
NextFieldContext = nextFieldContext;
RootParameter = context.RootParameter;
ParentNode = context.ParentNode;
this.Arguments = context.Arguments ?? new Dictionary<string, object>();
this.schema = context.schema;
Field = context.Field;
}

/// <summary>
/// Field is a complex expression (using a method or function) that returns a single object (not IEnumerable)
/// We wrap this is a function that does a null check and avoid duplicate calls on the method/service
Expand Down
5 changes: 5 additions & 0 deletions src/EntityGraphQL/Compiler/GqlNodes/BaseGraphQLQueryField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ protected BaseGraphQLQueryField(ISchemaProvider schema, IField? field, string na
{
}

protected BaseGraphQLQueryField(BaseGraphQLQueryField context, Expression? nextFieldContext)
: base(context, nextFieldContext)
{
}

public override IEnumerable<BaseGraphQLField> Expand(CompileContext compileContext, List<GraphQLFragmentStatement> fragments, bool withoutServiceFields, Expression fieldContext, ParameterExpression? docParam, object? docVariables)
{
var result = ProcessFieldDirectives(this, docParam, docVariables);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public GraphQLListSelectionField(ISchemaProvider schema, IField? field, string n
this.ListExpression = nodeExpression;
}

public GraphQLListSelectionField(GraphQLListSelectionField context, ParameterExpression? nextFieldContext)
: base(context, nextFieldContext)
{
this.ListExpression = context.ListExpression;
}

/// <summary>
/// The dotnet Expression for this node. Could be as simple as (Person p) => p.Name
/// Or as complex as (DbContext ctx) => ctx.People.Where(...).Select(p => new {...}).First()
Expand Down
38 changes: 38 additions & 0 deletions src/tests/EntityGraphQL.Tests/QueryTests/QueryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using EntityGraphQL.Tests.ApiVersion1;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.EntityFrameworkCore;

namespace EntityGraphQL.Tests
{
Expand Down Expand Up @@ -356,6 +357,37 @@ public void TestInheritance()
name
}
}");
var context = new TestAbstractDataContext();
context.Animals.Add(new Dog() { Name = "steve", HasBone = true });
context.Animals.Add(new Cat() { Name = "george", Lives = 9 });

var qr = gql.ExecuteQuery(context, null, null);
dynamic animals = (dynamic)qr.Data["animals"];
// we only have the fields requested
Assert.Equal(2, animals.Count);

Assert.Equal("Dog", animals[0].__typename);
Assert.Equal("Cat", animals[1].__typename);
}

[Fact]
public void TestInheritanceExtraFields()
{
var schemaProvider = new TestAbstractDataGraphSchema();
var gql = new GraphQLCompiler(schemaProvider).Compile(@"
query {
animals {
__typename
name
... on Cat {
lives
}
...on Dog {
hasBone
}
}
}
");

var context = new TestAbstractDataContext();
context.Animals.Add(new Dog() { Name = "steve", HasBone = true });
Expand All @@ -367,7 +399,13 @@ public void TestInheritance()
Assert.Equal(2, animals.Count);

Assert.Equal("Dog", animals[0].__typename);
Assert.Equal("steve", animals[0].name);
Assert.True(animals[0].hasBone);
Assert.Equal("Cat", animals[1].__typename);
Assert.Equal("george", animals[1].name);
Assert.Equal(9, animals[1].lives);
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ public TestAbstractDataGraphSchema()
var animal = AddInterface<Animal>(name: "Animal", description: "An animal");
animal.AddAllFields();

AddInheritedType<Dog>(name: "Dog", "", baseType: "Animal");
AddInheritedType<Cat>(name: "Cat", "", baseType: "Animal");
AddInheritedType<Dog>(name: "Dog", "", baseType: "Animal").AddAllFields();
AddInheritedType<Cat>(name: "Cat", "", baseType: "Animal").AddAllFields();

UpdateQuery(query =>
{
query.AddField(ctx => ctx.Animals, "All animals in the world");
});
});

}
}
}
Expand Down