Skip to content

Commit

Permalink
Use node field for to fetch patches. (#6019)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib authored Apr 4, 2023
1 parent 13349fa commit 05469b0
Show file tree
Hide file tree
Showing 59 changed files with 923 additions and 319 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<RootNamespace>HotChocolate</RootNamespace>
<Description>Contains common abstractions used between the Hot Chocolate GraphQL type system and the GraphQL query execution engine.</Description>
<Nullable>enable</Nullable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<WarningsAsErrors>$(WarningsAsErrors);nullable</WarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ public sealed class ListResult : ResultData, IReadOnlyList<object?>
private int _capacity;
private int _count;

/// <summary>
/// Gets the number of elements this list can hold.
/// </summary>
public int Capacity => _capacity;

/// <inheritdoc cref="IReadOnlyCollection{T}.Count"/>
/// <summary>
/// Gets the number of elements in this list.
/// </summary>
public int Count => _count;

/// <inheritdoc cref="IReadOnlyList{T}.this"/>
Expand Down Expand Up @@ -64,22 +69,25 @@ internal void SetUnsafe(int index, ResultData? item)
/// Ensures that the result object has enough capacity on the buffer
/// to store the expected fields.
/// </summary>
/// <param name="capacity">
/// <param name="requiredCapacity">
/// The capacity needed.
/// </param>
internal void EnsureCapacity(int capacity)
internal void EnsureCapacity(int requiredCapacity)
{
// If this list has a capacity specified we will reset it.
// The capacity is only set when the list is rented out,
// Once the item is returned the capacity is reset to zero.
if (_capacity > 0)
{
Reset();
}

if (_buffer.Length < capacity)
if (_buffer.Length < requiredCapacity)
{
Array.Resize(ref _buffer, capacity);
Array.Resize(ref _buffer, requiredCapacity);
}

_capacity = capacity;
_capacity = requiredCapacity;
}

/// <summary>
Expand Down Expand Up @@ -117,7 +125,7 @@ internal void Reset()
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
public IEnumerator<object?> GetEnumerator()
{
for (var i = 0; i < _capacity; i++)
for (var i = 0; i < _count; i++)
{
yield return _buffer[i];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,7 @@ internal void Set(string name, object? value, bool isNullable)
{
_name = name;
_value = value;

if (isNullable)
{
_flags = Flags.Nullable | Flags.Initialized;
}
else
{
_flags = Flags.Initialized;
}
_flags = isNullable ? Flags.InitializedAndNullable : Flags.Initialized;
}

internal void Reset()
Expand All @@ -42,6 +34,7 @@ internal void Reset()
private enum Flags : byte
{
Initialized = 1,
Nullable = 2
Nullable = 2,
InitializedAndNullable = Initialized | Nullable
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using HotChocolate.Language;
using HotChocolate.Properties;
using HotChocolate.Utilities;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using HotChocolate.Fusion.Composition;
using HotChocolate.Language;
using HotChocolate.Skimmed.Serialization;
using HotChocolate.Utilities;
using static HotChocolate.Fusion.CommandLine.Helpers.PackageHelper;

namespace HotChocolate.Fusion.CommandLine.Commands;
Expand Down Expand Up @@ -66,6 +67,12 @@ private static async Task ExecuteAsync(
packageFile.Directory.Create();
}

if (!packageFile.Extension.EqualsOrdinal(Extensions.FusionPackage) &&
!packageFile.Extension.EqualsOrdinal(Extensions.ZipPackage))
{
packageFile = new FileInfo(packageFile.FullName + Extensions.FusionPackage);
}

await using var package = FusionGraphPackage.Open(packageFile.FullName);

if (subgraphPackageFiles is null || subgraphPackageFiles.Count == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public SubgraphConfigSetHttpCommand() : base("http")
IsRequired = true
};


var clientName = new Option<string>("--client-name")
{
Description = "The name of the graphql-http configuration.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal sealed class SubgraphPackCommand : Command
{
public SubgraphPackCommand() : base("pack")
{
Description = "Creates a subgraph package.";
Description = "Creates a Fusion subgraph package.";

var packageFile = new SubgraphPackageFileOption();
var schemaFile = new SubgraphSchemaFileOption();
Expand Down Expand Up @@ -90,6 +90,11 @@ private static async Task ExecuteAsync(
var fileName = $"{config.Name}{Extensions.SubgraphPackage}";
packageFile = new FileInfo(Combine(workingDirectory.FullName, fileName));
}
else if (!packageFile.Extension.EqualsOrdinal(Extensions.SubgraphPackage) &&
!packageFile.Extension.EqualsOrdinal(Extensions.ZipPackage))
{
packageFile = new FileInfo($"{packageFile.FullName}{Extensions.SubgraphPackage}");
}

if (packageFile.Exists)
{
Expand Down
5 changes: 3 additions & 2 deletions src/HotChocolate/Fusion/src/CommandLine/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace HotChocolate.Fusion.CommandLine;

internal static class Extensions
{
public const string SubgraphPackage = ".ccspkg";
public const string FusionPackage = ".ccfpkg";
public const string SubgraphPackage = ".fsp";
public const string FusionPackage = ".fgp";
public const string ZipPackage = ".zip";
}
Binary file removed src/HotChocolate/Fusion/src/CommandLine/foo.ccfpkg
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public static string CreateVariableName(
? CreateVariableName(type, directive.Coordinate.Value)
: CreateVariableName(type, directive.Field);

private static string CreateVariableName(
ObjectType type,
public static string CreateVariableName(
this ObjectType type,
SchemaCoordinate coordinate)
=> $"{type.Name}_{coordinate.MemberName}";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ public FusionGraphComposer(
bool fusionTypeSelf = false,
Func<ICompositionLog>? logFactory = null)
: this(
new IEntityEnricher[] { new RefResolverEntityEnricher() },
new IEntityEnricher[]
{
new RefResolverEntityEnricher(),
new NodeEntityEnricher()
},
new ITypeMergeHandler[]
{
new InterfaceTypeMergeHandler(), new UnionTypeMergeHandler(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
using HotChocolate.Language;
using HotChocolate.Skimmed;

namespace HotChocolate.Fusion.Composition.Pipeline;

internal class NodeEntityEnricher : IEntityEnricher
{
private static readonly FieldNode _idField =
new FieldNode(
null,
new NameNode("id"),
null,
null,
Array.Empty<DirectiveNode>(),
Array.Empty<ArgumentNode>(),
null);

private static readonly VariableDefinitionNode _idVariable =
new VariableDefinitionNode(
null,
new VariableNode("var"),
new NonNullTypeNode(new NamedTypeNode("ID")),
null,
Array.Empty<DirectiveNode>());

private static readonly VariableDefinitionNode _idsVariable =
new VariableDefinitionNode(
null,
new VariableNode("var"),
new NonNullTypeNode(new ListTypeNode(new NonNullTypeNode(new NamedTypeNode("ID")))),
null,
Array.Empty<DirectiveNode>());

public ValueTask EnrichAsync(
CompositionContext context,
EntityGroup entity,
CancellationToken cancellationToken = default)
{
foreach (var (type, schema) in entity.Parts)
{
if (schema.QueryType is not null &&
schema.QueryType.Fields.ContainsName("node") &&
schema.Types.TryGetType<InterfaceType>("Node", out var nodeType) &&
type.Implements.Contains(nodeType))
{
ResolveWithNode(entity, schema, type, entity.Name);

if (schema.QueryType.Fields.ContainsName("nodes"))
{
ResolveWithNodes(entity, schema, type, entity.Name);
}
}
}
return default;
}

private static void ResolveWithNode(
EntityGroup entity,
Schema sourceSchema,
ObjectType sourceType,
string targetName)
{
var arguments = new List<ArgumentNode>();

var spread = new FragmentSpreadNode(
null,
new NameNode(targetName),
Array.Empty<DirectiveNode>());

var inlineFragment = new InlineFragmentNode(
null,
new NamedTypeNode(sourceType.Name),
Array.Empty<DirectiveNode>(),
new SelectionSetNode(new[] { spread }));

// Create a new FieldNode for the entity resolver
var selection = new FieldNode(
null,
new NameNode("node"),
null,
null,
Array.Empty<DirectiveNode>(),
arguments,
new SelectionSetNode(new[] { inlineFragment }));

// 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.Single,
selectionSet,
sourceType.Name,
sourceSchema.Name);

var var = sourceType.CreateVariableName(new SchemaCoordinate(targetName, "id"));
var varNode = new VariableNode(var);
arguments.Add(new ArgumentNode("id", varNode));

resolver.Variables.Add(
var,
new VariableDefinition(
var,
_idField,
_idVariable.WithVariable(varNode)));

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

private static void ResolveWithNodes(
EntityGroup entity,
Schema sourceSchema,
ObjectType sourceType,
string targetName)
{
var arguments = new List<ArgumentNode>();

var spread = new FragmentSpreadNode(
null,
new NameNode(targetName),
Array.Empty<DirectiveNode>());

var inlineFragment = new InlineFragmentNode(
null,
new NamedTypeNode(sourceType.Name),
Array.Empty<DirectiveNode>(),
new SelectionSetNode(new[] { spread }));

// Create a new FieldNode for the entity resolver
var selection = new FieldNode(
null,
new NameNode("nodes"),
null,
null,
Array.Empty<DirectiveNode>(),
arguments,
new SelectionSetNode(new[] { inlineFragment }));

// 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,
sourceType.Name,
sourceSchema.Name);

var var = sourceType.CreateVariableName(new SchemaCoordinate(targetName, "id"));
var varNode = new VariableNode(var);
arguments.Add(new ArgumentNode("ids", varNode));

resolver.Variables.Add(
var,
new VariableDefinition(
var,
_idField,
_idsVariable.WithVariable(varNode)));

// Add the new EntityResolver to the entity metadata
entity.Metadata.EntityResolvers.Add(resolver);
}
}
33 changes: 33 additions & 0 deletions src/HotChocolate/Fusion/src/Core/Execution/ExecutionState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using HotChocolate.Execution.Processing;

namespace HotChocolate.Fusion.Execution;
Expand Down Expand Up @@ -26,6 +28,37 @@ public bool ContainsState(ISelectionSet selectionSet)
}
}

public bool ContainsState(ISelectionSet[] selectionSets)
{
var taken = false;
Monitor.Enter(_map, ref taken);

try
{
ref var start = ref MemoryMarshal.GetArrayDataReference(selectionSets);
ref var end = ref Unsafe.Add(ref start, selectionSets.Length);

while (Unsafe.IsAddressLessThan(ref start, ref end))
{
if (_map.ContainsKey(start))
{
return true;
}

start = ref Unsafe.Add(ref start, 1);
}
}
finally
{
if (taken)
{
Monitor.Exit(_map);
}
}

return false;
}

public bool TryGetState(
ISelectionSet selectionSet,
[NotNullWhen(true)] out IReadOnlyList<WorkItem>? values)
Expand Down
Loading

0 comments on commit 05469b0

Please sign in to comment.