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 @@ -194,23 +194,25 @@ private static string ToGraphQLType(

private static INamedTypeSymbol? GetListInnerType(INamedTypeSymbol typeSymbol)
{
if (typeSymbol.IsGenericType
&& (typeSymbol.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IReadOnlyList<T>"
|| typeSymbol.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IList<T>"))
if (typeSymbol.IsGenericType && IsEdgeListDefinition(typeSymbol.OriginalDefinition))
{
return typeSymbol.TypeArguments[0] as INamedTypeSymbol;
}

foreach (var interfaceType in typeSymbol.AllInterfaces)
{
if (interfaceType.IsGenericType
&& (interfaceType.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IReadOnlyList<T>"
|| interfaceType.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IList<T>"))
if (interfaceType.IsGenericType && IsEdgeListDefinition(interfaceType.OriginalDefinition))
{
return interfaceType.TypeArguments[0] as INamedTypeSymbol;
}
}

return null;
}

private static bool IsEdgeListDefinition(INamedTypeSymbol typeDefinition)
=> typeDefinition.ToDisplayString()
is "System.Collections.Generic.IReadOnlyList<T>"
or "System.Collections.Generic.IList<T>"
or "System.Collections.Generic.IAsyncEnumerable<T>";
}
Original file line number Diff line number Diff line change
Expand Up @@ -1547,35 +1547,69 @@ private static bool IsSupportedBatchParameterType(ITypeSymbol type)

private void WritePropertyResolver(Resolver resolver)
{
var isAwaited = resolver.ResultKind is ResolverResultKind.Task or ResolverResultKind.TaskAsyncEnumerable;
var isAsync = isAwaited || resolver.ResultKind is ResolverResultKind.AsyncEnumerable;

Writer.WriteMethod(
"public",
returnType: WellKnownTypes.FieldResolverDelegates,
methodName: $"{resolver.Member.Name}",
[],
string.Format(
"new global::{0}(pureResolver: {1})",
"new global::{0}({1}: {2})",
WellKnownTypes.FieldResolverDelegates,
isAsync ? "resolver" : "pureResolver",
resolver.Member.Name));

Writer.WriteLine();

Writer.WriteIndentedLine(
"private global::{0}? {1}(global::{2} context)",
WellKnownTypes.Object,
resolver.Member.Name,
WellKnownTypes.ResolverContext);
if (isAsync)
{
Writer.WriteIndented("private ");

if (isAwaited)
{
Writer.Write("async ");
}

Writer.WriteLine(
"global::{0}<global::{1}?> {2}(global::{3} context)",
WellKnownTypes.ValueTask,
WellKnownTypes.Object,
resolver.Member.Name,
WellKnownTypes.ResolverContext);
}
else
{
Writer.WriteIndentedLine(
"private global::{0}? {1}(global::{2} context)",
WellKnownTypes.Object,
resolver.Member.Name,
WellKnownTypes.ResolverContext);
}

Writer.WriteIndentedLine("{");
using (Writer.IncreaseIndent())
{
var typeName = resolver.Member.ContainingType.ToFullyQualified();
var receiver = resolver.IsStatic ? typeName : GetInstanceReceiver(typeName);

Writer.WriteIndentedLine(
"var result = {0}.{1};",
isAwaited ? "var result = await {0}.{1};" : "var result = {0}.{1};",
receiver,
resolver.Member.Name);

Writer.WriteIndentedLine("return result;");
if (isAsync && !isAwaited)
{
Writer.WriteIndentedLine(
"return new global::{0}<global::{1}?>(result);",
WellKnownTypes.ValueTask,
WellKnownTypes.Object);
}
else
{
Writer.WriteIndentedLine("return result;");
}
}

Writer.WriteIndentedLine("}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ public static bool TryGetGraphQLTypeName(
public static INamedTypeSymbol? GetConnectionBaseSymbol(this Compilation compilation)
=> compilation.GetTypeByMetadataName("HotChocolate.Types.Pagination.ConnectionBase`3");

public static INamedTypeSymbol? GetStreamPageConnectionSymbol(this Compilation compilation)
=> compilation.GetTypeByMetadataName("HotChocolate.Types.Pagination.StreamPageConnection`1");

public static INamedTypeSymbol? GetEdgeInterfaceSymbol(this Compilation compilation)
=> compilation.GetTypeByMetadataName("HotChocolate.Types.Pagination.IEdge`1");

Expand Down Expand Up @@ -248,7 +251,8 @@ public static bool IsConnectionType(this Compilation compilation, ITypeSymbol po
return false;
}

return IsDerivedFromGenericBase(namedType, compilation.GetConnectionBaseSymbol());
return IsDerivedFromGenericBase(namedType, compilation.GetConnectionBaseSymbol())
|| IsDerivedFromGenericBase(namedType, compilation.GetStreamPageConnectionSymbol());
}

public static bool IsEdgeType(this Compilation compilation, ITypeSymbol possibleEdgeType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1554,11 +1554,6 @@ public static bool IsNonNullable(this IParameterSymbol parameter)

public static ResolverResultKind GetResultKind(this IMethodSymbol method)
{
const string task = $"{WellKnownTypes.Task}<";
const string valueTask = $"{WellKnownTypes.ValueTask}<";
const string taskEnumerable = $"{WellKnownTypes.Task}<{WellKnownTypes.AsyncEnumerable}<";
const string valueTaskEnumerable = $"{WellKnownTypes.ValueTask}<{WellKnownTypes.AsyncEnumerable}<";

if (method.ReturnsVoid || method.ReturnsByRef || method.ReturnsByRefReadonly)
{
return ResolverResultKind.Invalid;
Expand All @@ -1571,14 +1566,9 @@ public static ResolverResultKind GetResultKind(this IMethodSymbol method)
return ResolverResultKind.Invalid;
}

if (returnType.StartsWith(task) || returnType.StartsWith(valueTask))
if (TryGetTaskResultKind(returnType, out var taskResultKind))
{
if (returnType.StartsWith(taskEnumerable) || returnType.StartsWith(valueTaskEnumerable))
{
return ResolverResultKind.TaskAsyncEnumerable;
}

return ResolverResultKind.Task;
return taskResultKind;
}

if (returnType.StartsWith(WellKnownTypes.Executable))
Expand All @@ -1599,6 +1589,39 @@ public static ResolverResultKind GetResultKind(this IMethodSymbol method)
return ResolverResultKind.Pure;
}

public static ResolverResultKind GetResultKind(this IPropertySymbol property)
{
var type = property.Type.ToDisplayString();

if (TryGetTaskResultKind(type, out var taskResultKind))
{
return taskResultKind;
}

return type.StartsWith(WellKnownTypes.AsyncEnumerable)
? ResolverResultKind.AsyncEnumerable
: ResolverResultKind.Pure;
}

private static bool TryGetTaskResultKind(string type, out ResolverResultKind resultKind)
{
const string task = $"{WellKnownTypes.Task}<";
const string valueTask = $"{WellKnownTypes.ValueTask}<";
const string taskEnumerable = $"{WellKnownTypes.Task}<{WellKnownTypes.AsyncEnumerable}<";
const string valueTaskEnumerable = $"{WellKnownTypes.ValueTask}<{WellKnownTypes.AsyncEnumerable}<";

if (type.StartsWith(task) || type.StartsWith(valueTask))
{
resultKind = type.StartsWith(taskEnumerable) || type.StartsWith(valueTaskEnumerable)
? ResolverResultKind.TaskAsyncEnumerable
: ResolverResultKind.Task;
return true;
}

resultKind = default;
return false;
}

public static bool IsListType(this ISymbol member, [NotNullWhen(true)] out string? elementType)
{
if (member is IMethodSymbol methodSymbol)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,28 +383,31 @@ private static string GetTypeLookupKey(string typeNamespace, string typeName)
private static INamedTypeSymbol? GetEdgeType(
INamedTypeSymbol connectionType)
{
var property = GetEdgesProperty(connectionType);
var returnType = property?.GetReturnType();
var member = GetEdgesMember(connectionType);
var returnType = member?.GetReturnType();

if (returnType is not INamedTypeSymbol namedType
|| !namedType.IsGenericType
|| namedType.TypeArguments.Length != 1
|| namedType.Name != "IReadOnlyList")
|| namedType.Name is not ("IReadOnlyList" or "IAsyncEnumerable"))
{
return null;
}

return (INamedTypeSymbol)namedType.TypeArguments[0];
}

private static IPropertySymbol? GetEdgesProperty(
private static ISymbol? GetEdgesMember(
INamedTypeSymbol connectionType)
{
var member = connectionType.AllPublicInstanceMembers().FirstOrDefault(p => p.Name == "Edges");

if (member is IPropertySymbol property)
foreach (var member in connectionType.AllPublicInstanceMembers())
{
return property;
switch (member)
{
case IPropertySymbol { Name: "Edges" }:
case IMethodSymbol { MethodKind: MethodKind.Ordinary, Name: "GetEdgesAsync" }:
return member;
}
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,18 @@ private static Resolver CreateResolver(
INamedTypeSymbol resolverType,
IMethodSymbol resolverMethod,
string? subscribeWith = null)
=> CreateResolver(context.SemanticModel.Compilation, resolverType, resolverMethod, subscribeWith: subscribeWith);
=> CreateResolver(
context.SemanticModel.Compilation,
resolverType,
resolverMethod,
FieldFlags.None,
subscribeWith: subscribeWith);

public static Resolver CreateResolver(
Compilation compilation,
INamedTypeSymbol resolverType,
IMethodSymbol resolverMethod,
FieldFlags flags,
string? resolverTypeName = null,
string? subscribeWith = null)
{
Expand Down Expand Up @@ -345,6 +351,7 @@ public static Resolver CreateResolver(
: compilation.IsConnectionType(resolverMethod.ReturnType)
? ResolverKind.ConnectionResolver
: ResolverKind.Default,
flags: flags,
subscribeWith: subscribeWith);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,31 @@ private static ConnectionClassInfo Create(
switch (member)
{
case IMethodSymbol { MethodKind: MethodKind.Ordinary } method:
resolvers.Add(ObjectTypeInspector.CreateResolver(compilation, runtimeType, method, name));
var methodFlags = FieldFlags.None;

if (isConnection)
{
if (method.Name.Equals("GetEdgesAsync", StringComparison.Ordinal))
{
methodFlags |= FieldFlags.ConnectionEdgesField;
}
else if (method.Name.Equals("GetNodesAsync", StringComparison.Ordinal))
{
methodFlags |= FieldFlags.ConnectionNodesField;
}
else if (method.Name.Equals("GetTotalCountAsync", StringComparison.Ordinal))
{
methodFlags |= FieldFlags.TotalCount;
}
}

resolvers.Add(
ObjectTypeInspector.CreateResolver(
compilation,
runtimeType,
method,
methodFlags,
name));
break;

case IPropertySymbol property:
Expand Down Expand Up @@ -109,7 +133,7 @@ private static ConnectionClassInfo Create(
property,
compilation.GetDescription(property),
compilation.GetDeprecationReason(property),
ResolverResultKind.Pure,
property.GetResultKind(),
[],
ObjectTypeInspector.GetMemberBindings(member),
compilation.CreateTypeReference(property),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,28 @@ private static ConnectionTypeInfo Create(
switch (member)
{
case IMethodSymbol { MethodKind: MethodKind.Ordinary } method:
resolvers.Add(CreateResolver(compilation, runtimeType, method, connectionName));
var methodFlags = FieldFlags.None;

if (method.Name.Equals("GetEdgesAsync", StringComparison.Ordinal))
{
methodFlags |= FieldFlags.ConnectionEdgesField;
}
else if (method.Name.Equals("GetNodesAsync", StringComparison.Ordinal))
{
methodFlags |= FieldFlags.ConnectionNodesField;
}
else if (method.Name.Equals("GetTotalCountAsync", StringComparison.Ordinal))
{
methodFlags |= FieldFlags.TotalCount;
}

resolvers.Add(
CreateResolver(
compilation,
runtimeType,
method,
methodFlags,
connectionName));
break;

case IPropertySymbol property:
Expand All @@ -178,7 +199,7 @@ private static ConnectionTypeInfo Create(
property,
compilation.GetDescription(property),
compilation.GetDeprecationReason(property),
ResolverResultKind.Pure,
property.GetResultKind(),
[],
GetMemberBindings(property),
compilation.CreateTypeReference(property),
Expand Down
10 changes: 8 additions & 2 deletions src/HotChocolate/Core/src/Types.Analyzers/Models/EdgeTypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,13 @@ private static EdgeTypeInfo Create(
switch (member)
{
case IMethodSymbol { MethodKind: MethodKind.Ordinary } method:
resolvers.Add(ObjectTypeInspector.CreateResolver(compilation, runtimeType, method, edgeName));
resolvers.Add(
ObjectTypeInspector.CreateResolver(
compilation,
runtimeType,
method,
FieldFlags.None,
edgeName));
break;

case IPropertySymbol property:
Expand All @@ -171,7 +177,7 @@ private static EdgeTypeInfo Create(
property,
compilation.GetDescription(property),
compilation.GetDeprecationReason(property),
ResolverResultKind.Pure,
property.GetResultKind(),
[],
ObjectTypeInspector.GetMemberBindings(member),
compilation.CreateTypeReference(property),
Expand Down
Loading
Loading