graphql-platform
graphql-platform copied to clipboard
Support for Sort using EFCore.SqlServer.HierarchyId property
Is your feature request related to a problem?
Eventual goal: Sort IQuerable collection by EFCore.SqlServer.HierarchyId property.
We have a hierarchyId (https://github.com/efcore/EFCore.SqlServer.HierarchyId) column inside a POCO object.
Alternative 1:
If HierarchyId column wasn't ignored then the following exception is thrown:
System.InvalidOperationException: 'No compatible constructor found for input type type `Microsoft.EntityFrameworkCore.HierarchyId`.
Either you have to provide a public constructor with settable properties or a public constructor that allows to pass in values for read-only properties.There was no way to set the following properties: .'
Alternative 2:
We ignored HierarchyId property and then used a resolver to expose this column. Now, data cannot be sorted by this resolved property since sorting as of now doesn't support the resolved columns.
The solution you'd like
Ability to sort by a resolved field OR ability to expose a HierarchyId column in schema.
Product
Hot Chocolate
This one works in v13.9.0
(except that FilterInput is empty so that still needs to be resolved).
But here is a working implementation of hierarchyId
using HotChocolate.Data.Sorting;
using HotChocolate.Language;
using HotChocolate.Configuration;
using HotChocolate.Types.Descriptors.Definitions;
using HotChocolate.Execution.Configuration;
namespace Foo;
public static partial class SqlHierarchyIdExtensions
{
public static IRequestExecutorBuilder AddSqlHierarchyIdType(this IRequestExecutorBuilder gb)
{
gb.AddType<SqlHierarchyIdType>();
gb.BindRuntimeType<HierarchyId, SqlHierarchyIdType>();
gb.AddConvention<ISortConvention>(_ => new SortConventionExtension(descriptor =>
{
// bind HierarchyId as it is a class to avoid SortFilterInputType<HierarchyId>
descriptor.BindRuntimeType<HierarchyId, DefaultSortEnumType>();
}));
return gb;
}
}
/// <summary>
/// The `SqlHierarchyIdType` scalar type represents a <see cref="Microsoft.EntityFrameworkCore.HierarchyId"/>
/// </summary>
public class SqlHierarchyIdType : ScalarType<HierarchyId, StringValueNode>
{
public SqlHierarchyIdType() : base("SqlHierarchyId")
{
Description = "Represents a SQL server hierarchyid";
}
protected override bool IsInstanceOfType(HierarchyId runtimeValue)
=> true;
protected override bool IsInstanceOfType(StringValueNode valueSyntax)
{
try
{
return HierarchyId.Parse(valueSyntax.Value) != null;
}
catch
{
return false;
}
}
protected override void OnValidateType(ITypeSystemObjectContext context, DefinitionBase definition)
{
base.OnValidateType(context, definition);
}
public override IValueNode ParseResult(object? resultValue)
=> ParseValue(resultValue);
protected override HierarchyId ParseLiteral(StringValueNode valueSyntax)
=> HierarchyId.Parse(valueSyntax.Value);
protected override StringValueNode ParseValue(HierarchyId runtimeValue)
=> new StringValueNode(runtimeValue.ToString());
}