Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public Expression<Func<TRoot, TRoot>> BuildNodeExpression<TRoot>(
var typeNode = new TypeNode(entityType.RuntimeType);
var selectionSet = selection.DeclaringOperation.GetSelectionSet(selection, entityType);
CollectSelections(context, selectionSet, typeNode);
AddAlwaysProjectedFields(typeNode, entityType);
dependencyMask = mask.Value;
root.TryAddNode(typeNode);

Expand Down Expand Up @@ -147,6 +148,7 @@ private void CollectTypes(Context context, Selection selection, TypeContainer pa
var possibleTypeNode = new TypeNode(possibleType.RuntimeType);
var possibleSelectionSet = selection.DeclaringOperation.GetSelectionSet(selection, possibleType);
CollectSelections(context, possibleSelectionSet, possibleTypeNode);
AddAlwaysProjectedFields(possibleTypeNode, possibleType);
parent.TryAddNode(possibleTypeNode);

if (possibleTypeNode.Nodes.Count == 0)
Expand All @@ -162,6 +164,7 @@ private void CollectTypes(Context context, Selection selection, TypeContainer pa
var typeNode = new TypeNode(objectType.RuntimeType);
var selectionSet = selection.DeclaringOperation.GetSelectionSet(selection, (ObjectType)namedType);
CollectSelections(context, selectionSet, typeNode);
AddAlwaysProjectedFields(typeNode, objectType);
parent.TryAddNode(typeNode);

if (typeNode.Nodes.Count == 0)
Expand Down Expand Up @@ -449,6 +452,11 @@ private void CollectSelection(
var field = selection.Field;
var namedType = field.Type.NamedType();

if (field.Flags.HasFlag(CoreFieldFlags.NotProjected))
{
return;
}

// A field is projectable if it has a pure member resolver before middleware is
// compiled and the member is declared on the parent runtime type, a base type, or
// an implemented interface. Middleware prevents the pure resolver from being used
Expand Down Expand Up @@ -505,6 +513,21 @@ private static bool IsLeafScalarAutoProperty(PropertyInfo property)
=> (property.PropertyType.IsValueType || property.PropertyType == typeof(string))
&& property.GetMethod?.GetCustomAttribute<CompilerGeneratedAttribute>() is not null;

private static void AddAlwaysProjectedFields(
TypeNode parent,
ObjectType selectionType)
{
foreach (var field in selectionType.Fields)
{
if (field.Flags.HasFlag(CoreFieldFlags.AlwaysProjected)
&& field.Type.NamedType().IsLeafType()
&& field.Member is PropertyInfo property)
{
parent.AddOrGetNode(property);
}
}
}

private static void TryAddAnyLeafField(
TypeNode parent,
ObjectType selectionType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@ internal enum CoreFieldFlags : long
MemberReplacement = 1L << 34,
UseV15MutationFieldNameFormat = 1L << 35,
MutationPayload = 1L << 36,
HasPureResolver = 1L << 37
HasPureResolver = 1L << 37,
AlwaysProjected = 1L << 38,
NotProjected = 1L << 39,
Comment thread
michaelstaib marked this conversation as resolved.
HasProjectionMiddleware = 1L << 40
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Runtime.CompilerServices;
using HotChocolate.Types.Descriptors.Configurations;

namespace HotChocolate.Types;

internal static class OutputFieldDefinitionExtensions
{
/// <summary>
/// Checks if all of the specified <paramref name="flags"/> are set on the field.
/// </summary>
public static bool HasCoreFieldFlags(this IOutputFieldDefinition field, CoreFieldFlags flags)
=> (Unsafe.As<FieldBase>(field).Flags & flags) == flags;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HotChocolate.Types;
using HotChocolate.Types.Descriptors.Configurations;

namespace HotChocolate.Data.Projections;

Expand All @@ -8,13 +9,13 @@ public static bool IsNotProjected(this IOutputFieldDefinition field)
=> field.IsExcludedManually() || field.HasProjectionMiddleware() || field.IsPagingField();

private static bool IsExcludedManually(this IOutputFieldDefinition field)
=> field.Features.Get<ProjectionFeature>()?.AlwaysProjected is false;
=> field.HasCoreFieldFlags(CoreFieldFlags.NotProjected);

public static bool IsAlwaysProjected(this IOutputFieldDefinition field)
=> field.Features.Get<ProjectionFeature>()?.AlwaysProjected is true;
=> field.HasCoreFieldFlags(CoreFieldFlags.AlwaysProjected);

public static bool HasProjectionMiddleware(this IOutputFieldDefinition field)
=> field.Features.Get<ProjectionFeature>()?.HasProjectionMiddleware is true;
=> field.HasCoreFieldFlags(CoreFieldFlags.HasProjectionMiddleware);

private static bool IsPagingField(this IOutputFieldDefinition field)
=> ((field.Flags & FieldFlags.Connection) == FieldFlags.Connection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ public static class ProjectionObjectFieldDescriptorExtensions

/// <summary>
/// <para>
/// Configure if this field should be projected by <see cref="UseProjection{T}"/> or if it
/// should be skipped
/// Configure if this field should be projected or if it should be skipped
/// </para>
/// <para>
/// if <paramref name="isProjected"/> is false, this field will never be projected even if
Expand All @@ -45,13 +44,19 @@ public static IObjectFieldDescriptor IsProjected(
{
ArgumentNullException.ThrowIfNull(descriptor);

descriptor
.Extend()
.OnBeforeCreate(
c => c.Features.Update<ProjectionFeature>(
f => f is null
? new ProjectionFeature(AlwaysProjected: isProjected)
: f with { AlwaysProjected = isProjected }));
var configuration = descriptor.Extend().Configuration;

if (isProjected)
{
configuration.Flags |= CoreFieldFlags.AlwaysProjected;
configuration.Flags &= ~CoreFieldFlags.NotProjected;
}
else
{
configuration.Flags |= CoreFieldFlags.NotProjected;
Comment thread
michaelstaib marked this conversation as resolved.
configuration.Flags &= ~CoreFieldFlags.AlwaysProjected;
}

return descriptor;
}

Expand Down Expand Up @@ -172,16 +177,7 @@ private static void CompileMiddleware(
var convention = context.DescriptorContext.GetProjectionConvention(scope);
RegisterOptimizer(definition, convention.CreateOptimizer());

var feature = definition.Features.Get<ProjectionFeature>();

if (feature is null)
{
definition.Features.Set(new ProjectionFeature(HasProjectionMiddleware: true));
}
else if (!feature.HasProjectionMiddleware)
{
definition.Features.Set(feature with { HasProjectionMiddleware = true });
}
definition.Flags |= CoreFieldFlags.HasProjectionMiddleware;

var factory = s_factoryTemplate.MakeGenericMethod(type);
var middleware = CreateDataMiddleware((IQueryBuilder)factory.Invoke(null, [convention])!);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,9 @@ public override void OnAfterCompleteName(
List<string>? alwaysProjected = null;
foreach (var field in objectTypeDefinition.Fields)
{
alwaysProjected ??= [];
if (field.GetFeatures().TryGet(out ProjectionFeature? feature)
&& feature.AlwaysProjected)
if (field.Flags.HasFlag(CoreFieldFlags.AlwaysProjected))
{
Comment thread
glen-84 marked this conversation as resolved.
alwaysProjected ??= [];
alwaysProjected.Add(field.Name);
}
}
Expand Down
Loading
Loading