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

Added new ObjectTypeAttribute<T> Feature. #7009

Merged
merged 2 commits into from
Mar 22, 2024
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 @@ -17,5 +17,5 @@ public enum FederationVersion
Federation27 = 2_7,
// default to latest-1
Default = Federation26,
Latest = Federation27
Latest = Federation27,
}
13 changes: 9 additions & 4 deletions src/HotChocolate/Core/src/Abstractions/WellKnownContextData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,24 +274,29 @@ public static class WellKnownContextData
/// The key to access the authorization allowed flag on the member context.
/// </summary>
public const string AllowAnonymous = "HotChocolate.Authorization.AllowAnonymous";

/// <summary>
/// The key to access the true nullability flag on the execution context.
/// </summary>
public const string EnableTrueNullability = "HotChocolate.Types.EnableTrueNullability";

/// <summary>
/// The key to access the tag options object.
/// </summary>
public const string TagOptions = "HotChocolate.Types.TagOptions";

/// <summary>
/// Type key to access the internal schema options.
/// </summary>
public const string InternalSchemaOptions = "HotChocolate.Types.InternalSchemaOptions";

/// <summary>
/// Type key to access the paging arguments in the local resolver state.
/// </summary>
public const string PagingArguments = "HotChocolate.Types.PagingArguments";

/// <summary>
/// Type key to access the object type configuration hooks in the schema builder context data.
/// </summary>
public const string ObjectTypeConfigurations = "HotChocolate.Types.ObjectTypeConfigurations";
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static Path CombinePath(Path path, JsonElement errorSubPath, int skipSubE
{
{ ValueKind: JsonValueKind.String, } nameElement => path.Append(nameElement.GetString()!),
{ ValueKind: JsonValueKind.Number, } indexElement => path.Append(indexElement.GetInt32()),
_ => throw new InvalidOperationException("The error path contains an unsupported element.")
_ => throw new InvalidOperationException("The error path contains an unsupported element."),
};
}

Expand Down
26 changes: 21 additions & 5 deletions src/HotChocolate/Core/src/Types.Analyzers/Errors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ public static class Errors
new(
id: "HC0074",
title: "Parameter Missing.",
messageFormat:
SourceGenResources.DataLoader_KeyParameterMissing,
messageFormat: SourceGenResources.DataLoader_KeyParameterMissing,
category: "DataLoader",
DiagnosticSeverity.Error,
isEnabledByDefault: true);
Expand All @@ -19,9 +18,26 @@ public static class Errors
new(
id: "HC0075",
title: "Access Modifier Invalid.",
messageFormat:
SourceGenResources.DataLoader_InvalidAccessModifier,
messageFormat: SourceGenResources.DataLoader_InvalidAccessModifier,
category: "DataLoader",
DiagnosticSeverity.Error,
isEnabledByDefault: true);
}

public static readonly DiagnosticDescriptor ObjectTypePartialKeywordMissing =
new(
id: "HC00XX",
title: "Partial Keyword Missing.",
messageFormat: "A split object type class needs to be a partial class.",
category: "TypeSystem",
DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor ObjectTypeStaticKeywordMissing =
new(
id: "HC00XX",
title: "Static Keyword Missing.",
messageFormat: "A split object type class needs to be a static class.",
category: "TypeSystem",
DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,67 @@ public void WriteRegisterTypeExtension(string typeName, bool staticType)
: "builder.AddTypeExtension<global::{0}>();",
typeName);

public void WriteRegisterObjectTypeExtension(string runtimeTypeName, string extensionType)
{
_writer.WriteIndentedLine("builder.ConfigureSchema(sb =>", runtimeTypeName);
_writer.WriteIndentedLine("{");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine("const string typeKey = \"8734371_Type_ObjectType<{0}>\";", runtimeTypeName);
_writer.WriteIndentedLine("const string hooksKey = \"8734371_Hooks_ObjectType<{0}>\";", runtimeTypeName);
_writer.WriteLine();
_writer.WriteIndentedLine("if (!sb.ContextData.ContainsKey(typeKey))");
_writer.WriteIndentedLine("{");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine("sb.AddObjectType<{0}>(", runtimeTypeName);
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine("descriptor =>");
_writer.WriteIndentedLine("{");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine(
"var hooks = (global::System.Collections.Generic.List<Action<IObjectTypeDescriptor" +
"<{0}>>>)descriptor.Extend().Context.ContextData[hooksKey]!;",
runtimeTypeName);
_writer.WriteIndentedLine("foreach (var configure in hooks)");
_writer.WriteIndentedLine("{");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine("configure(descriptor);");
}
_writer.WriteIndentedLine("};");
}
_writer.WriteIndentedLine("});");
}
_writer.WriteLine();
_writer.WriteIndentedLine("sb.ContextData.Add(typeKey, null);");
}
_writer.WriteIndentedLine("}");

_writer.WriteLine();
_writer.WriteIndentedLine("if (!sb.ContextData.TryGetValue(hooksKey, out var value))");
_writer.WriteIndentedLine("{");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine(
"value = new System.Collections.Generic.List<Action<IObjectTypeDescriptor<{0}>>>();",
runtimeTypeName);
_writer.WriteIndentedLine("sb.ContextData.Add(hooksKey, value);");
}

_writer.WriteIndentedLine("}");
_writer.WriteLine();
_writer.WriteIndentedLine(
"((System.Collections.Generic.List<Action<IObjectTypeDescriptor<{0}>>>)value!)" +
".Add({1}.Initialize);",
runtimeTypeName,
extensionType);
}
_writer.WriteIndentedLine("});");
}

public void WriteRegisterDataLoader(string typeName)
=> _writer.WriteIndentedLine("builder.AddDataLoader<global::{0}>();", typeName);

Expand Down Expand Up @@ -127,4 +188,4 @@ public void Dispose()
_writer = default!;
_disposed = true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System.Text;
using HotChocolate.Types.Analyzers.Helpers;
using HotChocolate.Types.Analyzers.Inspectors;

namespace HotChocolate.Types.Analyzers.Generators;

public sealed class ObjectTypeExtensionSyntaxGenerator
{
private readonly string _ns;
private readonly CodeWriter _writer;

public ObjectTypeExtensionSyntaxGenerator(StringBuilder sb, string ns)
{
_ns = ns;
_writer = new(sb);
}

public void WriterHeader()
{
_writer.WriteFileHeader();
_writer.WriteLine();
}

public void WriteBeginNamespace()
{
_writer.WriteIndentedLine("namespace {0}", _ns);
_writer.WriteIndentedLine("{");
_writer.IncreaseIndent();
}

public void WriteEndNamespace()
{
_writer.DecreaseIndent();
_writer.WriteIndentedLine("}");
_writer.WriteLine();
}

public string WriteBeginClass(string typeName)
{
_writer.WriteIndentedLine("public static partial class {0}", typeName);
_writer.WriteIndentedLine("{");
_writer.IncreaseIndent();
return typeName;
}

public void WriteEndClass()
{
_writer.DecreaseIndent();
_writer.WriteIndentedLine("}");
}

public void WriteInitializeMethod(ObjectTypeExtensionInfo objectTypeExtension)
{
_writer.WriteIndentedLine(
"internal static void Initialize(global::HotChocolate.Types.IObjectTypeDescriptor<{0}> descriptor)",
objectTypeExtension.RuntimeType.ToFullyQualified());
_writer.WriteIndentedLine("{");

using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine("var bindingFlags = System.Reflection.BindingFlags.Public |");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine("System.Reflection.BindingFlags.NonPublic |");
_writer.WriteIndentedLine("System.Reflection.BindingFlags.Static;");
}

_writer.WriteIndentedLine(
"var thisType = typeof({0});",
objectTypeExtension.Type.ToFullyQualified());

if (objectTypeExtension.NodeResolver is not null)
{
_writer.WriteLine();
_writer.WriteIndentedLine("descriptor");
using (_writer.IncreaseIndent())
{
_writer.WriteIndentedLine(".ImplementsNode()");
_writer.WriteIndentedLine(
".ResolveNodeWith((global::System.Reflection.MethodInfo)" +
"thisType.GetMember(\"{0}\", bindingFlags)[0]);",
objectTypeExtension.NodeResolver.Name);
}
}

if (objectTypeExtension.Members.Length > 0)
{
_writer.WriteLine();
foreach (var member in objectTypeExtension.Members)
{
_writer.WriteIndentedLine(
"descriptor.Field(thisType.GetMember(\"{0}\", bindingFlags)[0]);",
member.Name);
}
}

_writer.WriteLine();
_writer.WriteIndentedLine("Configure(descriptor);");
}

_writer.WriteIndentedLine("}");
}

public void WriteConfigureMethod(ObjectTypeExtensionInfo objectTypeExtension)
{
_writer.WriteIndentedLine(
"static partial void Configure(global::HotChocolate.Types.IObjectTypeDescriptor<{0}> descriptor);",
objectTypeExtension.RuntimeType.ToFullyQualified());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void WriteBeginClass(string typeName)
_writer.WriteLine();
}
_first = false;

_writer.WriteIndentedLine("public sealed class {0}", typeName);

using (_writer.IncreaseIndent())
Expand Down Expand Up @@ -79,14 +79,14 @@ public void WriteConfigureMethod(OperationType type, IEnumerable<OperationInfo>
_writer.WriteIndentedLine("System.Reflection.BindingFlags.NonPublic |");
_writer.WriteIndentedLine("System.Reflection.BindingFlags.Static;");
}

_writer.WriteIndentedLine("descriptor.Name({0});", GetOperationConstant(type));

var typeIndex = 0;
foreach (var group in operations.GroupBy(t => t.TypeName))
{
_writer.WriteLine();

var typeName = $"type{++typeIndex}";
_writer.WriteIndentedLine("var {0} = typeof({1});", typeName, group.Key);

Expand All @@ -98,7 +98,7 @@ public void WriteConfigureMethod(OperationType type, IEnumerable<OperationInfo>
operation.MethodName);
}
}

_writer.DecreaseIndent();
_writer.WriteIndentedLine("}");
}
Expand All @@ -109,15 +109,15 @@ private static string GetOperationConstant(OperationType type)
OperationType.Query => "global::HotChocolate.Types.OperationTypeNames.Query",
OperationType.Mutation => "global::HotChocolate.Types.OperationTypeNames.Mutation",
OperationType.Subscription => "global::HotChocolate.Types.OperationTypeNames.Subscription",
_ => throw new InvalidOperationException()
_ => throw new InvalidOperationException(),
};

public override string ToString()
=> _sb.ToString();

public SourceText ToSourceText()
=> SourceText.From(ToString(), Encoding.UTF8);

public void Dispose()
{
if (_disposed)
Expand All @@ -130,4 +130,4 @@ public void Dispose()
_writer = default!;
_disposed = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private void WriteFactory(string typeName, List<RequestMiddlewareParameterInfo>
for (var i = 0; i < parameters.Count; i++)
{
var parameter = parameters[i];

if(i > 0)
{
_writer.Write(", ");
Expand Down Expand Up @@ -223,7 +223,7 @@ private void WriteInvoke(string methodName, List<RequestMiddlewareParameterInfo>
for (var i = 0; i < parameters.Count; i++)
{
var parameter = parameters[i];

if(i > 0)
{
_writer.Write(", ");
Expand Down Expand Up @@ -295,4 +295,4 @@ public void Dispose()
_writer = default!;
_disposed = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ public static void WriteGeneratedAttribute(this CodeWriter writer)
{
throw new ArgumentNullException(nameof(writer));
}

#if DEBUG
writer.WriteIndentedLine(
"[global::System.CodeDom.Compiler.GeneratedCode(" +
"[global::System.CodeDom.Compiler.GeneratedCode(" +
"\"HotChocolate\", \"11.0.0\")]");
#else
var version = typeof(CodeWriter).Assembly.GetName().Version!.ToString();
Expand All @@ -34,6 +34,8 @@ public static void WriteFileHeader(this CodeWriter writer)
writer.WriteLine();
writer.WriteIndentedLine("using System;");
writer.WriteIndentedLine("using System.Runtime.CompilerServices;");
writer.WriteIndentedLine("using HotChocolate;");
writer.WriteIndentedLine("using HotChocolate.Types;");
writer.WriteIndentedLine("using HotChocolate.Execution.Configuration;");
}

Expand All @@ -43,4 +45,4 @@ public static CodeWriter WriteComment(this CodeWriter writer, string comment)
writer.WriteLine(comment);
return writer;
}
}
}
Loading
Loading