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

VCST-2376: update GraphQL.NET to v8 #21

Open
wants to merge 23 commits into
base: dev
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion src/VirtoCommerce.Xapi.Core/BaseQueries/CommandBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override void Build(ISchema schema)

protected override IEnumerable<QueryArgument> GetArguments()
{
var type = GraphTypeExtenstionHelper.GetActualComplexType<NonNullGraphType<TCommandGraphType>>();
var type = GraphTypeExtensionHelper.GetActualComplexType<NonNullGraphType<TCommandGraphType>>();

yield return new QueryArgument(type) { Name = _argumentName };
}
Expand Down
3 changes: 1 addition & 2 deletions src/VirtoCommerce.Xapi.Core/BaseQueries/RequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ protected RequestBuilder(
protected virtual FieldType GetFieldType()
{
var builder = FieldBuilder<object, TResponse>
.Create(GraphTypeExtenstionHelper.GetActualType<TResponseGraphType>())
.Name(Name)
.Create(Name, GraphTypeExtensionHelper.GetActualType<TResponseGraphType>())
.ResolveAsync(async context =>
{
var (_, response) = await Resolve(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ protected SearchQueryBuilder(IMediator mediator, IAuthorizationService authoriza

protected override FieldType GetFieldType()
{
var builder = GraphTypeExtenstionHelper.CreateConnection<TItemGraphType, object>()
.Name(Name)
var builder = GraphTypeExtensionHelper.CreateConnection<TItemGraphType, object>(Name)
.PageSize(DefaultPageSize);

ConfigureArguments(builder.FieldType);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using GraphQL.Server.Transports.AspNetCore;
using GraphQL.Server.Transports.AspNetCore.WebSockets;
using GraphQL.Server.Ui.Playground;
using GraphQL.Types;
using Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -25,7 +28,16 @@ public static IApplicationBuilder UseSchemaGraphQL<TSchema>(this IApplicationBui
? GraphQlPath
: $"{GraphQlPath}/{schemaPath}";

builder.UseGraphQL<TSchema>(path: graphQlPath);
builder.UseGraphQL<GraphQLHttpMiddlewareWithLogs<TSchema>>(path: graphQlPath, new GraphQLHttpMiddlewareOptions()
{
// configure keep-alive packets
WebSockets = new GraphQLWebSocketOptions()
{
KeepAliveTimeout = TimeSpan.FromSeconds(10), // pass the desired keep-alive timeout
KeepAliveMode = KeepAliveMode.Interval,
}
});

if (schemaIntrospectionEnabled)
{
var playgroundPath = "/ui/playground";
Expand All @@ -34,11 +46,33 @@ public static IApplicationBuilder UseSchemaGraphQL<TSchema>(this IApplicationBui
playgroundPath = $"{playgroundPath}/{schemaPath}";
}

builder.UseGraphQLPlayground(new PlaygroundOptions
{
GraphQLEndPoint = graphQlPath,
},
path: playgroundPath);
#pragma warning disable CS0618 // Type or member is obsolete
// UI Playground
builder.UseGraphQLPlayground(playgroundPath,
new PlaygroundOptions
{
GraphQLEndPoint = graphQlPath,
SubscriptionsEndPoint = graphQlPath,
});
#pragma warning restore CS0618 // Type or member is obsolete

// GraphiQL
var graphiqlPath = "/ui/graphiql";
builder.UseGraphQLGraphiQL(path: graphiqlPath,
new GraphQL.Server.Ui.GraphiQL.GraphiQLOptions
{
GraphQLEndPoint = graphQlPath, // url of GraphQL endpoint
SubscriptionsEndPoint = graphQlPath, // url of GraphQL endpoint
});

// Altair
var altairPath = "/ui/altair";
builder.UseGraphQLAltair(path: altairPath,
new GraphQL.Server.Ui.Altair.AltairOptions
{
GraphQLEndPoint = graphQlPath, // url of GraphQL endpoint
SubscriptionsEndPoint = graphQlPath, // url of GraphQL endpoint
});
}

return builder;
Expand Down
46 changes: 25 additions & 21 deletions src/VirtoCommerce.Xapi.Core/Extensions/AstFieldExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@
using System.Linq;
using GraphQL;
using GraphQL.Execution;
using GraphQL.Language.AST;
using GraphQL.Types;
using GraphQLParser;
using GraphQLParser.AST;
using VirtoCommerce.Platform.Core.Common;

namespace VirtoCommerce.Xapi.Core.Extensions
{
public static class AstFieldExtensions
{
public static IEnumerable<string> GetAllNodesPaths(this IEnumerable<Field> fields, IResolveFieldContext context)
public static IEnumerable<string> GetAllNodesPaths(this IEnumerable<(GraphQLField Field, FieldType FieldType)> fields, IResolveFieldContext context)
{
return fields.SelectMany(x => x.GetAllTreeNodesPaths(context)).Distinct();
return fields.SelectMany(x => x.Field.GetAllTreeNodesPaths(context)).Distinct();
}

private static IEnumerable<string> GetAllTreeNodesPaths(this INode node, IResolveFieldContext context, string path = null)
private static IEnumerable<string> GetAllTreeNodesPaths(this ASTNode node, IResolveFieldContext context, string path = null)
{
if (node is Field field)
if (node is GraphQLField field)
{
path = path != null ? string.Join(".", path, field.Name) : field.Name;
path = path != null ? string.Join(".", path, field.Name.ToString()) : field.Name.ToString();
}

// combine fragment nodes and other children nodes
var combinedNodes = GetCombinedChildrenNodes(node, context);
if (combinedNodes.Any())
if (combinedNodes.Count != 0)
{
var childrenPaths = combinedNodes.Where(n => context != null && ShouldIncludeNode(context, n))
var childrenPaths = combinedNodes.Where(n => context != null && ShouldIncludeNode(n, context))
.SelectMany(n => n.GetAllTreeNodesPaths(context, path));
foreach (var childPath in childrenPaths.DefaultIfEmpty(path))
{
Expand All @@ -38,29 +40,31 @@ private static IEnumerable<string> GetAllTreeNodesPaths(this INode node, IResolv
}
}

private static IEnumerable<INode> GetCombinedChildrenNodes(INode node, IResolveFieldContext context)
private static List<ASTNode> GetCombinedChildrenNodes(ASTNode node, IResolveFieldContext context)
{
var combinedNodes = new List<INode>();
var combinedNodes = new List<ASTNode>();

if (node.Children.IsNullOrEmpty())
if (node is not IHasSelectionSetNode selectionNode ||
selectionNode.SelectionSet == null ||
selectionNode.SelectionSet.Selections.IsNullOrEmpty())
{
return combinedNodes;
}

var fragments = context?.Document?.Fragments;
if (fragments.IsNullOrEmpty())
var fragmentDefenitions = context?.Document?.Definitions?.OfType<GraphQLFragmentDefinition>().ToList();
if (fragmentDefenitions.IsNullOrEmpty())
{
return node.Children ?? combinedNodes;
return selectionNode.SelectionSet.Selections ?? combinedNodes;
}

foreach (var child in node.Children)
foreach (var child in selectionNode.SelectionSet.Selections)
{
if (child is FragmentSpread fragment)
if (child is GraphQLFragmentSpread fragment)
{
var fragmentDefenition = fragments.FirstOrDefault(x => x.Name == fragment.Name);
if (fragmentDefenition?.Children != null)
var fragmentDefenition = fragmentDefenitions.FirstOrDefault(x => x.FragmentName.Name == fragment.FragmentName.Name);
if (fragmentDefenition?.SelectionSet != null && fragmentDefenition.SelectionSet.Selections != null)
{
combinedNodes.AddRange(fragmentDefenition.Children.Where(x => x is not NamedType));
combinedNodes.AddRange(fragmentDefenition.SelectionSet.Selections);
}
}
else
Expand All @@ -72,9 +76,9 @@ private static IEnumerable<INode> GetCombinedChildrenNodes(INode node, IResolveF
return combinedNodes;
}

private static bool ShouldIncludeNode(IResolveFieldContext context, INode node)
private static bool ShouldIncludeNode(ASTNode node, IResolveFieldContext context)
{
var directives = node is IHaveDirectives haveDirectives ? haveDirectives.Directives : null;
var directives = node is IHasDirectivesNode haveDirectives ? haveDirectives.Directives : null;

if (directives != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using GraphQL;
using GraphQL.DataLoader;
using VirtoCommerce.CustomerModule.Core.Services;
using VirtoCommerce.Xapi.Core.Models;
Expand Down
4 changes: 2 additions & 2 deletions src/VirtoCommerce.Xapi.Core/Extensions/FieldTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static FieldBuilder<TSourceType, TReturnType> ResolveSynchronizedAsync<TS
IDistributedLockService distributedLockService,
Func<IResolveFieldContext<TSourceType>, Task<TReturnType>> resolve)
{
async Task<TReturnType> ResolveWrapperAsync(IResolveFieldContext<TSourceType> context)
async ValueTask<TReturnType> ResolveWrapperAsync(IResolveFieldContext<TSourceType> context)
{
// Find resource key in context
var resourceKey = GetResourceKey(context, resourceKeyPrefix, resourceKeyProperty);
Expand All @@ -62,7 +62,7 @@ async Task<TReturnType> ResolveWrapperAsync(IResolveFieldContext<TSourceType> co
: await distributedLockService.ExecuteAsync(resourceKey, async () => await resolve(context));
}

fieldBuilder.FieldType.Resolver = new AsyncFieldResolver<TSourceType, TReturnType>(ResolveWrapperAsync);
fieldBuilder.FieldType.Resolver = new FuncFieldResolver<TSourceType, TReturnType>(ResolveWrapperAsync);

return fieldBuilder;
}
Expand Down
38 changes: 16 additions & 22 deletions src/VirtoCommerce.Xapi.Core/Extensions/GraphQLBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GraphQL.Server;
using GraphQL.Server.Transports.Subscriptions.Abstractions;
using GraphQL.Server.Transports.WebSockets;
using GraphQL;
using GraphQL.DI;
using GraphQL.Validation;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using VirtoCommerce.Xapi.Core.Subscriptions.Infrastructure;
using ServiceLifetime = GraphQL.DI.ServiceLifetime;

namespace VirtoCommerce.Xapi.Core.Extensions
{
Expand All @@ -24,7 +23,7 @@ public static IGraphQLBuilder ReplaceValidationRule<TOldRule, TNewRule>(this IGr
if (oldRule != null)
{
coreRules.Remove(oldRule);
builder.AddCustomValidationRule<TNewRule>();
builder.AddValidationRule<TNewRule>();
}

return builder;
Expand All @@ -33,39 +32,34 @@ public static IGraphQLBuilder ReplaceValidationRule<TOldRule, TNewRule>(this IGr
public static IGraphQLBuilder AddCustomValidationRule<TRule>(this IGraphQLBuilder builder)
where TRule : class, IValidationRule
{
builder.Services.AddSingleton<IValidationRule, TRule>();
builder.Services.Register<IValidationRule, TRule>(ServiceLifetime.Singleton);

return builder;
}

public static IGraphQLBuilder AddCustomValidationRule(this IGraphQLBuilder builder, Type ruleType)
{
builder.Services.AddSingleton(typeof(IValidationRule), ruleType);
builder.Services.Register(typeof(IValidationRule), ruleType);

return builder;
}

public static IGraphQLBuilder AddSchema(this IGraphQLBuilder builder, Type coreAssemblyMarker, Type dataAssemblyMarker)
public static IGraphQLBuilder AddSchema(this IGraphQLBuilder builder, IServiceCollection services, Type assemblyMarker)
{
builder.AddGraphTypes(coreAssemblyMarker);
builder.Services.AddMediatR(coreAssemblyMarker, dataAssemblyMarker);
builder.Services.AddAutoMapper(coreAssemblyMarker, dataAssemblyMarker);
builder.Services.AddSchemaBuilders(dataAssemblyMarker);
builder.AddGraphTypes(assemblyMarker.Assembly);
services.AddMediatR(assemblyMarker);
services.AddAutoMapper(assemblyMarker);
services.AddSchemaBuilders(assemblyMarker);

return builder;
}

/// <summary>
/// Add required services for GraphQL web sockets with custom IWebSocketConnectionFactory implementation
/// </summary>
public static IGraphQLBuilder AddCustomWebSockets(this IGraphQLBuilder builder)
public static IGraphQLBuilder AddSchema(this IGraphQLBuilder builder, IServiceCollection services, Type coreAssemblyMarker, Type dataAssemblyMarker)
{
builder.Services
.AddTransient(typeof(IWebSocketConnectionFactory<>), typeof(CustomWebSocketConnectionFactory<>))
.AddTransient<IOperationMessageListener, LogMessagesListener>()
.AddTransient<IOperationMessageListener, ProtocolMessageListener>()
.AddTransient<IOperationMessageListener, KeepAliveResolver>()
.AddTransient<IOperationMessageListener, SubscriptionsUserContextResolver>();
builder.AddGraphTypes(coreAssemblyMarker.Assembly);
services.AddMediatR(coreAssemblyMarker, dataAssemblyMarker);
services.AddAutoMapper(coreAssemblyMarker, dataAssemblyMarker);
services.AddSchemaBuilders(dataAssemblyMarker);

return builder;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace VirtoCommerce.Xapi.Core.Helpers
{
public static class GraphTypeExtenstionHelper
public static class GraphTypeExtensionHelper
{
/// <summary>
/// Returns the actual (overridden) type for requested type
Expand Down Expand Up @@ -56,28 +56,35 @@ private static Type GetActualComplexTypeRecursive(Type outerGraphType)
return GetActualType(outerGraphType);
}

public static ConnectionBuilder<TSourceType> CreateConnection<TNodeType, TSourceType>() where TNodeType : IGraphType
public static ConnectionBuilder<TSourceType> CreateConnection<TNodeType, TSourceType>(string name) where TNodeType : IGraphType
{
return CreateConnection<TNodeType, EdgeType<TNodeType>, ConnectionType<TNodeType>, TSourceType>();
return CreateConnection<TNodeType, EdgeType<TNodeType>, ConnectionType<TNodeType>, TSourceType>(name);
}

public static ConnectionBuilder<TSourceType> CreateConnection<TNodeType, TEdgeType, TConnectionType, TSourceType>()
public static ConnectionBuilder<TSourceType> CreateConnection<TNodeType, TEdgeType, TConnectionType, TSourceType>(string name)
where TNodeType : IGraphType
where TEdgeType : EdgeType<TNodeType>
where TConnectionType : ConnectionType<TNodeType, TEdgeType>
{
//EdgeType<ProductType>, ProductsConnectonType<ProductType>
//Try first find the actual TNodeType in the AbstractTypeFactory
var actualNodeType = GetActualType<TNodeType>();
var createMethodInfo = typeof(ConnectionBuilder<>).MakeGenericType(typeof(TSourceType)).GetMethods().FirstOrDefault(x => x.Name.EqualsInvariant(nameof(ConnectionBuilder.Create)) && x.GetGenericArguments().Length == 3);
var createMethodInfo = typeof(ConnectionBuilder<>).MakeGenericType(typeof(TSourceType)).GetMethods()
.FirstOrDefault(x => x.Name.EqualsInvariant(nameof(ConnectionBuilder.Create))
&& x.GetGenericArguments().Length == 3
&& x.GetParameters().Length == 1);

if (createMethodInfo == null)
{
throw new PlatformException("No suitable 'ConnectionBuilder.Create' method with three generic types found");
}

var genericEgdeType = typeof(TEdgeType).GetGenericTypeDefinition().MakeGenericType(new[] { actualNodeType });
var genericConnectionType = typeof(TConnectionType).GetGenericTypeDefinition().MakeGenericType(new[] { actualNodeType });
var connectionBuilder = (ConnectionBuilder<TSourceType>)createMethodInfo.MakeGenericMethod(actualNodeType, genericEgdeType, genericConnectionType).Invoke(null, new[] { Type.Missing });
var connectionBuilder = (ConnectionBuilder<TSourceType>)createMethodInfo
.MakeGenericMethod(actualNodeType, genericEgdeType, genericConnectionType)
.Invoke(null, new[] { name });

return connectionBuilder;
}
}
Expand Down
18 changes: 0 additions & 18 deletions src/VirtoCommerce.Xapi.Core/Infrastructure/CustomGraphQLBuilder.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public CustomSchemaFilter(IOptions<GraphQLPlaygroundOptions> playgroundOptions)

public Task<bool> AllowType(IGraphType type) => _isAllowed;

public Task<bool> AllowDirective(DirectiveGraphType directive) => _isAllowed;
public Task<bool> AllowDirective(Directive directive) => _isAllowed;

public Task<bool> AllowArgument(IFieldType field, QueryArgument argument) => _isAllowed;

Expand Down
Loading
Loading