diff --git a/src/HotChocolate/Data/src/AutoMapper/AutoMapperQueryableExtensions.cs b/src/HotChocolate/Data/src/AutoMapper/AutoMapperQueryableExtensions.cs index 9a48720b582..6ec6948af2e 100644 --- a/src/HotChocolate/Data/src/AutoMapper/AutoMapperQueryableExtensions.cs +++ b/src/HotChocolate/Data/src/AutoMapper/AutoMapperQueryableExtensions.cs @@ -38,7 +38,9 @@ public static IQueryable ProjectTo( QueryableProjectionVisitor.Default.Visit(visitorContext); +#pragma warning disable CS8631 Expression> projection = visitorContext.Project(); +#pragma warning restore CS8631 return queryable.ProjectTo(mapper.ConfigurationProvider, projection); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs b/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs index 1b8d74292fd..294d4abe739 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using HotChocolate.Execution.Processing; using HotChocolate.Resolvers; using HotChocolate.Types; @@ -38,7 +39,7 @@ public interface ISelectedField /// Gets the field selection for which a field resolver is /// being executed. /// - IFieldSelection Selection { get; } + ISelection Selection { get; } /// /// Gets the field on which the field resolver is being executed. diff --git a/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs b/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs index cf494393e46..53dad0fd8bc 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs @@ -27,7 +27,7 @@ internal SelectedField(IResolverContext resolverContext, ISelection selection) } /// - public IFieldSelection Selection => _selection; + public ISelection Selection => _selection; /// public IObjectField Field => Selection.Field; @@ -87,7 +87,7 @@ public bool IsSelected( return false; } - private IReadOnlyList? GetFieldSelections( + private IReadOnlyList? GetFieldSelections( ObjectType? type = null, bool allowInternals = false) { diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionConvention.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionConvention.cs index 3aee02a2483..2bd6ffb78e0 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionConvention.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionConvention.cs @@ -28,5 +28,5 @@ public interface IProjectionConvention : IConvention /// /// Returns the selection optimizer for this projection convention. /// - ISelectionOptimizer CreateOptimizer(); + ISelectionSetOptimizer CreateOptimizer(); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionProvider.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionProvider.cs index 0f785e784e3..62dd88ea385 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionProvider.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionProvider.cs @@ -31,6 +31,6 @@ public interface IProjectionProvider : IConvention /// Either a new rewritten selection or the same one if no rewriting was performed /// Selection RewriteSelection( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, Selection selection); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionConvention.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionConvention.cs index edbb3bf8e09..986a8ad682a 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionConvention.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionConvention.cs @@ -85,7 +85,7 @@ protected internal override void Complete(IConventionContext context) public FieldMiddleware CreateExecutor() => _provider.CreateExecutor(); - public ISelectionOptimizer CreateOptimizer() => + public ISelectionSetOptimizer CreateOptimizer() => new ProjectionOptimizer(_provider); private static IReadOnlyList CollectExtensions( diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs index 5e68a73fa1c..dd4612301f1 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs @@ -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++) diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs index 01ab8693800..06eb770f8fb 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs @@ -12,7 +12,7 @@ field.Field.Member is { } && field.Field.ContextData.ContainsKey(ContextArgumentNameKey); public Selection RewriteSelection( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, Selection selection) { var resolverPipeline = @@ -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; } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs index c70c9a2454a..e042b62aa66 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs @@ -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) @@ -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, @@ -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); } @@ -90,7 +93,7 @@ private static (string filedName, IObjectField field) TryGetObjectField(IPageTyp ErrorHelper.ProjectionVisitor_NodeFieldWasNotFound(type)); } - private IReadOnlyList CollectSelection(SelectionOptimizerContext context) + private IReadOnlyList CollectSelection(SelectionSetOptimizerContext context) { var selections = new List(); @@ -102,11 +105,11 @@ private IReadOnlyList CollectSelection(SelectionOptimizerContext } private static void CollectSelectionOfEdges( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, List 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) { @@ -124,11 +127,11 @@ edgeSubFieldNode.Name.Value is "node" && } private static void CollectSelectionOfItems( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, List 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) { @@ -138,11 +141,11 @@ private static void CollectSelectionOfItems( } private static void CollectSelectionOfNodes( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, List 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) { diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs index af72bc4a55e..d64c5def7a0 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs @@ -12,7 +12,7 @@ field.Field.Member is { } && field.Field.ContextData.ContainsKey(ContextArgumentNameKey); public Selection RewriteSelection( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, Selection selection) { var resolverPipeline = @@ -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; } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs index 2ecb1ef12ce..ca0e6b93646 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs @@ -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; diff --git a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs index ec232dee0e1..b783734a3e7 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs @@ -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; } @@ -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; @@ -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; diff --git a/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs index 2cc9cdb6f65..8a95bcc06de 100644 --- a/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs @@ -4,7 +4,7 @@ namespace HotChocolate.Data.Projections; -public class ProjectionOptimizer : ISelectionOptimizer +public class ProjectionOptimizer : ISelectionSetOptimizer { private readonly IProjectionProvider _provider; @@ -13,34 +13,20 @@ public ProjectionOptimizer(IProjectionProvider provider) _provider = provider; } - public void OptimizeSelectionSet(SelectionOptimizerContext context) + public void OptimizeSelectionSet(SelectionSetOptimizerContext context) { - var processedFields = new HashSet(); - while (!processedFields.SetEquals(context.Fields.Keys)) + var processedSelections = new HashSet(); + while (!processedSelections.SetEquals(context.Selections.Keys)) { - var fieldsToProcess = new HashSet(context.Fields.Keys); - fieldsToProcess.ExceptWith(processedFields); - foreach (var field in fieldsToProcess) + var selectionToProcess = new HashSet(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; - } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs index 886a813889b..4222ab7f8e2 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs @@ -23,6 +23,6 @@ public interface IProjectionOptimizer /// Returns either the original or a rewritten version of it /// Selection RewriteSelection( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, Selection selection); } diff --git a/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionConventionExtensionsTests.cs b/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionConventionExtensionsTests.cs index 95e4a5d89b9..cb478afcc0c 100644 --- a/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionConventionExtensionsTests.cs +++ b/src/HotChocolate/Data/test/Data.Projections.Tests/ProjectionConventionExtensionsTests.cs @@ -124,7 +124,7 @@ public FieldMiddleware CreateExecutor() } public Selection RewriteSelection( - SelectionOptimizerContext context, + SelectionSetOptimizerContext context, Selection selection) { throw new NotImplementedException(); @@ -133,8 +133,7 @@ public Selection RewriteSelection( private sealed class MockProjectionConvention : ProjectionConvention { - public MockProjectionConvention( - Action configure) + public MockProjectionConvention(Action configure) : base(configure) { } diff --git a/src/HotChocolate/Filters/src/Types.Filters/QueryableFilterMiddleware.cs b/src/HotChocolate/Filters/src/Types.Filters/QueryableFilterMiddleware.cs index 5e93e1c92f6..b1f9bb5be2f 100644 --- a/src/HotChocolate/Filters/src/Types.Filters/QueryableFilterMiddleware.cs +++ b/src/HotChocolate/Filters/src/Types.Filters/QueryableFilterMiddleware.cs @@ -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(