Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate HotChocolate.Data to new selections #5178

Merged
merged 13 commits into from
Jun 27, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ public static IQueryable<TResult> ProjectTo<TSource, TResult>(

QueryableProjectionVisitor.Default.Visit(visitorContext);

#pragma warning disable CS8631
Expression<Func<TResult, object?>> projection = visitorContext.Project<TResult, object?>();
#pragma warning restore CS8631

return queryable.ProjectTo(mapper.ConfigurationProvider, projection);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using HotChocolate.Execution.Processing;
using HotChocolate.Resolvers;
using HotChocolate.Types;

Expand Down Expand Up @@ -38,7 +39,7 @@ public interface ISelectedField
/// Gets the field selection for which a field resolver is
/// being executed.
/// </summary>
IFieldSelection Selection { get; }
ISelection Selection { get; }

/// <summary>
/// Gets the field on which the field resolver is being executed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal SelectedField(IResolverContext resolverContext, ISelection selection)
}

/// <inheritdoc />
public IFieldSelection Selection => _selection;
public ISelection Selection => _selection;

/// <inheritdoc />
public IObjectField Field => Selection.Field;
Expand Down Expand Up @@ -87,7 +87,7 @@ public bool IsSelected(
return false;
}

private IReadOnlyList<IFieldSelection>? GetFieldSelections(
private IReadOnlyList<ISelection>? GetFieldSelections(
ObjectType? type = null,
bool allowInternals = false)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ public interface IProjectionConvention : IConvention
/// <returns>
/// Returns the selection optimizer for this projection convention.
/// </returns>
ISelectionOptimizer CreateOptimizer();
ISelectionSetOptimizer CreateOptimizer();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public interface IProjectionProvider : IConvention
/// Either a new rewritten selection or the same one if no rewriting was performed
/// </returns>
Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection);
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ protected internal override void Complete(IConventionContext context)
public FieldMiddleware CreateExecutor<TEntityType>() =>
_provider.CreateExecutor<TEntityType>();

public ISelectionOptimizer CreateOptimizer() =>
public ISelectionSetOptimizer CreateOptimizer() =>
new ProjectionOptimizer(_provider);

private static IReadOnlyList<IProjectionProviderExtension> CollectExtensions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ protected internal override void Complete(IConventionContext context)
}

public Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection)
{
for (var i = 0; i < _optimizer.Count; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ field.Field.Member is { } &&
field.Field.ContextData.ContainsKey(ContextArgumentNameKey);

public Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection)
{
var resolverPipeline =
Expand All @@ -31,18 +31,8 @@ static FieldDelegate WrappedPipeline(FieldDelegate next) =>

resolverPipeline = WrappedPipeline(resolverPipeline);

var compiledSelection = new Selection(
context.GetNextId(),
context.Type,
selection.Field,
selection.Field.Type,
selection.SyntaxNode,
selection.ResponseName,
resolverPipeline,
arguments: selection.Arguments,
isInternal: false);

context.Fields[compiledSelection.ResponseName] = compiledSelection;
return compiledSelection;
context.SetResolver(selection, resolverPipeline);

return selection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ field.DeclaringType is IPageType &&
field.Field.Name.Value is "edges" or "items" or "nodes";

public Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection)
{
if (context.Type.NamedType() is not IPageType pageType)
Expand All @@ -30,18 +30,21 @@ public Selection RewriteSelection(

var selections = CollectSelection(context);

context.Fields[CombinedEdgeField] =
CreateCombinedSelection(context,
var combinedSelection =
CreateCombinedSelection(
context,
selection,
selection.DeclaringType,
pageType,
selections);

context.AddSelection(CombinedEdgeField, combinedSelection);

return selection;
}

private Selection CreateCombinedSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
ISelection selection,
IObjectType declaringType,
IPageType pageType,
Expand All @@ -63,13 +66,13 @@ private Selection CreateCombinedSelection(
context.CompileResolverPipeline(nodesField, combinedField);

return new Selection(
context.GetNextId(),
context.GetNextSelectionId(),
declaringType,
nodesField,
nodesField.Type,
combinedField,
CombinedEdgeField,
nodesPipeline,
resolverPipeline: nodesPipeline,
arguments: selection.Arguments,
isInternal: true);
}
Expand All @@ -90,7 +93,7 @@ private static (string filedName, IObjectField field) TryGetObjectField(IPageTyp
ErrorHelper.ProjectionVisitor_NodeFieldWasNotFound(type));
}

private IReadOnlyList<ISelectionNode> CollectSelection(SelectionOptimizerContext context)
private IReadOnlyList<ISelectionNode> CollectSelection(SelectionSetOptimizerContext context)
{
var selections = new List<ISelectionNode>();

Expand All @@ -102,11 +105,11 @@ private IReadOnlyList<ISelectionNode> CollectSelection(SelectionOptimizerContext
}

private static void CollectSelectionOfEdges(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
List<ISelectionNode> selections)
{
if (context.Fields.Values
.FirstOrDefault(x => x.Field.Name == "edges") is { } edgeSelection)
if (context.Selections.Values
.FirstOrDefault(x => x.Field.Name == "edges") is { } edgeSelection)
{
foreach (var edgeSubField in edgeSelection.SelectionSet!.Selections)
{
Expand All @@ -124,11 +127,11 @@ edgeSubFieldNode.Name.Value is "node" &&
}

private static void CollectSelectionOfItems(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
List<ISelectionNode> selections)
{
if (context.Fields.Values
.FirstOrDefault(x => x.Field.Name == "items") is { } itemSelection)
if (context.Selections.Values
.FirstOrDefault(x => x.Field.Name == "items") is { } itemSelection)
{
foreach (var nodeField in itemSelection.SelectionSet!.Selections)
{
Expand All @@ -138,11 +141,11 @@ private static void CollectSelectionOfItems(
}

private static void CollectSelectionOfNodes(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
List<ISelectionNode> selections)
{
if (context.Fields.Values
.FirstOrDefault(x => x.Field.Name == "nodes") is { } nodeSelection)
if (context.Selections.Values
.FirstOrDefault(x => x.Field.Name == "nodes") is { } nodeSelection)
{
foreach (var nodeField in nodeSelection.SelectionSet!.Selections)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ field.Field.Member is { } &&
field.Field.ContextData.ContainsKey(ContextArgumentNameKey);

public Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection)
{
var resolverPipeline =
Expand All @@ -28,18 +28,8 @@ static FieldDelegate WrappedPipeline(FieldDelegate next) =>

resolverPipeline = WrappedPipeline(resolverPipeline);

var compiledSelection = new Selection(
context.GetNextId(),
context.Type,
selection.Field,
selection.Field.Type,
selection.SyntaxNode,
selection.ResponseName,
resolverPipeline,
arguments: selection.Arguments,
isInternal: false);
context.SetResolver(selection, resolverPipeline);

context.Fields[compiledSelection.ResponseName] = compiledSelection;
return compiledSelection;
return selection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
using System.Linq.Expressions;
using HotChocolate.Data.Projections.Expressions.Handlers;
using HotChocolate.Execution.Processing;
using HotChocolate.Language;
using HotChocolate.Resolvers;
using HotChocolate.Types;

namespace HotChocolate.Data.Projections.Expressions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ field.DeclaringType is ObjectType objectType &&
objectType.ContextData.ContainsKey(AlwaysProjectedFieldsKey);

public Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection)
{
if (!(context.Type is ObjectType type &&
type.ContextData.TryGetValue(AlwaysProjectedFieldsKey, out var fieldsObj) &&
fieldsObj is string[] fields))
type.ContextData.TryGetValue(AlwaysProjectedFieldsKey, out var fieldsObj) &&
fieldsObj is string[] fields))
{
return selection;
}
Expand All @@ -29,14 +29,14 @@ public Selection RewriteSelection(
var alias = "__projection_alias_" + i;

// if the field is already in the selection set we do not need to project it
if (context.Fields.TryGetValue(fields[i], out var field) &&
if (context.Selections.TryGetValue(fields[i], out var field) &&
field.Field.Name == fields[i])
{
continue;
}

// if the field is already added as an alias we do not need to add it
if (context.Fields.TryGetValue(alias, out field) &&
if (context.Selections.TryGetValue(alias, out field) &&
field.Field.Name == fields[i])
{
continue;
Expand All @@ -55,17 +55,17 @@ public Selection RewriteSelection(
var nodesPipeline = context.CompileResolverPipeline(nodesField, nodesFieldNode);

var compiledSelection = new Selection(
context.GetNextId(),
context.GetNextSelectionId(),
context.Type,
nodesField,
nodesField.Type,
nodesFieldNode,
alias,
nodesPipeline,
resolverPipeline: nodesPipeline,
arguments: selection.Arguments,
isInternal: true);

context.Fields[alias] = compiledSelection;
context.AddSelection(alias, compiledSelection);
}

return selection;
Expand Down
36 changes: 11 additions & 25 deletions src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace HotChocolate.Data.Projections;

public class ProjectionOptimizer : ISelectionOptimizer
public class ProjectionOptimizer : ISelectionSetOptimizer
{
private readonly IProjectionProvider _provider;

Expand All @@ -13,34 +13,20 @@ public ProjectionOptimizer(IProjectionProvider provider)
_provider = provider;
}

public void OptimizeSelectionSet(SelectionOptimizerContext context)
public void OptimizeSelectionSet(SelectionSetOptimizerContext context)
{
var processedFields = new HashSet<string>();
while (!processedFields.SetEquals(context.Fields.Keys))
var processedSelections = new HashSet<string>();
while (!processedSelections.SetEquals(context.Selections.Keys))
{
var fieldsToProcess = new HashSet<string>(context.Fields.Keys);
fieldsToProcess.ExceptWith(processedFields);
foreach (var field in fieldsToProcess)
var selectionToProcess = new HashSet<string>(context.Selections.Keys);
selectionToProcess.ExceptWith(processedSelections);
foreach (var responseName in selectionToProcess)
{
context.Fields[field] =
_provider.RewriteSelection(context, context.Fields[field]);
processedFields.Add(field);
var rewrittenSelection =
_provider.RewriteSelection(context, context.Selections[responseName]);
context.ReplaceSelection(responseName, rewrittenSelection);
processedSelections.Add(responseName);
}
}
}

public bool AllowFragmentDeferral(
SelectionOptimizerContext context,
InlineFragmentNode fragment)
{
return false;
}

public bool AllowFragmentDeferral(
SelectionOptimizerContext context,
FragmentSpreadNode fragmentSpread,
FragmentDefinitionNode fragmentDefinition)
{
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public interface IProjectionOptimizer
/// Returns either the original <paramref name="selection"/> or a rewritten version of it
/// </returns>
Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection);
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public FieldMiddleware CreateExecutor<TEntityType>()
}

public Selection RewriteSelection(
SelectionOptimizerContext context,
SelectionSetOptimizerContext context,
Selection selection)
{
throw new NotImplementedException();
Expand All @@ -133,8 +133,7 @@ public Selection RewriteSelection(

private sealed class MockProjectionConvention : ProjectionConvention
{
public MockProjectionConvention(
Action<IProjectionConventionDescriptor> configure)
public MockProjectionConvention(Action<IProjectionConventionDescriptor> configure)
: base(configure)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public async Task InvokeAsync(IMiddlewareContext context)
}

if (source is not null &&
context.Field.Arguments[_contextData.ArgumentName].Type is InputObjectType iot &&
context.Selection.Arguments[_contextData.ArgumentName].Type is InputObjectType iot &&
iot is IFilterInputType fit)
{
var visitorContext = new QueryableFilterVisitorContext(
Expand Down