Implementing an @export directive
See original GitHub issueI want to implement an @export
directive. This would export the value of a field into a variable that can be used in another part of the query (discussed here and here). I have read the documentation about implementing a directive, from here.
Here is an example of how this would work:
query($cid : Int!, $ano : Int!, $customerId : Int)
{
useCompany(no: $cid)
{
associate(filter : {associateNo : {_eq: $ano}})
{
items
{
customerNo @export(as: "customerId")
}
}
order(first : 5, filter : {customerNo : {_eq : $customerId}})
{
items
{
orderNo
orderDate
customerNo
}
}
}
}
Here, I first execute a query that retrieves a customer ID and then this is used in a second query to fetch some orders of that customer.
I defined a directive as follows:
internal class ExportDirective : Directive
{
public ExportDirective() :
base("export", DirectiveLocation.Field, DirectiveLocation.FragmentSpread, DirectiveLocation.InlineFragment)
{
Description = "Export the value of a field into a variable that can be used somewhere else in the query.";
Arguments = new QueryArguments(
new QueryArgument<StringGraphType>
{
Name = "as",
Description = "The name of the exported variable"
});
}
}
And a visitor as follows:
internal class ExportDirectiveVisitor : BaseSchemaNodeVisitor
{
public override void VisitObjectFieldDefinition(FieldType field, IObjectGraphType type, ISchema schema)
{
var applied = field.FindAppliedDirective("export");
if (applied != null)
{
var inner = field.Resolver ?? NameFieldResolver.Instance;
field.Resolver = new FuncFieldResolver<object>(async context =>
{
object result = await inner.ResolveAsync(context);
var arg = applied.FindArgument("as");
var exportName = arg?.Name;
if (!string.IsNullOrEmpty(exportName))
{
var value = context.Variables.ValueFor(exportName);
if (value is null)
{
context.Variables.Add(new Variable(exportName) { Value = result });
}
}
return result;
});
}
}
}
(Ignore the actual details of this implementation. Might not be correct or complete, but I didn’t get a chance to test it.)
I registered them with the schema:
public class MySchema : Schema
{
public MySchema(IServiceProvider provider)
: base(provider)
{
Directives.Register(new ExportDirective());
RegisterVisitor(new ExportDirectiveVisitor());
}
}
The visitor executes when I start the app and the schema is created. But this is not what I want. I want this to be evaluated every time I run a query. What do I have to do for that?
Issue Analytics
- State:
- Created a year ago
- Comments:23 (14 by maintainers)
I also don’t quite understand why the delay nodes execute before exhausting the main loop. I had expected your code to execute all the regular nodes first, then all the data loader nodes, then if the prior loops are satisfied, all the delayed nodes. Something like this:
You may be able to considerably reduce the amount of code in your class with that logic, if it works correctly.
Excellent suggestion, the state can be anything here. Yes, I tried it an it works so I can remove some unnecessary code.