Skip to content

Commit

Permalink
edits
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Aug 23, 2023
1 parent 19f7c56 commit 9ff9d34
Show file tree
Hide file tree
Showing 17 changed files with 380 additions and 87 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Runtime.CompilerServices;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using HotChocolate.Language;
using HotChocolate.Skimmed;
Expand Down Expand Up @@ -35,19 +35,32 @@ public ValueTask EnrichAsync(
{
var typeName = splits[1];
var fieldName = splits[3];
var isList = entityResolver.Type.IsListType();

if (typeName.Equals(originalTypeName, OrdinalIgnoreCase))
if (!isList && typeName.Equals(originalTypeName, OrdinalIgnoreCase))
{
var field = type.Fields.FirstOrDefault(f => f.Name.Equals(fieldName, OrdinalIgnoreCase));
if (field is not null)
{
TryRegisterEntityResolver(entity, type, entityResolver, field, schema);
}
}
else if (typeName.Length - 1 == originalTypeName.Length &&
typeName.AsSpan()[typeName.Length - 1] == 's')
else if (isList && typeName.Equals(originalTypeName, OrdinalIgnoreCase) ||
(typeName.Length - 1 == originalTypeName.Length &&
typeName.AsSpan()[typeName.Length - 1] == 's'))
{
var field = type.Fields.FirstOrDefault(f => f.Name.Equals(fieldName, OrdinalIgnoreCase));

if (field is null)
{
var fieldPlural = fieldName[..^1];
field = type.Fields.FirstOrDefault(f => f.Name.Equals(fieldPlural, OrdinalIgnoreCase));
}

if (field is not null)
{
TryRegisterBatchEntityResolver(entity, type, entityResolver, field, schema);
}
}
}
}
Expand All @@ -63,12 +76,14 @@ private static void TryRegisterEntityResolver(
OutputField keyField,
Schema schema)
{
// Check if the query field type matches the entity type
// and if it has any arguments that contain the @is directive
if (entityResolverField.Arguments.Count == 1 &&
(entityResolverField.Type == entityType ||
if (!TryResolveKeyArgument(entityResolverField, keyField, out var keyArg))
{
return;
}

if (entityResolverField.Type == entityType ||
(entityResolverField.Type.Kind is TypeKind.NonNull &&
entityResolverField.Type.InnerType() == entityType)))
entityResolverField.Type.InnerType() == entityType))
{
var arguments = new List<ArgumentNode>();

Expand Down Expand Up @@ -102,59 +117,182 @@ private static void TryRegisterEntityResolver(
null);

var keyFieldDirective = new IsDirective(keyFieldNode);
var arg = entityResolverField.Arguments.First();
var var = entityType.CreateVariableName(keyFieldDirective);
arguments.Add(new ArgumentNode(arg.Name, new VariableNode(var)));
resolver.Variables.Add(var, arg.CreateVariableField(keyFieldDirective, var));
arguments.Add(new ArgumentNode(keyArg.Name, new VariableNode(var)));
resolver.Variables.Add(var, keyArg.CreateVariableField(keyFieldDirective, var));

// Add the new EntityResolver to the entity metadata
entity.Metadata.EntityResolvers.Add(resolver);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsListOf(IType type, IType entityType)

private static bool TryResolveKeyArgument(
OutputField entityResolverField,
OutputField keyField,
[NotNullWhen(true)] out InputField? keyArgument)
{
if (type.Kind == TypeKind.NonNull)
if (entityResolverField.Arguments.TryGetField(keyField.Name, out keyArgument))
{
type = type.InnerType();
return keyArgument.Type.Equals(keyField.Type, TypeComparison.Structural);
}

if (type.Kind != TypeKind.List)
if (entityResolverField.Arguments.Count == 1)
{
return false;
keyArgument = entityResolverField.Arguments.First();
}
else
{
foreach (var argument in entityResolverField.Arguments)
{
if (keyArgument is null)
{
keyArgument = argument;
continue;
}

type = type.InnerType();
if (argument.Type.Kind is not TypeKind.NonNull)
{
continue;
}

if (type.Kind == TypeKind.NonNull)
{
type = type.InnerType();
if (argument.DefaultValue is null)
{
keyArgument = null;
return false;
}
}
}

return ReferenceEquals(type, entityType);
return keyArgument?.Type.Equals(keyField.Type, TypeComparison.Structural) ?? false;
}

private static void TryRegisterBatchEntityResolver(
EntityGroup entity,
ObjectType entityType,
OutputField entityResolverField,
OutputField keyField,
Schema schema)
{
if (!TryResolveBatchKeyArgument(entityResolverField, keyField, out var keyArg))
{
return;
}

var returnType = entityResolverField.Type;

if (returnType.Kind is TypeKind.NonNull)
{
returnType = returnType.InnerType();
}

if(returnType.Kind != TypeKind.List)
{
return;
}

returnType = returnType.InnerType();

if (returnType == entityType ||
(returnType.Kind is TypeKind.NonNull &&
returnType.InnerType() == entityType))
{
var arguments = new List<ArgumentNode>();

// Create a new FieldNode for the entity resolver
var selection = new FieldNode(
null,
new NameNode(entityResolverField.GetOriginalName()),
null,
null,
Array.Empty<DirectiveNode>(),
arguments,
null);

// Create a new SelectionSetNode for the entity resolver
var selectionSet = new SelectionSetNode(new[] { selection });

// Create a new EntityResolver for the entity
var resolver = new EntityResolver(
EntityResolverKind.BatchWithKey,
selectionSet,
entityType.Name,
schema.Name);

var keyFieldNode = new FieldNode(
null,
new NameNode(keyField.Name),
null,
null,
Array.Empty<DirectiveNode>(),
Array.Empty<ArgumentNode>(),
null);

var keyFieldDirective = new IsDirective(keyFieldNode);
var var = entityType.CreateVariableName(keyFieldDirective);
arguments.Add(new ArgumentNode(keyArg.Name, new VariableNode(var)));
resolver.Variables.Add(var, keyArg.CreateVariableField(keyFieldDirective, var));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsListOfScalar(IType type)
// Add the new EntityResolver to the entity metadata
entity.Metadata.EntityResolvers.Add(resolver);
}
}

private static bool TryResolveBatchKeyArgument(
OutputField entityResolverField,
OutputField keyField,
[NotNullWhen(true)] out InputField? keyArgument)
{
if (type.Kind == TypeKind.NonNull)
if (entityResolverField.Arguments.TryGetField(keyField.Name, out keyArgument))
{
type = type.InnerType();
if (keyArgument.Type.IsListType())
{
return keyArgument.Type.Equals(keyField.Type.InnerType(), TypeComparison.Structural);
}

keyArgument = null;
return false;
}

if (type.Kind != TypeKind.List)
if (entityResolverField.Arguments.Count == 1)
{
keyArgument = entityResolverField.Arguments.First();

if (keyArgument.Type.IsListType())
{
return keyArgument.Type.Equals(keyField.Type.InnerType(), TypeComparison.Structural);
}

keyArgument = null;
return false;
}

type = type.InnerType();
foreach (var argument in entityResolverField.Arguments)
{
if (keyArgument is null)
{
keyArgument = argument;
continue;
}

if (argument.Type.Kind is not TypeKind.NonNull)
{
continue;
}

if (argument.DefaultValue is null)
{
keyArgument = null;
return false;
}
}

if (type.Kind == TypeKind.NonNull)
if (keyArgument?.Type.IsListType() is true &&
keyArgument.Type.InnerType().Equals(keyField.Type, TypeComparison.Structural))
{
type = type.InnerType();
return true;
}

return type.Kind == TypeKind.Scalar;
keyArgument = null;
return false;
}
}
4 changes: 4 additions & 0 deletions src/HotChocolate/Skimmed/src/Skimmed/ComplexType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ public string Name
public FieldCollection<OutputField> Fields { get; } = new();

public IDictionary<string, object?> ContextData { get; } = new Dictionary<string, object?>();

public bool Equals(IType? other) => Equals(other, TypeComparison.Reference);

public abstract bool Equals(IType? other, TypeComparison comparison);
}
8 changes: 7 additions & 1 deletion src/HotChocolate/Skimmed/src/Skimmed/EnumType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ public string Name

public EnumValueCollection Values { get; } = new();

public IDictionary<string, object?> ContextData { get; } = new Dictionary<string, object?>();
public IDictionary<string, object?> ContextData { get; } =
new Dictionary<string, object?>();

public override string ToString()
=> RewriteEnumType(this).ToString(true);

public bool Equals(IType? other) => Equals(other, TypeComparison.Reference);

public bool Equals(IType? other, TypeComparison comparison)
=> other is EnumType otherEnum && otherEnum.Name.Equals(Name, StringComparison.Ordinal);

public static EnumType Create(string name) => new(name);
}
67 changes: 25 additions & 42 deletions src/HotChocolate/Skimmed/src/Skimmed/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ namespace HotChocolate.Skimmed;

public static class TypeExtensions
{
public static bool IsListType(this IType type)
=> type.Kind switch
{
TypeKind.List => true,
TypeKind.NonNull when ((NonNullType) type).NullableType.Kind == TypeKind.List => true,
_ => false
};

public static bool IsInputType(this IType type)
=> type.Kind switch
{
Expand All @@ -27,19 +35,12 @@ public static bool IsOutputType(this IType type)

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IType InnerType(this IType type)
{
switch (type)
=> type switch
{
case ListType listType:
return listType.ElementType;

case NonNullType nonNullType:
return nonNullType.NullableType;

default:
return type;
}
}
ListType listType => listType.ElementType,
NonNullType nonNullType => nonNullType.NullableType,
_ => type
};

public static INamedType NamedType(this IType type)
{
Expand All @@ -65,38 +66,20 @@ public static INamedType NamedType(this IType type)
}

public static ITypeNode ToTypeNode(this IType type)
{
switch (type)
=> type switch
{
case INamedType namedType:
return new NamedTypeNode(namedType.Name);

case ListType listType:
return new ListTypeNode(ToTypeNode(listType.ElementType));

case NonNullType nonNullType:
return new NonNullTypeNode((INullableTypeNode)ToTypeNode(nonNullType.NullableType));

default:
throw new NotSupportedException();
}
}
INamedType namedType => new NamedTypeNode(namedType.Name),
ListType listType => new ListTypeNode(ToTypeNode(listType.ElementType)),
NonNullType nonNullType => new NonNullTypeNode((INullableTypeNode) ToTypeNode(nonNullType.NullableType)),
_ => throw new NotSupportedException()
};

public static IType ReplaceNameType(this IType type, Func<string, INamedType> newNamedType)
{
switch (type)
=> type switch
{
case INamedType namedType:
return newNamedType(namedType.Name);

case ListType listType:
return new ListType(ReplaceNameType(listType.ElementType, newNamedType));

case NonNullType nonNullType:
return new NonNullType(ReplaceNameType(nonNullType.NullableType, newNamedType));

default:
throw new NotSupportedException();
}
}
INamedType namedType => newNamedType(namedType.Name),
ListType listType => new ListType(ReplaceNameType(listType.ElementType, newNamedType)),
NonNullType nonNullType => new NonNullType(ReplaceNameType(nonNullType.NullableType, newNamedType)),
_ => throw new NotSupportedException()
};
}
Loading

0 comments on commit 9ff9d34

Please sign in to comment.