diff --git a/src/Core/Abstractions/ErrorBuilderExtensions.cs b/src/Core/Abstractions/ErrorBuilderExtensions.cs index d63614ab466..d9839ce4774 100644 --- a/src/Core/Abstractions/ErrorBuilderExtensions.cs +++ b/src/Core/Abstractions/ErrorBuilderExtensions.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System; using HotChocolate.Language; @@ -27,5 +28,14 @@ public static IErrorBuilder AddLocation( } return builder; } + + public static IErrorBuilder SetMessage( + this IErrorBuilder builder, + string format, + params object[] args) => + builder.SetMessage(string.Format( + CultureInfo.InvariantCulture, + format, + args)); } } diff --git a/src/Core/Abstractions/Execution/IVariableValueCollection.cs b/src/Core/Abstractions/Execution/IVariableValueCollection.cs index 9ade2573c2b..72e328cdbbf 100644 --- a/src/Core/Abstractions/Execution/IVariableValueCollection.cs +++ b/src/Core/Abstractions/Execution/IVariableValueCollection.cs @@ -6,7 +6,7 @@ public interface IVariableValueCollection { /// - /// Gets a coreced variable value from the collection. + /// Gets a coerced variable value from the collection. /// /// The variable name. /// @@ -22,7 +22,7 @@ public interface IVariableValueCollection T GetVariable(NameString name); /// - /// Tries to get a coreced variable value from the collection. + /// Tries to get a coerced variable value from the collection. /// /// The variable name. /// The coerced variable value. diff --git a/src/Core/Core.sln b/src/Core/Core.sln index 9b91ff8bc35..9e90018dc7b 100644 --- a/src/Core/Core.sln +++ b/src/Core/Core.sln @@ -41,13 +41,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Filters.Tests", "Type EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Tests.Documentation", "Types.Tests.Documentation\Types.Tests.Documentation.csproj", "{38537BB2-BDD9-4842-BD2D-0B84B371F1D8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersistedQueries.FileSystem", "PersistedQueries.FileSystem\PersistedQueries.FileSystem.csproj", "{BC4DAE10-B145-4F9F-9504-BF5EA4C42A60}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersistedQueries.FileSystem", "PersistedQueries.FileSystem\PersistedQueries.FileSystem.csproj", "{BC4DAE10-B145-4F9F-9504-BF5EA4C42A60}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Subscriptions.Redis", "Subscriptions.Redis\Subscriptions.Redis.csproj", "{85660981-4992-49A8-A786-D6FB82E01463}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Subscriptions.Redis", "Subscriptions.Redis\Subscriptions.Redis.csproj", "{85660981-4992-49A8-A786-D6FB82E01463}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StarWars", "StarWars\StarWars.csproj", "{6D66B162-D2F6-411E-8F9C-F0B3AB5A9289}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StarWars", "StarWars\StarWars.csproj", "{6D66B162-D2F6-411E-8F9C-F0B3AB5A9289}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersistedQueries.Redis", "PersistedQueries.Redis\PersistedQueries.Redis.csproj", "{B4CC72E4-C93E-4AFB-8381-BFF6F4B06CC9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersistedQueries.Redis", "PersistedQueries.Redis\PersistedQueries.Redis.csproj", "{B4CC72E4-C93E-4AFB-8381-BFF6F4B06CC9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersistedQueries.FileSystem.Tests", "PersistedQueries.FileSystem.Tests\PersistedQueries.FileSystem.Tests.csproj", "{F3657CF0-6B18-4021-8CCF-A7C131E4F745}" EndProject @@ -63,9 +63,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenDonut", "..\DataLoader EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting", "Types.Sorting\Types.Sorting.csproj", "{F3B8AE0B-C6D9-4B45-8131-40E93CFE6BB3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting.Tests", "Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{A23C8758-6173-46F8-B132-28E5B75846B0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Tests", "Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{A23C8758-6173-46F8-B132-28E5B75846B0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting.Mongo.Tests", "Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{E8843255-77EB-471F-B682-528BB4B5D1D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Mongo.Tests", "Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{E8843255-77EB-471F-B682-528BB4B5D1D5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Core/Core/Execution/Extensions/QueryExecutionBuilderExtensions.cs b/src/Core/Core/Execution/Extensions/QueryExecutionBuilderExtensions.cs index 602d4230b1b..6ae98f99b4b 100644 --- a/src/Core/Core/Execution/Extensions/QueryExecutionBuilderExtensions.cs +++ b/src/Core/Core/Execution/Extensions/QueryExecutionBuilderExtensions.cs @@ -22,8 +22,7 @@ public static IQueryExecutionBuilder UseDefaultPipeline( throw new ArgumentNullException(nameof(builder)); } - return builder - .UseDefaultPipeline(new QueryExecutionOptions()); + return builder.UseDefaultPipeline(new QueryExecutionOptions()); } public static IQueryExecutionBuilder UseDefaultPipeline( @@ -119,7 +118,7 @@ public static IQueryExecutionBuilder UseActivePersistedQueryPipeline( .UseWritePersistedQuery(); } - private static IQueryExecutionBuilder AddDefaultServices( + public static IQueryExecutionBuilder AddDefaultServices( this IQueryExecutionBuilder builder, IQueryExecutionOptionsAccessor options) { @@ -134,7 +133,7 @@ private static IQueryExecutionBuilder AddDefaultServices( .AddDefaultDocumentHashProvider(); } - private static IQueryExecutionBuilder UseDefaultDiagnostics( + public static IQueryExecutionBuilder UseDefaultDiagnostics( this IQueryExecutionBuilder builder, IInstrumentationOptionsAccessor options) { diff --git a/src/Core/Core/Execution/Utilities/DictionaryToObjectValueConverter.cs b/src/Core/Core/Execution/Utilities/DictionaryToObjectValueConverter.cs index 8eb328feb3c..1e21c04612d 100644 --- a/src/Core/Core/Execution/Utilities/DictionaryToObjectValueConverter.cs +++ b/src/Core/Core/Execution/Utilities/DictionaryToObjectValueConverter.cs @@ -13,11 +13,6 @@ internal class DictionaryToObjectValueConverter { public IValueNode Convert(object from, IInputType type, VariableDefinitionNode variable) { - if (from == null) - { - throw new ArgumentNullException(nameof(from)); - } - if (type is null) { throw new ArgumentNullException(nameof(type)); @@ -35,7 +30,28 @@ public IValueNode Convert(object from, IInputType type, VariableDefinitionNode v Name = "$" + variable.Variable.Name.Value }; Visit(from, context); - return (IValueNode)context.Object; + return from is null ? NullValueNode.Default : (IValueNode)context.Object; + } + + public IValueNode Convert(object from, IInputType type, string variableName) + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (variableName is null) + { + throw new ArgumentNullException(nameof(variableName)); + } + + var context = new ConverterContext + { + InputType = type, + Name = "$" + variableName + }; + Visit(from, context); + return from is null ? NullValueNode.Default : (IValueNode)context.Object; } protected override void VisitObject( diff --git a/src/Core/Core/Execution/Utilities/VariableValueBuilder.cs b/src/Core/Core/Execution/Utilities/VariableValueBuilder.cs index 6bb09360771..471f1ad5ed0 100644 --- a/src/Core/Core/Execution/Utilities/VariableValueBuilder.cs +++ b/src/Core/Core/Execution/Utilities/VariableValueBuilder.cs @@ -98,8 +98,7 @@ private Variable CoerceVariableValue( IReadOnlyDictionary variableValues, Variable variable) { - var value = variableValues.TryGetValue( - variable.Name, out var rawValue) + var value = variableValues.TryGetValue(variable.Name, out var rawValue) ? Normalize(variableDefinition, variable, rawValue) : variable.DefaultValue; @@ -197,14 +196,9 @@ private static void CheckForInvalidValueType( if (variable.Value != null) { - if (variable.Value is IValueNode literal) - { - invalid = !variable.Type.IsInstanceOfType(literal); - } - else - { - invalid = !variable.Type.IsInstanceOfType(variable.Value); - } + invalid = variable.Value is IValueNode literal + ? !variable.Type.IsInstanceOfType(literal) + : !variable.Type.IsInstanceOfType(variable.Value); } if (invalid) @@ -255,8 +249,7 @@ private IType GetType(ITypeNode typeNode) return _schema.GetType(namedType.Name.Value); } - throw new NotSupportedException( - TypeResources.VariableValueBuilder_NodeKind); + throw new NotSupportedException(TypeResources.VariableValueBuilder_NodeKind); } private ref struct Variable diff --git a/src/Core/Core/Properties/InternalsVisibleTo.cs b/src/Core/Core/Properties/InternalsVisibleTo.cs index edd3026a15e..64a008a6546 100644 --- a/src/Core/Core/Properties/InternalsVisibleTo.cs +++ b/src/Core/Core/Properties/InternalsVisibleTo.cs @@ -3,3 +3,6 @@ [assembly: InternalsVisibleTo("HotChocolate.Core.Tests")] [assembly: InternalsVisibleTo("HotChocolate.Validation.Tests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] + +// this is temporary until we reworked the variable coercion #1274 +[assembly: InternalsVisibleTo("HotChocolate.Stitching")] diff --git a/src/Core/Language/Parser/GraphQLConstants.cs b/src/Core/Language/Parser/GraphQLConstants.cs index 3d708056f5c..d8d1afe139f 100644 --- a/src/Core/Language/Parser/GraphQLConstants.cs +++ b/src/Core/Language/Parser/GraphQLConstants.cs @@ -5,7 +5,7 @@ namespace HotChocolate.Language /// /// This class provides internal char utilities /// that are used to tokenize a GraphQL source text. - /// These utilities are used by the lexer dfault implementation. + /// These utilities are used by the lexer default implementation. /// internal static partial class GraphQLConstants { diff --git a/src/Core/Utilities/BufferHelper.cs b/src/Core/Utilities/BufferHelper.cs index c2e47e004c0..a75da4de492 100644 --- a/src/Core/Utilities/BufferHelper.cs +++ b/src/Core/Utilities/BufferHelper.cs @@ -31,8 +31,7 @@ public static async Task ReadAsync( if (bytesRemaining == 0) { - var next = ArrayPool.Shared.Rent( - buffer.Length * 2); + var next = ArrayPool.Shared.Rent(buffer.Length * 2); Buffer.BlockCopy(buffer, 0, next, 0, buffer.Length); ArrayPool.Shared.Return(buffer); buffer = next; diff --git a/src/Server/Server.sln b/src/Server/Server.sln index ee311e07e43..22f1c5b14df 100644 --- a/src/Server/Server.sln +++ b/src/Server/Server.sln @@ -59,7 +59,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Abstractions", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Tests.Utilities", "AspNetCore.Tests.Utilities\AspNetCore.Tests.Utilities.csproj", "{AF440449-DBE1-40AB-B155-87C3B31E7378}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StarWars", "..\Core\StarWars\StarWars.csproj", "{9CA71125-2837-4F92-9822-CB41B64E2E43}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StarWars", "..\Core\StarWars\StarWars.csproj", "{9CA71125-2837-4F92-9822-CB41B64E2E43}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetClassic.Abstractions", "AspNetClassic.Abstractions\AspNetClassic.Abstractions.csproj", "{B930D413-E013-4DE6-B1AB-C88BE946E615}" EndProject diff --git a/src/Stitching/.vscode/tasks.json b/src/Stitching/.vscode/tasks.json new file mode 100644 index 00000000000..31c32bd3457 --- /dev/null +++ b/src/Stitching/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + // Ask dotnet build to generate full paths for file names. + "/property:GenerateFullPaths=true", + // Do not generate summary otherwise it leads to duplicate errors in Problems panel + "/consoleloggerparameters:NoSummary" + ], + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/src/Stitching/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap b/src/Stitching/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap index 101e2a23d84..c3a918ad743 100644 --- a/src/Stitching/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap +++ b/src/Stitching/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap @@ -189,7 +189,7 @@ }, "QueryName": null, "QueryHash": null, - "OperationName": null, + "OperationName": "exec_batch", "VariableValues": { "__0__a": "foo" }, diff --git a/src/Stitching/Stitching.Tests/Delegation/ArgumentScopedVariableResolverTests.cs b/src/Stitching/Stitching.Tests/Delegation/ArgumentScopedVariableResolverTests.cs index 03745d454bd..c852631cad2 100644 --- a/src/Stitching/Stitching.Tests/Delegation/ArgumentScopedVariableResolverTests.cs +++ b/src/Stitching/Stitching.Tests/Delegation/ArgumentScopedVariableResolverTests.cs @@ -1,5 +1,4 @@ using System; -using ChilliCream.Testing; using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Resolvers; @@ -24,10 +23,9 @@ public void CreateVariableValue() }); var context = new Mock(MockBehavior.Strict); - context.SetupGet(t => t.Field).Returns( - schema.GetType("Query").Fields["foo"]); - context.Setup(t => t.Argument("a")) - .Returns("baz"); + ObjectField field = schema.GetType("Query").Fields["foo"]; + context.SetupGet(t => t.Field).Returns(field); + context.Setup(t => t.Argument("a")).Returns(new StringValueNode("baz")); var scopedVariable = new ScopedVariableNode( null, @@ -37,15 +35,15 @@ public void CreateVariableValue() // act var resolver = new ArgumentScopedVariableResolver(); VariableValue value = resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("bar", - Assert.IsType(value.DefaultValue).Value); + Assert.Equal("bar", Assert.IsType(value.DefaultValue).Value); Assert.Equal("arguments_a", value.Name); - Assert.IsType(value.Type); - Assert.Equal("baz", value.Value); + Assert.Equal("String", Assert.IsType(value.Type).Name.Value); + Assert.Equal("baz", value.Value.Value); } [Fact] @@ -83,8 +81,9 @@ public void ArgumentDoesNotExist() // act var resolver = new ArgumentScopedVariableResolver(); Action a = () => resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Collection( @@ -111,8 +110,10 @@ public void ContextIsNull() // act var resolver = new ArgumentScopedVariableResolver(); - Action a = () => resolver.Resolve(null, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + null, + scopedVariable, + schema.GetType("String")); // assert Assert.Equal("context", @@ -139,8 +140,10 @@ public void ScopedVariableIsNull() // act var resolver = new ArgumentScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, null, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + null, + schema.GetType("String")); // assert Assert.Equal("variable", @@ -160,10 +163,9 @@ public void InvalidScope() }); var context = new Mock(); - context.SetupGet(t => t.Field).Returns( - schema.GetType("Query").Fields["foo"]); - context.Setup(t => t.Argument(It.IsAny())) - .Returns("Baz"); + ObjectField field = schema.GetType("Query").Fields["foo"]; + context.SetupGet(t => t.Field).Returns(field); + context.Setup(t => t.Argument(It.IsAny())).Returns("Baz"); var scopedVariable = new ScopedVariableNode( null, @@ -172,8 +174,10 @@ public void InvalidScope() // act var resolver = new ArgumentScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Equal("variable", diff --git a/src/Stitching/Stitching.Tests/Delegation/ContextDataScopedVariableResolverTests.cs b/src/Stitching/Stitching.Tests/Delegation/ContextDataScopedVariableResolverTests.cs index 8f4e74623ae..e99ad5c8c0e 100644 --- a/src/Stitching/Stitching.Tests/Delegation/ContextDataScopedVariableResolverTests.cs +++ b/src/Stitching/Stitching.Tests/Delegation/ContextDataScopedVariableResolverTests.cs @@ -1,10 +1,7 @@ using System; using System.Collections.Generic; -using ChilliCream.Testing; -using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Resolvers; -using HotChocolate.Stitching.Delegation; using HotChocolate.Types; using Moq; using Xunit; @@ -39,15 +36,15 @@ public void CreateVariableValue() // act var resolver = new ContextDataScopedVariableResolver(); VariableValue value = resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Null(value.DefaultValue); Assert.Equal("contextData_a", value.Name); - Assert.Equal("abc", - Assert.IsType(value.Type).Name.Value); - Assert.Equal("AbcDef", value.Value); + Assert.Equal("String", Assert.IsType(value.Type).Name.Value); + Assert.Equal("AbcDef", value.Value.Value); } [Fact] @@ -75,15 +72,15 @@ public void ContextDataEntryDoesNotExist() // act var resolver = new ContextDataScopedVariableResolver(); VariableValue value = resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Null(value.DefaultValue); Assert.Equal("contextData_a", value.Name); - Assert.Equal("abc", - Assert.IsType(value.Type).Name.Value); - Assert.Null(value.Value); + Assert.Equal("String", Assert.IsType(value.Type).Name.Value); + Assert.Equal(NullValueNode.Default, value.Value); } @@ -106,12 +103,13 @@ public void ContextIsNull() // act var resolver = new ContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(null, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + null, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("context", - Assert.Throws(a).ParamName); + Assert.Equal("context", Assert.Throws(a).ParamName); } [Fact] @@ -130,12 +128,13 @@ public void ScopedVariableIsNull() // act var resolver = new ContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, null, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + null, + schema.GetType("String")); // assert - Assert.Equal("variable", - Assert.Throws(a).ParamName); + Assert.Equal("variable", Assert.Throws(a).ParamName); } [Fact] @@ -159,12 +158,13 @@ public void TargetTypeIsNull() // act var resolver = new ContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, null); // assert - Assert.Equal("targetType", - Assert.Throws(a).ParamName); + Assert.Equal("targetType", Assert.Throws(a).ParamName); } [Fact] @@ -188,12 +188,13 @@ public void InvalidScope() // act var resolver = new ContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("variable", - Assert.Throws(a).ParamName); + Assert.Equal("variable", Assert.Throws(a).ParamName); } } } diff --git a/src/Stitching/Stitching.Tests/Delegation/FieldScopedVariableResolverTests.cs b/src/Stitching/Stitching.Tests/Delegation/FieldScopedVariableResolverTests.cs index 92087001f4d..7a90a2a4d13 100644 --- a/src/Stitching/Stitching.Tests/Delegation/FieldScopedVariableResolverTests.cs +++ b/src/Stitching/Stitching.Tests/Delegation/FieldScopedVariableResolverTests.cs @@ -3,7 +3,6 @@ using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Resolvers; -using HotChocolate.Stitching.Delegation; using HotChocolate.Types; using Moq; using Xunit; @@ -40,14 +39,15 @@ public void CreateVariableValue() // act var resolver = new FieldScopedVariableResolver(); VariableValue value = resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Null(value.DefaultValue); Assert.Equal("fields_a", value.Name); Assert.IsType(value.Type); - Assert.Equal("baz", value.Value); + Assert.Equal("baz", value.Value.Value); } [Fact] @@ -86,8 +86,10 @@ public void FieldDoesNotExist() // act var resolver = new FieldScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Collection( @@ -114,12 +116,13 @@ public void ContextIsNull() // act var resolver = new FieldScopedVariableResolver(); - Action a = () => resolver.Resolve(null, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + null, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("context", - Assert.Throws(a).ParamName); + Assert.Equal("context", Assert.Throws(a).ParamName); } [Fact] @@ -142,12 +145,13 @@ public void ScopedVariableIsNull() // act var resolver = new FieldScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, null, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + null, + schema.GetType("String")); // assert - Assert.Equal("variable", - Assert.Throws(a).ParamName); + Assert.Equal("variable", Assert.Throws(a).ParamName); } [Fact] @@ -175,12 +179,13 @@ public void InvalidScope() // act var resolver = new FieldScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("variable", - Assert.Throws(a).ParamName); + Assert.Equal("variable", Assert.Throws(a).ParamName); } } } diff --git a/src/Stitching/Stitching.Tests/Delegation/ScopedContextDataScopedVariableResolverTests.cs b/src/Stitching/Stitching.Tests/Delegation/ScopedContextDataScopedVariableResolverTests.cs index b2b16f85108..a30a5c52dd1 100644 --- a/src/Stitching/Stitching.Tests/Delegation/ScopedContextDataScopedVariableResolverTests.cs +++ b/src/Stitching/Stitching.Tests/Delegation/ScopedContextDataScopedVariableResolverTests.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; using System.Collections.Immutable; -using ChilliCream.Testing; -using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Resolvers; -using HotChocolate.Stitching.Delegation; using HotChocolate.Types; using Moq; using Xunit; @@ -40,15 +36,15 @@ public void CreateVariableValue() // act var resolver = new ScopedContextDataScopedVariableResolver(); VariableValue value = resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Null(value.DefaultValue); Assert.Equal("scopedContextData_a", value.Name); - Assert.Equal("abc", - Assert.IsType(value.Type).Name.Value); - Assert.Equal("AbcDef", value.Value); + Assert.Equal("String", Assert.IsType(value.Type).Name.Value); + Assert.Equal("AbcDef", value.Value.Value); } [Fact] @@ -76,15 +72,15 @@ public void ContextDataEntryDoesNotExist() // act var resolver = new ScopedContextDataScopedVariableResolver(); VariableValue value = resolver.Resolve( - context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + context.Object, + scopedVariable, + schema.GetType("String")); // assert Assert.Null(value.DefaultValue); Assert.Equal("scopedContextData_a", value.Name); - Assert.Equal("abc", - Assert.IsType(value.Type).Name.Value); - Assert.Null(value.Value); + Assert.Equal("String", Assert.IsType(value.Type).Name.Value); + Assert.Equal(NullValueNode.Default, value.Value); } @@ -107,12 +103,13 @@ public void ContextIsNull() // act var resolver = new ScopedContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(null, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + null, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("context", - Assert.Throws(a).ParamName); + Assert.Equal("context", Assert.Throws(a).ParamName); } [Fact] @@ -131,12 +128,13 @@ public void ScopedVariableIsNull() // act var resolver = new ScopedContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, null, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + null, + schema.GetType("String")); // assert - Assert.Equal("variable", - Assert.Throws(a).ParamName); + Assert.Equal("variable", Assert.Throws(a).ParamName); } [Fact] @@ -160,12 +158,13 @@ public void TargetTypeIsNull() // act var resolver = new ScopedContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, null); // assert - Assert.Equal("targetType", - Assert.Throws(a).ParamName); + Assert.Equal("targetType", Assert.Throws(a).ParamName); } [Fact] @@ -189,12 +188,13 @@ public void InvalidScope() // act var resolver = new ScopedContextDataScopedVariableResolver(); - Action a = () => resolver.Resolve(context.Object, scopedVariable, - new NamedTypeNode(new NameNode("abc"))); + Action a = () => resolver.Resolve( + context.Object, + scopedVariable, + schema.GetType("String")); // assert - Assert.Equal("variable", - Assert.Throws(a).ParamName); + Assert.Equal("variable", Assert.Throws(a).ParamName); } } } diff --git a/src/Stitching/Stitching.Tests/Middleware/DelegateToRemoteSchemaMiddlewareTests.cs b/src/Stitching/Stitching.Tests/Middleware/DelegateToRemoteSchemaMiddlewareTests.cs index 1f03dc056a0..51e99592370 100644 --- a/src/Stitching/Stitching.Tests/Middleware/DelegateToRemoteSchemaMiddlewareTests.cs +++ b/src/Stitching/Stitching.Tests/Middleware/DelegateToRemoteSchemaMiddlewareTests.cs @@ -1210,9 +1210,8 @@ ... on LifeInsuranceContract { Snapshot.Match(result); } - public async Task - ExecutedMutationWithRenamedInputField( - IQueryRequestBuilder requestBuilder) + public async Task ExecutedMutationWithRenamedInputField( + IQueryRequestBuilder requestBuilder) { IHttpClientFactory clientFactory = CreateRemoteSchemas(); @@ -1221,11 +1220,8 @@ public async Task serviceCollection.AddStitchedSchema(builder => builder.AddSchemaFromHttp("contract") .AddSchemaFromHttp("customer") - .RenameField( - new FieldReference("CreateCustomerInput", "name"), - "foo") - .AddExtensionsFromString( - FileResource.Open("StitchingExtensions.graphql")) + .RenameField(new FieldReference("CreateCustomerInput", "name"), "foo") + .AddExtensionsFromString(FileResource.Open("StitchingExtensions.graphql")) .AddSchemaConfiguration(c => { c.RegisterType(); diff --git a/src/Stitching/Stitching.Tests/Middleware/HttpInterceptorTests.cs b/src/Stitching/Stitching.Tests/Middleware/HttpInterceptorTests.cs index 944db07dcfd..7c704af4506 100644 --- a/src/Stitching/Stitching.Tests/Middleware/HttpInterceptorTests.cs +++ b/src/Stitching/Stitching.Tests/Middleware/HttpInterceptorTests.cs @@ -79,7 +79,7 @@ public class DummyInterceptor : IHttpQueryRequestInterceptor { public Task OnResponseReceivedAsync( - IHttpQueryRequest request, + IReadOnlyQueryRequest request, HttpResponseMessage response, IQueryResult result) { diff --git a/src/Stitching/Stitching.Tests/Middleware/ScalarTests.cs b/src/Stitching/Stitching.Tests/Middleware/ScalarTests.cs index c1522859f52..889bc0c12ab 100644 --- a/src/Stitching/Stitching.Tests/Middleware/ScalarTests.cs +++ b/src/Stitching/Stitching.Tests/Middleware/ScalarTests.cs @@ -118,6 +118,121 @@ public async Task Custom_Scalar_Types() result.MatchSnapshot(); } + [Fact] + public async Task Custom_Scalar_Delegated_Argument() + { + // arrange + IHttpClientFactory clientFactory = CreateRemoteSchemas(); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(clientFactory); + serviceCollection.AddStitchedSchema(builder => builder + .AddSchemaFromHttp("special") + .AddExtensionsFromString("extend type Query { custom_scalar_stitched(bar: MyCustomScalarValue): MyCustomScalarValue @delegate(schema: \"special\", path: \"custom_scalar(bar: $arguments:bar)\") }") + .AddSchemaConfiguration(c => { + c.RegisterType(); + })); + + IServiceProvider services = + serviceCollection.BuildServiceProvider(); + + IQueryExecutor executor = services + .GetRequiredService(); + IExecutionResult result = null; + + // act + using (IServiceScope scope = services.CreateScope()) + { + IReadOnlyQueryRequest request = + QueryRequestBuilder.New() + .SetQuery("{ custom_scalar_stitched(bar: \"2019-11-11\") }") + .SetServices(scope.ServiceProvider) + .Create(); + + result = await executor.ExecuteAsync(request); + } + + // assert + result.MatchSnapshot(); + } + + [Fact] + public async Task Custom_Scalar_Delegated_Input_Argument() + { + // arrange + IHttpClientFactory clientFactory = CreateRemoteSchemas(); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(clientFactory); + serviceCollection.AddStitchedSchema(builder => builder + .AddSchemaFromHttp("special") + .AddExtensionsFromString("extend type Query { custom_scalar_complex_stitched(bar: CustomInputValueInput): MyCustomScalarValue @delegate(schema: \"special\", path: \"custom_scalar_complex(bar: $arguments:bar)\") }") + .AddSchemaConfiguration(c => { + c.RegisterType(); + })); + + IServiceProvider services = + serviceCollection.BuildServiceProvider(); + + IQueryExecutor executor = services + .GetRequiredService(); + IExecutionResult result = null; + + // act + using (IServiceScope scope = services.CreateScope()) + { + IReadOnlyQueryRequest request = + QueryRequestBuilder.New() + .SetQuery("query ($bar: CustomInputValueInput) { custom_scalar_complex_stitched(bar: $bar) }") + .SetVariableValue("bar", new Dictionary { { "from", "2019-11-11" }, { "to", "2019-11-17" } }) + .SetServices(scope.ServiceProvider) + .Create(); + + result = await executor.ExecuteAsync(request); + } + + // assert + result.MatchSnapshot(); + } + + [Fact] + public async Task Custom_Scalar_Delegated_Input_Argument_Unstitched() + { + // arrange + IHttpClientFactory clientFactory = CreateRemoteSchemas(); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(clientFactory); + serviceCollection.AddStitchedSchema(builder => builder + .AddSchemaFromHttp("special") + .AddSchemaConfiguration(c => { + c.RegisterType(); + })); + + IServiceProvider services = + serviceCollection.BuildServiceProvider(); + + IQueryExecutor executor = services + .GetRequiredService(); + IExecutionResult result = null; + + // act + using (IServiceScope scope = services.CreateScope()) + { + IReadOnlyQueryRequest request = + QueryRequestBuilder.New() + .SetQuery("query ($bar: CustomInputValueInput) { custom_scalar_complex(bar: $bar) }") + .SetVariableValue("bar", new Dictionary { { "from", "2019-11-11" }, { "to", "2019-11-17" } }) + .SetServices(scope.ServiceProvider) + .Create(); + + result = await executor.ExecuteAsync(request); + } + + // assert + result.MatchSnapshot(); + } + protected override IHttpClientFactory CreateRemoteSchemas( Dictionary connections) { diff --git a/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Argument.snap b/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Argument.snap new file mode 100644 index 00000000000..2c9de14a72f --- /dev/null +++ b/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Argument.snap @@ -0,0 +1,8 @@ +{ + "Data": { + "custom_scalar_stitched": "2019-11-11" + }, + "Extensions": {}, + "Errors": [], + "ContextData": {} +} diff --git a/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Input_Argument.snap b/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Input_Argument.snap new file mode 100644 index 00000000000..839a97bdee4 --- /dev/null +++ b/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Input_Argument.snap @@ -0,0 +1,8 @@ +{ + "Data": { + "custom_scalar_complex_stitched": "2019-11-11-2019-11-17" + }, + "Extensions": {}, + "Errors": [], + "ContextData": {} +} diff --git a/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Input_Argument_Unstitched.snap b/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Input_Argument_Unstitched.snap new file mode 100644 index 00000000000..7817d283951 --- /dev/null +++ b/src/Stitching/Stitching.Tests/Middleware/__snapshots__/ScalarTests.Custom_Scalar_Delegated_Input_Argument_Unstitched.snap @@ -0,0 +1,8 @@ +{ + "Data": { + "custom_scalar_complex": "2019-11-11-2019-11-17" + }, + "Extensions": {}, + "Errors": [], + "ContextData": {} +} diff --git a/src/Stitching/Stitching.Tests/Schemas/SpecialCases/ContractSchemaFactory.cs b/src/Stitching/Stitching.Tests/Schemas/SpecialCases/ContractSchemaFactory.cs index 92ffaf40ba2..e1ca7eefb9e 100644 --- a/src/Stitching/Stitching.Tests/Schemas/SpecialCases/ContractSchemaFactory.cs +++ b/src/Stitching/Stitching.Tests/Schemas/SpecialCases/ContractSchemaFactory.cs @@ -29,22 +29,33 @@ protected override void Configure(IObjectTypeDescriptor descriptor) descriptor.Field("custom_scalar") .Type() .Argument("bar", a => a.Type()) - .Resolver(ctx => ctx.Argument("bar")); + .Resolver(ctx => ctx.Argument("bar")); + + descriptor.Field("custom_scalar_complex") + .Type() + .Argument("bar", a => a.Type()) + .Resolver(ctx => { + CustomInputValue input = ctx.Argument("bar"); + + return new MyCustomScalarValue { Text = $"{input.From.Text}-{input.To.Text}" }; + }); } } + public class MyCustomScalarValue + { + public string Text { get; set; } + } + public class MyCustomScalarType : ScalarType { - /// - /// Initializes a new instance of the class. - /// public MyCustomScalarType() - : base("Custom") + : base(nameof(MyCustomScalarValue)) { } - public override Type ClrType => typeof(string); + public override Type ClrType => typeof(MyCustomScalarValue); public override bool IsInstanceOfType(IValueNode literal) { @@ -66,7 +77,7 @@ public override object ParseLiteral(IValueNode literal) if (literal is StringValueNode stringLiteral) { - return stringLiteral.Value; + return new MyCustomScalarValue { Text = stringLiteral.Value }; } if (literal is NullValueNode) @@ -84,9 +95,9 @@ public override IValueNode ParseValue(object value) return new NullValueNode(null); } - if (value is string s) + if (value is MyCustomScalarValue s) { - return new StringValueNode(null, s, false); + return new StringValueNode(null, s.Text, false); } throw new ScalarSerializationException("some text"); @@ -99,9 +110,9 @@ public override object Serialize(object value) return null; } - if (value is string s) + if (value is MyCustomScalarValue s) { - return s; + return s.Text; } throw new ScalarSerializationException("some text"); @@ -117,7 +128,7 @@ public override bool TryDeserialize(object serialized, out object value) if (serialized is string s) { - value = s; + value = new MyCustomScalarValue { Text = s }; return true; } @@ -125,4 +136,25 @@ public override bool TryDeserialize(object serialized, out object value) return false; } } + + public class CustomInputValue + { + public MyCustomScalarValue From { get; set; } + + public MyCustomScalarValue To { get; set; } + } + + public class CustomInputValueType : InputObjectType + { + protected override void Configure(IInputObjectTypeDescriptor descriptor) + { + base.Configure(descriptor); + + descriptor.Field(i => i.From) + .Type>(); + + descriptor.Field(i => i.To) + .Type>(); + } + } } diff --git a/src/Stitching/Stitching.Tests/StitchingBuilderTests.cs b/src/Stitching/Stitching.Tests/StitchingBuilderTests.cs index dd4285dfe50..d4cb59506ef 100644 --- a/src/Stitching/Stitching.Tests/StitchingBuilderTests.cs +++ b/src/Stitching/Stitching.Tests/StitchingBuilderTests.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Net.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; using ChilliCream.Testing; using HotChocolate.AspNetCore; using HotChocolate.AspNetCore.Tests.Utilities; @@ -14,8 +16,6 @@ using HotChocolate.Stitching.Schemas.Contracts; using HotChocolate.Stitching.Schemas.Customers; using HotChocolate.Utilities; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using Moq; using Snapshooter.Xunit; using Xunit; @@ -66,15 +66,15 @@ public void AddSchema_SchemaAlreadyRegistered_ArgumentNullException() { // arrange StitchingBuilder stitchingBuilder = StitchingBuilder.New(); - NameString schemName = "abc"; + NameString schemaName = "abc"; stitchingBuilder.AddSchema( - schemName, + schemaName, sp => new DocumentNode(new List())); // act Action action = () => stitchingBuilder.AddSchema( - schemName, + schemaName, sp => new DocumentNode(new List())); // assert @@ -87,15 +87,15 @@ public void AddSchema_SchemaAlreadyRegistered_2_ArgumentNullException() { // arrange StitchingBuilder stitchingBuilder = StitchingBuilder.New(); - NameString schemName = "abc"; + NameString schemaName = "abc"; stitchingBuilder.AddQueryExecutor( - schemName, + schemaName, sp => default(IQueryExecutor)); // act Action action = () => stitchingBuilder.AddSchema( - schemName, + schemaName, sp => new DocumentNode(new List())); // assert @@ -108,7 +108,7 @@ public void AddSchema_SchemaNameIsEmpty_ArgumentNullException() { // arrange StitchingBuilder stitchingBuilder = StitchingBuilder.New(); - NameString schemName = "abc"; + NameString schemaName = "abc"; // act Action action = () => stitchingBuilder.AddSchema( @@ -124,11 +124,11 @@ public void AddSchema_LoadSchemaIsNull_ArgumentNullException() { // arrange StitchingBuilder stitchingBuilder = StitchingBuilder.New(); - NameString schemName = "abc"; + NameString schemaName = "abc"; // act Action action = () => stitchingBuilder.AddSchema( - schemName, (LoadSchemaDocument)null); + schemaName, (LoadSchemaDocument)null); // assert Assert.Equal("loadSchema", diff --git a/src/Stitching/Stitching/Client/RemoteQueryClient.cs b/src/Stitching/Stitching/Client/RemoteQueryClient.cs index 60cacbff5ef..666a6c645f8 100644 --- a/src/Stitching/Stitching/Client/RemoteQueryClient.cs +++ b/src/Stitching/Stitching/Client/RemoteQueryClient.cs @@ -14,8 +14,7 @@ public class RemoteQueryClient { private readonly object _sync = new object(); private readonly RemoteRequestDispatcher _dispatcher; - private List _bufferedRequests = - new List(); + private List _bufferedRequests = new List(); private int _bufferSize; public event RequestBufferedEventHandler BufferedRequest; @@ -29,8 +28,7 @@ public RemoteQueryClient( throw new ArgumentNullException(nameof(services)); } - Executor = executor - ?? throw new ArgumentNullException(nameof(executor)); + Executor = executor ?? throw new ArgumentNullException(nameof(executor)); _dispatcher = new RemoteRequestDispatcher(services, executor); } @@ -38,8 +36,7 @@ public RemoteQueryClient( public int BufferSize => _bufferSize; - public Task ExecuteAsync( - IReadOnlyQueryRequest request) + public Task ExecuteAsync(IReadOnlyQueryRequest request) { var bufferRequest = new BufferedRequest(request); diff --git a/src/Stitching/Stitching/Client/RemoteRequestDispatcher.cs b/src/Stitching/Stitching/Client/RemoteRequestDispatcher.cs index 64b849fa383..c428ccdb2a5 100644 --- a/src/Stitching/Stitching/Client/RemoteRequestDispatcher.cs +++ b/src/Stitching/Stitching/Client/RemoteRequestDispatcher.cs @@ -65,6 +65,7 @@ public Task DispatchAsync( return DispatchRequestsAsync( requests, rewriter.Merge(), + rewriter.OperationName, variableValues, cancellationToken); } @@ -93,6 +94,7 @@ private async Task DispatchSingleRequestsAsync( private async Task DispatchRequestsAsync( IList requests, DocumentNode mergedQuery, + NameNode operationName, IReadOnlyDictionary variableValues, CancellationToken cancellationToken) { @@ -102,6 +104,7 @@ private async Task DispatchRequestsAsync( IReadOnlyQueryRequest mergedRequest = QueryRequestBuilder.New() .SetQuery(mergedQuery) + .SetOperation(operationName.Value) .SetVariableValues(variableValues) .SetServices(_services) .Create(); diff --git a/src/Stitching/Stitching/Delegation/ArgumentScopedVariableResolver.cs b/src/Stitching/Stitching/Delegation/ArgumentScopedVariableResolver.cs index 1f3e6252acb..d4c55bec0f2 100644 --- a/src/Stitching/Stitching/Delegation/ArgumentScopedVariableResolver.cs +++ b/src/Stitching/Stitching/Delegation/ArgumentScopedVariableResolver.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.Linq; using HotChocolate.Execution; using HotChocolate.Language; @@ -16,7 +15,7 @@ internal class ArgumentScopedVariableResolver public VariableValue Resolve( IResolverContext context, ScopedVariableNode variable, - ITypeNode targetType) + IInputType targetType) { if (context == null) { @@ -30,8 +29,8 @@ public VariableValue Resolve( if (!ScopeNames.Arguments.Equals(variable.Scope.Value)) { - throw new ArgumentException(StitchingResources - .ArgumentScopedVariableResolver_CannotHandleVariable, + throw new ArgumentException( + StitchingResources.ArgumentScopedVariableResolver_CannotHandleVariable, nameof(variable)); } @@ -40,23 +39,22 @@ public VariableValue Resolve( if (argument == null) { - throw new QueryException(QueryError.CreateFieldError( - string.Format(CultureInfo.InvariantCulture, - StitchingResources - .ArgumentScopedVariableResolver_InvalidArgumentName, - variable.Name.Value), - context.Path, - context.FieldSelection) - .WithCode(ErrorCodes.ArgumentNotDefined)); + throw new QueryException(ErrorBuilder.New() + .SetMessage( + StitchingResources.ArgumentScopedVariableResolver_InvalidArgumentName, + variable.Name.Value) + .SetCode(ErrorCodes.ArgumentNotDefined) + .SetPath(context.Path) + .AddLocation(context.FieldSelection) + .Build()); } return new VariableValue ( variable.ToVariableName(), argument.Type.ToTypeNode(), - context.Argument(variable.Name.Value), - argument.Type.IsNonNullType() - && argument.DefaultValue.IsNull() + context.Argument(variable.Name.Value), + argument.Type.IsNonNullType() && argument.DefaultValue.IsNull() ? null : argument.DefaultValue ); diff --git a/src/Stitching/Stitching/Delegation/ContextDataScopedVariableResolver.cs b/src/Stitching/Stitching/Delegation/ContextDataScopedVariableResolver.cs index 58f86c25a88..3dcb2551652 100644 --- a/src/Stitching/Stitching/Delegation/ContextDataScopedVariableResolver.cs +++ b/src/Stitching/Stitching/Delegation/ContextDataScopedVariableResolver.cs @@ -1,17 +1,22 @@ using System; -using HotChocolate.Language; +using HotChocolate.Execution; using HotChocolate.Resolvers; using HotChocolate.Stitching.Properties; +using HotChocolate.Types; +using HotChocolate.Utilities; namespace HotChocolate.Stitching.Delegation { internal class ContextDataScopedVariableResolver : IScopedVariableResolver { + private readonly DictionaryToObjectValueConverter _converter = + new DictionaryToObjectValueConverter(); + public VariableValue Resolve( IResolverContext context, ScopedVariableNode variable, - ITypeNode targetType) + IInputType targetType) { if (context == null) { @@ -35,14 +40,13 @@ public VariableValue Resolve( nameof(variable)); } - context.ContextData.TryGetValue(variable.Name.Value, - out object data); + context.ContextData.TryGetValue(variable.Name.Value, out object data); return new VariableValue ( variable.ToVariableName(), - targetType, - data, + targetType.ToTypeNode(), + _converter.Convert(data, targetType, variable.Value), null ); } diff --git a/src/Stitching/Stitching/Delegation/FieldScopedVariableResolver.cs b/src/Stitching/Stitching/Delegation/FieldScopedVariableResolver.cs index 2fb805b1943..2979834687e 100644 --- a/src/Stitching/Stitching/Delegation/FieldScopedVariableResolver.cs +++ b/src/Stitching/Stitching/Delegation/FieldScopedVariableResolver.cs @@ -12,10 +12,13 @@ namespace HotChocolate.Stitching.Delegation internal class FieldScopedVariableResolver : IScopedVariableResolver { + private readonly DictionaryToObjectValueConverter _converter = + new DictionaryToObjectValueConverter(); + public VariableValue Resolve( IResolverContext context, ScopedVariableNode variable, - ITypeNode targetType) + IInputType targetType) { if (context == null) { @@ -44,20 +47,20 @@ public VariableValue Resolve( return new VariableValue ( variable.ToVariableName(), - field.Type.ToTypeNode(), - obj[field.Name], + targetType.ToTypeNode(), + _converter.Convert(obj[field.Name], targetType, variable.Value), null ); } - throw new QueryException(QueryError.CreateFieldError( - string.Format(CultureInfo.InvariantCulture, - StitchingResources - .FieldScopedVariableResolver_InvalidFieldName, - variable.Name.Value), - context.Path, - context.FieldSelection) - .WithCode(ErrorCodes.FieldNotDefined)); + throw new QueryException(ErrorBuilder.New() + .SetMessage( + StitchingResources.FieldScopedVariableResolver_InvalidFieldName, + variable.Name.Value) + .SetCode(ErrorCodes.FieldNotDefined) + .SetPath(context.Path) + .AddLocation(context.FieldSelection) + .Build()); } } } diff --git a/src/Stitching/Stitching/Delegation/IScopedVariableResolver.cs b/src/Stitching/Stitching/Delegation/IScopedVariableResolver.cs index 1582e1e9856..ae02e45da54 100644 --- a/src/Stitching/Stitching/Delegation/IScopedVariableResolver.cs +++ b/src/Stitching/Stitching/Delegation/IScopedVariableResolver.cs @@ -1,6 +1,5 @@ -using System.Collections.Generic; -using HotChocolate.Language; using HotChocolate.Resolvers; +using HotChocolate.Types; namespace HotChocolate.Stitching.Delegation { @@ -9,6 +8,6 @@ internal interface IScopedVariableResolver VariableValue Resolve( IResolverContext context, ScopedVariableNode variable, - ITypeNode targetType); + IInputType targetType); } } diff --git a/src/Stitching/Stitching/Delegation/RootScopedVariableResolver.cs b/src/Stitching/Stitching/Delegation/RootScopedVariableResolver.cs index 7603043aa0a..5b7e8cc3648 100644 --- a/src/Stitching/Stitching/Delegation/RootScopedVariableResolver.cs +++ b/src/Stitching/Stitching/Delegation/RootScopedVariableResolver.cs @@ -2,34 +2,28 @@ using System.Collections.Generic; using System.Globalization; using HotChocolate.Execution; -using HotChocolate.Language; using HotChocolate.Resolvers; using HotChocolate.Stitching.Properties; +using HotChocolate.Types; namespace HotChocolate.Stitching.Delegation { internal class RootScopedVariableResolver : IScopedVariableResolver { - public RootScopedVariableResolver() - { - Resolvers[ScopeNames.Arguments] = - new ArgumentScopedVariableResolver(); - Resolvers[ScopeNames.Fields] = - new FieldScopedVariableResolver(); - Resolvers[ScopeNames.ContextData] = - new ContextDataScopedVariableResolver(); - Resolvers[ScopeNames.ScopedContextData] = - new ScopedContextDataScopedVariableResolver(); - } - - private Dictionary Resolvers { get; } = - new Dictionary(); + private readonly Dictionary _resolvers = + new Dictionary + { + { ScopeNames.Arguments, new ArgumentScopedVariableResolver() }, + { ScopeNames.Fields, new FieldScopedVariableResolver() }, + { ScopeNames.ContextData, new ContextDataScopedVariableResolver() }, + { ScopeNames.ScopedContextData, new ScopedContextDataScopedVariableResolver() } + }; public VariableValue Resolve( IResolverContext context, ScopedVariableNode variable, - ITypeNode targetType) + IInputType targetType) { if (context == null) { @@ -41,20 +35,20 @@ public VariableValue Resolve( throw new ArgumentNullException(nameof(variable)); } - if (Resolvers.TryGetValue(variable.Scope.Value, + if (_resolvers.TryGetValue(variable.Scope.Value, out IScopedVariableResolver resolver)) { return resolver.Resolve(context, variable, targetType); } - throw new QueryException(QueryError.CreateFieldError( - string.Format(CultureInfo.InvariantCulture, - StitchingResources - .RootScopedVariableResolver_ScopeNotSupported, - variable.Scope.Value), - context.Path, - context.FieldSelection) - .WithCode(ErrorCodes.ScopeNotDefined)); + throw new QueryException(ErrorBuilder.New() + .SetMessage( + StitchingResources.RootScopedVariableResolver_ScopeNotSupported, + variable.Scope.Value) + .SetCode(ErrorCodes.ScopeNotDefined) + .SetPath(context.Path) + .AddLocation(context.FieldSelection) + .Build()); } } } diff --git a/src/Stitching/Stitching/Delegation/ScopedContextDataScopedVariableResolver.cs b/src/Stitching/Stitching/Delegation/ScopedContextDataScopedVariableResolver.cs index e2f138b7f30..fdc065ec343 100644 --- a/src/Stitching/Stitching/Delegation/ScopedContextDataScopedVariableResolver.cs +++ b/src/Stitching/Stitching/Delegation/ScopedContextDataScopedVariableResolver.cs @@ -1,17 +1,21 @@ using System; -using HotChocolate.Language; +using HotChocolate.Execution; using HotChocolate.Resolvers; using HotChocolate.Stitching.Properties; +using HotChocolate.Types; namespace HotChocolate.Stitching.Delegation { internal class ScopedContextDataScopedVariableResolver : IScopedVariableResolver { + private readonly DictionaryToObjectValueConverter _converter = + new DictionaryToObjectValueConverter(); + public VariableValue Resolve( IResolverContext context, ScopedVariableNode variable, - ITypeNode targetType) + IInputType targetType) { if (context == null) { @@ -35,14 +39,13 @@ public VariableValue Resolve( nameof(variable)); } - context.ScopedContextData.TryGetValue(variable.Name.Value, - out object data); + context.ScopedContextData.TryGetValue(variable.Name.Value, out object data); return new VariableValue ( variable.ToVariableName(), - targetType, - data, + targetType.ToTypeNode(), + _converter.Convert(data, targetType, variable.Value), null ); } diff --git a/src/Stitching/Stitching/Delegation/VariableValue.cs b/src/Stitching/Stitching/Delegation/VariableValue.cs index bcfe9fa3828..01232db70b2 100644 --- a/src/Stitching/Stitching/Delegation/VariableValue.cs +++ b/src/Stitching/Stitching/Delegation/VariableValue.cs @@ -3,12 +3,12 @@ namespace HotChocolate.Stitching.Delegation { - internal class VariableValue + internal readonly struct VariableValue { internal VariableValue( string name, ITypeNode type, - object value, + IValueNode value, IValueNode defaultValue) { Name = name ?? throw new ArgumentNullException(nameof(name)); @@ -21,8 +21,11 @@ internal VariableValue( public ITypeNode Type { get; } - public object Value { get; } + public IValueNode Value { get; } public IValueNode DefaultValue { get; } + + public VariableValue WithValue(IValueNode value) => + new VariableValue(Name, Type, value, DefaultValue); } } diff --git a/src/Stitching/Stitching/ErrorCodes.cs b/src/Stitching/Stitching/ErrorCodes.cs index 73af61e5a85..6d3e2a6bb78 100644 --- a/src/Stitching/Stitching/ErrorCodes.cs +++ b/src/Stitching/Stitching/ErrorCodes.cs @@ -8,5 +8,6 @@ public static class ErrorCodes public const string ScopeNotDefined = "STITCHING_SCOPE_NOT_DEFINED"; public const string TypeNotDefined = "STITCHING_TYPE_NOT_DEFINED"; public const string HttpRequestException = "STITCHING_HTTP_REQUEST_EXCEPTION"; + public const string ArgumentNotFound = "STITCHING_DEL_ARGUMENT_NOT_FOUND"; } } diff --git a/src/Stitching/Stitching/Extensions/ContextDataExtensions.cs b/src/Stitching/Stitching/Extensions/ContextDataExtensions.cs index 55cb37e3331..266467632ea 100644 --- a/src/Stitching/Stitching/Extensions/ContextDataExtensions.cs +++ b/src/Stitching/Stitching/Extensions/ContextDataExtensions.cs @@ -1,40 +1,32 @@ -using System; using System.Collections.Generic; using HotChocolate.Execution; +using HotChocolate.Language; using HotChocolate.Resolvers; +#nullable enable + namespace HotChocolate.Stitching { internal static class ContextDataExtensions { - private const string _variables = "__hc_variables"; + private const string _variables = "HotChocolate.Stitching.Variables"; + private static readonly Dictionary _empty = + new Dictionary(); - public static IReadOnlyDictionary GetVariables( + public static IReadOnlyDictionary GetVariables( this IMiddlewareContext context) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - if (context.ContextData.TryGetValue(_variables, out object obj) - && obj is IReadOnlyDictionary variables) + && obj is IReadOnlyDictionary variables) { return variables; } - return new Dictionary(); + return _empty; } public static void SetVariables( this IQueryContext context, - IReadOnlyDictionary variables) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - + IReadOnlyDictionary variables) => context.ContextData[_variables] = variables; - } } } diff --git a/src/Stitching/Stitching/Extensions/StitchingQueryExecutionBuilderExtensions.cs b/src/Stitching/Stitching/Extensions/StitchingQueryExecutionBuilderExtensions.cs index b9135d77d44..a6688ef44e4 100644 --- a/src/Stitching/Stitching/Extensions/StitchingQueryExecutionBuilderExtensions.cs +++ b/src/Stitching/Stitching/Extensions/StitchingQueryExecutionBuilderExtensions.cs @@ -72,8 +72,15 @@ public static IQueryExecutionBuilder UseStitchingPipeline( } return builder + .AddDefaultServices(options) + .UseDefaultDiagnostics(options) + .UseQueryParser() + .UseNoCachedQueryError() + .UseValidation() + .UseOperationResolver() + .UseMaxComplexity() .UsePropagateVariables() - .UseDefaultPipeline(options); + .UseOperationExecutor(); } public static IQueryExecutionBuilder UseRemoteQueryExecutor( diff --git a/src/Stitching/Stitching/IHttpQueryRequestInterceptor.cs b/src/Stitching/Stitching/IHttpQueryRequestInterceptor.cs index 574684ca9c1..173e1967cce 100644 --- a/src/Stitching/Stitching/IHttpQueryRequestInterceptor.cs +++ b/src/Stitching/Stitching/IHttpQueryRequestInterceptor.cs @@ -7,7 +7,7 @@ namespace HotChocolate.Stitching public interface IHttpQueryRequestInterceptor { Task OnResponseReceivedAsync( - IHttpQueryRequest request, + IReadOnlyQueryRequest request, HttpResponseMessage response, IQueryResult result); } diff --git a/src/Stitching/Stitching/IRemoteQueryClient.cs b/src/Stitching/Stitching/IRemoteQueryClient.cs index 9335428b650..dceba4f2123 100644 --- a/src/Stitching/Stitching/IRemoteQueryClient.cs +++ b/src/Stitching/Stitching/IRemoteQueryClient.cs @@ -16,8 +16,7 @@ public interface IRemoteQueryClient int BufferSize { get; } - Task ExecuteAsync( - IReadOnlyQueryRequest request); + Task ExecuteAsync(IReadOnlyQueryRequest request); Task DispatchAsync(CancellationToken cancellationToken); } diff --git a/src/Stitching/Stitching/Middleware/CopyVariablesToResolverContextMiddleware.cs b/src/Stitching/Stitching/Middleware/CopyVariablesToResolverContextMiddleware.cs index 259b495b6bd..a185d415653 100644 --- a/src/Stitching/Stitching/Middleware/CopyVariablesToResolverContextMiddleware.cs +++ b/src/Stitching/Stitching/Middleware/CopyVariablesToResolverContextMiddleware.cs @@ -1,6 +1,9 @@ +using System.Collections.Generic; using System; using System.Threading.Tasks; using HotChocolate.Execution; +using HotChocolate.Language; +using HotChocolate.Utilities; namespace HotChocolate.Stitching { @@ -15,7 +18,16 @@ public CopyVariablesToResolverContextMiddleware(QueryDelegate next) public Task InvokeAsync(IQueryContext context) { - context.SetVariables(context.Request.VariableValues); + IVariableValueCollection variables = context.Operation.Variables; + var dict = new Dictionary(); + + foreach (string key in context.Request.VariableValues.Keys) + { + dict.Add(key, variables.GetVariable(key)); + } + + context.SetVariables(dict); + return _next.Invoke(context); } } diff --git a/src/Stitching/Stitching/Middleware/DelegateToRemoteSchemaMiddleware.cs b/src/Stitching/Stitching/Middleware/DelegateToRemoteSchemaMiddleware.cs index 74373d0b8f2..1f239ce65cc 100644 --- a/src/Stitching/Stitching/Middleware/DelegateToRemoteSchemaMiddleware.cs +++ b/src/Stitching/Stitching/Middleware/DelegateToRemoteSchemaMiddleware.cs @@ -50,8 +50,7 @@ delegateDirective.Path is null UpdateContextData(context, result, delegateDirective); - context.Result = new SerializedData( - ExtractData(result.Data, path.Count())); + context.Result = new SerializedData(ExtractData(result.Data, path.Count())); ReportErrors(delegateDirective.Schema, context, result.Errors); } @@ -68,17 +67,15 @@ private void UpdateContextData( ImmutableDictionary.Builder builder = ImmutableDictionary.CreateBuilder(); builder.AddRange(context.ScopedContextData); - builder[WellKnownProperties.SchemaName] = - delegateDirective.Schema; + builder[WellKnownProperties.SchemaName] = delegateDirective.Schema; builder.AddRange(result.ContextData); context.ScopedContextData = builder.ToImmutableDictionary(); } else { - context.ScopedContextData = - context.ScopedContextData.SetItem( - WellKnownProperties.SchemaName, - delegateDirective.Schema); + context.ModifyScopedContext(c => c.SetItem( + WellKnownProperties.SchemaName, + delegateDirective.Schema)); } } @@ -100,13 +97,15 @@ private static IReadOnlyQueryRequest CreateQuery( schemaName, context.Document, context.Operation, context.FieldSelection, context.ObjectType); - IEnumerable scopedVariables = + IEnumerable scopedVariables = ResolveScopedVariables( - context, schemaName, operationType, path); + context, schemaName, operationType, + path, fieldRewriter); - IReadOnlyCollection variableValues = + IReadOnlyCollection variableValues = CreateVariableValues( - context, scopedVariables, extractedField); + context, schemaName, scopedVariables, + extractedField, fieldRewriter); DocumentNode query = RemoteQueryBuilder.New() .SetOperation(context.Operation.Name, operationType) @@ -118,13 +117,10 @@ private static IReadOnlyQueryRequest CreateQuery( var requestBuilder = QueryRequestBuilder.New(); - AddVariables(context, schemaName, - requestBuilder, query, variableValues); + AddVariables(requestBuilder, query, variableValues); requestBuilder.SetQuery(query); - requestBuilder.AddProperty( - WellKnownProperties.IsAutoGenerated, - true); + requestBuilder.AddProperty(WellKnownProperties.IsAutoGenerated, true); return requestBuilder.Create(); } @@ -139,8 +135,8 @@ private static async Task ExecuteQueryAsync( .GetRemoteQueryClient(schemaName); IExecutionResult result = await remoteQueryClient - .ExecuteAsync(request) - .ConfigureAwait(false); + .ExecuteAsync(request) + .ConfigureAwait(false); if (result is IReadOnlyQueryResult queryResult) { @@ -195,7 +191,8 @@ private static void ReportErrors( builder.SetPath(path) .ClearLocations() .AddLocation(context.FieldSelection); - } else if (IsHttpError(error)) + } + else if (IsHttpError(error)) { builder.SetPath(context.Path) .ClearLocations() @@ -231,25 +228,28 @@ private static Path RewriteErrorPath(IError error, Path path) return current; } - private static bool IsHttpError(IError error) => error.Code == ErrorCodes.HttpRequestException; + private static bool IsHttpError(IError error) => + error.Code == ErrorCodes.HttpRequestException; - private static IReadOnlyCollection CreateVariableValues( + private static IReadOnlyCollection CreateVariableValues( IMiddlewareContext context, - IEnumerable scopedVaribles, - ExtractedField extractedField) + NameString schemaName, + IEnumerable scopedVariables, + ExtractedField extractedField, + ExtractFieldQuerySyntaxRewriter rewriter) { - var values = new Dictionary(); + var values = new Dictionary(); - foreach (VariableValue value in scopedVaribles) + foreach (Delegation.VariableValue value in scopedVariables) { values[value.Name] = value; } - IReadOnlyDictionary requestVariables = - context.GetVariables(); + IReadOnlyDictionary requestVariables = context.GetVariables(); - foreach (VariableValue value in ResolveUsedRequestVariables( - extractedField, requestVariables)) + foreach (Delegation.VariableValue value in ResolveUsedRequestVariables( + context.Schema, schemaName, extractedField, + requestVariables, rewriter)) { values[value.Name] = value; } @@ -257,44 +257,39 @@ private static IReadOnlyCollection CreateVariableValues( return values.Values; } - private static IReadOnlyList ResolveScopedVariables( + private static IReadOnlyList ResolveScopedVariables( IResolverContext context, NameString schemaName, OperationType operationType, - IEnumerable components) + IEnumerable components, + ExtractFieldQuerySyntaxRewriter rewriter) { - IStitchingContext stitchingContext = - context.Service(); - - ISchema remoteSchema = - stitchingContext.GetRemoteSchema(schemaName); - - IComplexOutputType type = - remoteSchema.GetOperationType(operationType); + var variables = new List(); - var variables = new List(); + IStitchingContext stitchingContext = context.Service(); + ISchema remoteSchema = stitchingContext.GetRemoteSchema(schemaName); + IComplexOutputType type = remoteSchema.GetOperationType(operationType); SelectionPathComponent[] comps = components.Reverse().ToArray(); for (int i = 0; i < comps.Length; i++) { SelectionPathComponent component = comps[i]; - if (!type.Fields.TryGetField(component.Name.Value, - out IOutputField field)) + if (!type.Fields.TryGetField(component.Name.Value, out IOutputField field)) { throw new QueryException(new Error { Message = string.Format( CultureInfo.InvariantCulture, - StitchingResources - .DelegationMiddleware_PathElementInvalid, + StitchingResources.DelegationMiddleware_PathElementInvalid, component.Name.Value, type.Name) }); } ResolveScopedVariableArguments( - context, component, field, variables); + context, schemaName, component, + field, variables, rewriter); if (i + 1 < comps.Length) { @@ -315,92 +310,61 @@ private static IReadOnlyList ResolveScopedVariables( private static void ResolveScopedVariableArguments( IResolverContext context, + NameString schemaName, SelectionPathComponent component, IOutputField field, - ICollection variables) + ICollection variables, + ExtractFieldQuerySyntaxRewriter rewriter) { - ITypeConversion typeConversion = - context.Service() - .GetTypeConversion(); - foreach (ArgumentNode argument in component.Arguments) { - if (!field.Arguments.TryGetField(argument.Name.Value, - out IInputField arg)) + if (!field.Arguments.TryGetField(argument.Name.Value, out IInputField arg)) { - throw new QueryException(new Error - { - Message = string.Format( - CultureInfo.InvariantCulture, - StitchingResources - .DelegationMiddleware_ArgumentNotFound, - argument.Name.Value) - }); + throw new QueryException( + ErrorBuilder.New() + .SetMessage( + StitchingResources.DelegationMiddleware_ArgumentNotFound, + argument.Name.Value) + .SetExtension("argument", argument.Name.Value) + .SetCode(ErrorCodes.ArgumentNotFound) + .Build()); } if (argument.Value is ScopedVariableNode sv) { - VariableValue variable = - _resolvers.Resolve(context, sv, arg.Type.ToTypeNode()); - - object value = variable.Value; - - if (!arg.Type.IsInstanceOfType(value)) - { - value = ConvertValue(typeConversion, arg.Type, value); - } - - variable = new VariableValue - ( - variable.Name, - variable.Type, - arg.Type.Serialize(value), - variable.DefaultValue - ); - - variables.Add(variable); + Delegation.VariableValue variable = + _resolvers.Resolve(context, sv, arg.Type); + IValueNode value = rewriter.RewriteValueNode( + schemaName, arg.Type, variable.Value); + variables.Add(variable.WithValue(value)); } } } - private static object ConvertValue( - ITypeConversion converter, - IInputType type, - object value) + private static IEnumerable ResolveUsedRequestVariables( + ISchema schema, + NameString schemaName, + ExtractedField extractedField, + IReadOnlyDictionary requestVariables, + ExtractFieldQuerySyntaxRewriter rewriter) { - Type sourceType = typeof(object); - - if (type.IsListType() && value is IEnumerable e) + foreach (VariableDefinitionNode variable in extractedField.Variables) { - if (e.Any()) - { - Type elementType = e.FirstOrDefault()?.GetType(); - if (elementType != null) - { - sourceType = - typeof(IEnumerable<>).MakeGenericType(elementType); - } - } - else + string name = variable.Variable.Name.Value; + INamedInputType namedType = schema.GetType( + variable.Type.NamedType().Name.Value); + + if (!requestVariables.TryGetValue(name, out IValueNode value)) { - return Activator.CreateInstance(type.ClrType); + value = NullValueNode.Default; } - } - return converter.Convert(sourceType, type.ClrType, value); - } + value = rewriter.RewriteValueNode( + schemaName, + (IInputType)variable.Type.ToType(namedType), + value); - private static IEnumerable ResolveUsedRequestVariables( - ExtractedField extractedField, - IReadOnlyDictionary requestVariables) - { - foreach (VariableDefinitionNode variable in - extractedField.Variables) - { - string name = variable.Variable.Name.Value; - requestVariables.TryGetValue(name, out object value); - - yield return new VariableValue + yield return new Delegation.VariableValue ( name, variable.Type, @@ -411,34 +375,22 @@ private static IEnumerable ResolveUsedRequestVariables( } private static void AddVariables( - IResolverContext context, - NameString schemaName, IQueryRequestBuilder builder, DocumentNode query, - IEnumerable variableValues) + IEnumerable variableValues) { OperationDefinitionNode operation = query.Definitions.OfType().First(); + var usedVariables = new HashSet( operation.VariableDefinitions.Select(t => t.Variable.Name.Value)); - foreach (VariableValue variableValue in variableValues) + foreach (Delegation.VariableValue variableValue in variableValues) { if (usedVariables.Contains(variableValue.Name)) { - object value = variableValue.Value; - - if (context.Schema.TryGetType( - variableValue.Type.NamedType().Name.Value, - out InputObjectType inputType)) - { - IInputType wrapped = WrapType(inputType, variableValue.Type); - value = ObjectVariableRewriter.RewriteVariable( - schemaName, wrapped, value); - } - - builder.AddVariableValue(variableValue.Name, value); + builder.AddVariableValue(variableValue.Name, variableValue.Value); } } } @@ -462,11 +414,11 @@ private static IInputType WrapType( } private static IReadOnlyList CreateVariableDefs( - IReadOnlyCollection variableValues) + IReadOnlyCollection variableValues) { var definitions = new List(); - foreach (VariableValue variableValue in variableValues) + foreach (Delegation.VariableValue variableValue in variableValues) { definitions.Add(new VariableDefinitionNode( null, diff --git a/src/Stitching/Stitching/Stitching.csproj b/src/Stitching/Stitching/Stitching.csproj index 787e1a15291..ee81663252b 100644 --- a/src/Stitching/Stitching/Stitching.csproj +++ b/src/Stitching/Stitching/Stitching.csproj @@ -26,11 +26,13 @@ + + diff --git a/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.Context.cs b/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.Context.cs index d85b72b5791..73f051b0b41 100644 --- a/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.Context.cs +++ b/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.Context.cs @@ -1,10 +1,7 @@ -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using HotChocolate.Language; using HotChocolate.Types; -using HotChocolate.Utilities; namespace HotChocolate.Stitching.Utilities { diff --git a/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.cs b/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.cs index 74b96e455e5..2e9101e7163 100644 --- a/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.cs +++ b/src/Stitching/Stitching/Utilities/ExtractFieldQuerySyntaxRewriter.cs @@ -66,6 +66,18 @@ public ExtractedField ExtractField( context.Fragments.Values.ToList()); } + public IValueNode RewriteValueNode( + NameString sourceSchema, + IInputType inputType, + IValueNode value) + { + sourceSchema.EnsureNotEmpty(nameof(sourceSchema)); + + var context = new Context(sourceSchema, null, null, null); + context.InputType = inputType; + return RewriteValue(value, context); + } + protected override FieldNode RewriteField( FieldNode node, Context context) @@ -73,22 +85,16 @@ protected override FieldNode RewriteField( FieldNode current = node; if (context.TypeContext is IComplexOutputType type - && type.Fields.TryGetField(current.Name.Value, - out IOutputField field)) + && type.Fields.TryGetField(current.Name.Value, out IOutputField field)) { Context cloned = context.Clone(); cloned.OutputField = field; - current = RewriteFieldName( - current, field, context); - + current = RewriteFieldName(current, field, context); current = Rewrite(current, current.Arguments, cloned, (p, c) => RewriteMany(p, c, RewriteArgument), current.WithArguments); - - current = RewriteFieldSelectionSet( - current, field, context); - + current = RewriteFieldSelectionSet(current, field, context); current = OnRewriteField(current, cloned); } @@ -184,7 +190,7 @@ protected override SelectionSetNode RewriteSelectionSet( { selections.Add(CreateField(WellKnownFieldNames.TypeName)); } - + current = current.WithSelections(selections); current = base.RewriteSelectionSet(current, context); current = OnRewriteSelectionSet(current, context); @@ -280,11 +286,9 @@ private static void RemoveDelegationFields( { if (context.TypeContext is IComplexOutputType type) { - foreach (FieldNode selection in node.Selections - .OfType()) + foreach (FieldNode selection in node.Selections.OfType()) { - if (type.Fields.TryGetField(selection.Name.Value, - out IOutputField field) + if (type.Fields.TryGetField(selection.Name.Value, out IOutputField field) && IsDelegationField(field.Directives)) { selections.Remove(selection); @@ -296,7 +300,7 @@ private static void RemoveDelegationFields( private static bool IsDelegationField(IDirectiveCollection directives) { return directives.Contains(DirectiveNames.Delegate) - || directives.Contains(DirectiveNames.Computed); + || directives.Contains(DirectiveNames.Computed); } private static void AddDependencies( @@ -304,13 +308,11 @@ private static void AddDependencies( List selections, IEnumerable dependencies) { - foreach (var typeGroup in dependencies.GroupBy(t => t.TypeName)) { var fields = new List(); - foreach (NameString fieldName in typeGroup - .Select(t => t.FieldName)) + foreach (NameString fieldName in typeGroup.Select(t => t.FieldName)) { fields.Add(CreateField(fieldName)); } @@ -366,8 +368,7 @@ protected override FragmentSpreadNode RewriteFragmentSpread( Context context) { string name = node.Name.Value; - if (!context.Fragments.TryGetValue(name, - out FragmentDefinitionNode fragment)) + if (!context.Fragments.TryGetValue(name, out FragmentDefinitionNode fragment)) { fragment = context.Document.Definitions .OfType() @@ -391,17 +392,13 @@ protected override FragmentDefinitionNode RewriteFragmentDefinition( return node; } - if (_schema.TryGetType( - current.TypeCondition.Name.Value, - out IComplexOutputType type)) + if (_schema.TryGetType(current.TypeCondition.Name.Value, out IComplexOutputType type)) { currentContext = currentContext.Clone(); currentContext.TypeContext = type; - currentContext.FragmentPath = - currentContext.FragmentPath.Add(current.Name.Value); + currentContext.FragmentPath = currentContext.FragmentPath.Add(current.Name.Value); - if (type.TryGetSourceDirective(context.Schema, - out SourceDirective sourceDirective)) + if (type.TryGetSourceDirective(context.Schema, out SourceDirective sourceDirective)) { current = current.WithTypeCondition( current.TypeCondition.WithName( @@ -419,15 +416,12 @@ protected override InlineFragmentNode RewriteInlineFragment( Context currentContext = context; InlineFragmentNode current = node; - if (_schema.TryGetType( - current.TypeCondition.Name.Value, - out IComplexOutputType type)) + if (_schema.TryGetType(current.TypeCondition.Name.Value, out IComplexOutputType type)) { currentContext = currentContext.Clone(); currentContext.TypeContext = type; - if (type.TryGetSourceDirective(context.Schema, - out SourceDirective sourceDirective)) + if (type.TryGetSourceDirective(context.Schema, out SourceDirective sourceDirective)) { current = current.WithTypeCondition( current.TypeCondition.WithName( diff --git a/src/Stitching/Stitching/Utilities/ExtractedField.cs b/src/Stitching/Stitching/Utilities/ExtractedField.cs index 9324d7f6f7a..dff3e50f5d5 100644 --- a/src/Stitching/Stitching/Utilities/ExtractedField.cs +++ b/src/Stitching/Stitching/Utilities/ExtractedField.cs @@ -11,12 +11,9 @@ public ExtractedField( IReadOnlyList variables, IReadOnlyList fragments) { - Field = field - ?? throw new ArgumentNullException(nameof(field)); - Variables = variables - ?? throw new ArgumentNullException(nameof(variables)); - Fragments = fragments - ?? throw new ArgumentNullException(nameof(fragments)); + Field = field ?? throw new ArgumentNullException(nameof(field)); + Variables = variables ?? throw new ArgumentNullException(nameof(variables)); + Fragments = fragments ?? throw new ArgumentNullException(nameof(fragments)); } public FieldNode Field { get; } diff --git a/src/Stitching/Stitching/Utilities/HttpQueryClient.cs b/src/Stitching/Stitching/Utilities/HttpQueryClient.cs index d8cf0f6caa3..887175feb38 100644 --- a/src/Stitching/Stitching/Utilities/HttpQueryClient.cs +++ b/src/Stitching/Stitching/Utilities/HttpQueryClient.cs @@ -1,58 +1,65 @@ -using System.Threading; using System; using System.Collections.Generic; using System.IO; using System.Net.Http; -using System.Text; +using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using HotChocolate.Execution; using HotChocolate.Language; -using HotChocolate.Server; using HotChocolate.Utilities; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; + +#nullable enable namespace HotChocolate.Stitching.Utilities { internal class HttpQueryClient { - private const string _json = "application/json"; + private static readonly KeyValuePair _contentTypeJson = + new KeyValuePair("Content-Type", "application/json"); - private readonly JsonSerializerSettings _jsonSettings = - new JsonSerializerSettings + private static readonly JsonSerializerOptions _options = + new JsonSerializerOptions { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - DateParseHandling = DateParseHandling.None + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + IgnoreNullValues = true, + IgnoreReadOnlyProperties = false }; public Task FetchAsync( IReadOnlyQueryRequest request, HttpClient httpClient, - IEnumerable interceptors, - CancellationToken cancellationToken) => - FetchAsync( - CreateRemoteRequest(request), + IEnumerable? interceptors = default, + CancellationToken cancellationToken = default) + { + using var writer = new JsonRequestWriter(); + WriteJsonRequest(writer, request); + var content = new ByteArrayContent(writer.GetInternalBuffer(), 0, writer.Length); + content.Headers.Add(_contentTypeJson.Key, _contentTypeJson.Value); + + return FetchAsync( + request, + content, httpClient, interceptors, cancellationToken); + } - public async Task FetchAsync( - HttpQueryRequest request, + private async Task FetchAsync( + IReadOnlyQueryRequest request, + HttpContent requestContent, HttpClient httpClient, - IEnumerable interceptors, + IEnumerable? interceptors, CancellationToken cancellationToken) { HttpResponseMessage message = - await FetchInternalAsync(request, httpClient) - .ConfigureAwait(false); + await FetchInternalAsync(requestContent, httpClient).ConfigureAwait(false); - using (Stream stream = await message.Content.ReadAsStreamAsync() - .ConfigureAwait(false)) + using (Stream stream = await message.Content.ReadAsStreamAsync().ConfigureAwait(false)) { object response = await BufferHelper.ReadAsync( stream, - (buffer, bytesBuffered) => - ParseJson(buffer, bytesBuffered), + (buffer, bytesBuffered) => ParseJson(buffer, bytesBuffered), cancellationToken) .ConfigureAwait(false); @@ -61,14 +68,12 @@ response is IReadOnlyDictionary d ? HttpResponseDeserializer.Deserialize(d) : QueryResult.CreateError( ErrorBuilder.New() - .SetMessage( - "Could not deserialize query response.") + .SetMessage("Could not deserialize query response.") .Build()); - if (interceptors != null) + if (interceptors is { }) { - foreach (IHttpQueryRequestInterceptor interceptor in - interceptors) + foreach (IHttpQueryRequestInterceptor interceptor in interceptors) { await interceptor.OnResponseReceivedAsync( request, message, queryResult) @@ -82,8 +87,8 @@ await interceptor.OnResponseReceivedAsync( private static object ParseJson(byte[] buffer, int bytesBuffered) { - return Utf8GraphQLRequestParser.ParseJson( - new ReadOnlySpan(buffer, 0, bytesBuffered)); + var json = new ReadOnlySpan(buffer, 0, bytesBuffered); + return Utf8GraphQLRequestParser.ParseJson(json); } public Task<(string, HttpResponseMessage)> FetchStringAsync( @@ -103,60 +108,125 @@ private static object ParseJson(byte[] buffer, int bytesBuffered) return FetchStringInternalAsync(request, httpClient); } - private async Task<(string, HttpResponseMessage)> - FetchStringInternalAsync( - HttpQueryRequest request, - HttpClient httpClient) + private async Task<(string, HttpResponseMessage)> FetchStringInternalAsync( + HttpQueryRequest request, + HttpClient httpClient) { - var content = new StringContent( - SerializeRemoteRequest(request), - Encoding.UTF8, - _json); + byte[] json = JsonSerializer.SerializeToUtf8Bytes(request, _options); + var content = new ByteArrayContent(json, 0, json.Length); + content.Headers.Add(_contentTypeJson.Key, _contentTypeJson.Value); HttpResponseMessage response = await httpClient.PostAsync(default(Uri), content) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); - string json = await response.Content.ReadAsStringAsync() + string responseContent = await response.Content.ReadAsStringAsync() .ConfigureAwait(false); - return (json, response); + return (responseContent, response); } - private async Task FetchInternalAsync( - HttpQueryRequest request, + private static async Task FetchInternalAsync( + HttpContent requestContent, HttpClient httpClient) { - var content = new StringContent( - SerializeRemoteRequest(request), - Encoding.UTF8, - _json); - HttpResponseMessage response = - await httpClient.PostAsync(default(Uri), content) + await httpClient.PostAsync(default(Uri), requestContent) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); - return response; } - private HttpQueryRequest CreateRemoteRequest( + private void WriteJsonRequest( + JsonRequestWriter writer, IReadOnlyQueryRequest request) { - return new HttpQueryRequest + writer.WriteStartObject(); + writer.WriteQuery(request.Query); + writer.WriteOperationName(request.OperationName); + WriteJsonRequestVariables(writer, request.VariableValues); + writer.WriteEndObject(); + } + + private static void WriteJsonRequestVariables( + JsonRequestWriter writer, + IReadOnlyDictionary variables) + { + if (variables is { } && variables.Count > 0) { - Query = request.Query.ToString(), - OperationName = request.OperationName, - Variables = request.VariableValues - }; + writer.WritePropertyName("variables"); + + writer.WriteStartObject(); + + foreach (KeyValuePair variable in variables) + { + writer.WritePropertyName(variable.Key); + WriteValue(writer, variable.Value); + } + + writer.WriteEndObject(); + } } - private string SerializeRemoteRequest( - HttpQueryRequest remoteRequest) + private static void WriteValue(JsonRequestWriter writer, object value) { - return JsonConvert.SerializeObject( - remoteRequest, _jsonSettings); + if (value is null || value is NullValueNode) + { + writer.WriteNullValue(); + } + else + { + switch (value) + { + case ObjectValueNode obj: + writer.WriteStartObject(); + + foreach (ObjectFieldNode field in obj.Fields) + { + writer.WritePropertyName(field.Name.Value); + WriteValue(writer, field.Value); + } + + writer.WriteEndObject(); + break; + + case ListValueNode list: + writer.WriteStartArray(); + + foreach (IValueNode item in list.Items) + { + WriteValue(writer, item); + } + + writer.WriteEndArray(); + break; + + case StringValueNode s: + writer.WriteStringValue(s.Value); + break; + + case EnumValueNode e: + writer.WriteStringValue(e.Value); + break; + + case IntValueNode i: + writer.WriteNumberValue(i.Value); + break; + + case FloatValueNode f: + writer.WriteNumberValue(f.Value); + break; + + case BooleanValueNode b: + writer.WriteBooleanValue(b.Value); + break; + + default: + throw new NotSupportedException( + "Unknown variable value kind."); + } + } } } } diff --git a/src/Stitching/Stitching/Utilities/JsonRequestWriter.cs b/src/Stitching/Stitching/Utilities/JsonRequestWriter.cs new file mode 100644 index 00000000000..b4552b2896e --- /dev/null +++ b/src/Stitching/Stitching/Utilities/JsonRequestWriter.cs @@ -0,0 +1,172 @@ +using System; +using System.Buffers; +using System.Text.Json; +using HotChocolate.Execution; + +namespace HotChocolate.Stitching.Utilities +{ + internal sealed class JsonRequestWriter + : IBufferWriter + , IDisposable + { + private const int _initialBufferSize = 512; + private static readonly JsonWriterOptions _options = + new JsonWriterOptions { SkipValidation = true }; + private readonly Utf8JsonWriter _writer; + private byte[] _buffer; + private int _capacity; + private int _start; + private bool _disposed; + + public JsonRequestWriter() + { + _buffer = ArrayPool.Shared.Rent(_initialBufferSize); + _capacity = _buffer.Length; + _writer = new Utf8JsonWriter(this, _options); + } + + public int Length => _start; + + public ReadOnlyMemory Body => _buffer.AsMemory().Slice(0, _start); + + public Utf8JsonWriter JsonWriter => _writer; + + public byte[] GetInternalBuffer() => _buffer; + + public void WriteStartObject() + { + _writer.WriteStartObject(); + _writer.Flush(); + } + + public void WriteEndObject() + { + _writer.WriteEndObject(); + _writer.Flush(); + } + + public void WriteStartArray() + { + _writer.WriteStartArray(); + _writer.Flush(); + } + + public void WriteEndArray() + { + _writer.WriteEndArray(); + _writer.Flush(); + } + + public void WriteQuery(IQuery query) + { + _writer.WriteString("query", query.ToSpan()); + _writer.Flush(); + } + + public void WriteOperationName(string operationName) + { + if (operationName is { }) + { + _writer.WriteString("operationName", operationName); + _writer.Flush(); + } + } + + public void WritePropertyName(string name) + { + _writer.WritePropertyName(name); + _writer.Flush(); + } + + public void WriteNullValue() + { + _writer.WriteNullValue(); + _writer.Flush(); + } + + public void WriteStringValue(string value) + { + _writer.WriteStringValue(value); + _writer.Flush(); + } + + public void WriteBooleanValue(bool value) + { + _writer.WriteBooleanValue(value); + _writer.Flush(); + } + + public void WriteNumberValue(string value) + { + Span span = GetSpan(value.Length); + + for (int i = 0; i < value.Length; i++) + { + span[i] = (byte)value[i]; + } + + Advance(value.Length); + } + + public void Advance(int count) + { + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + _start += count; + _capacity -= count; + } + + public Memory GetMemory(int sizeHint = 0) + { + var size = sizeHint < 1 ? _initialBufferSize : sizeHint; + EnsureBufferCapacity(size); + return _buffer.AsMemory().Slice(_start, size); + } + + public Span GetSpan(int sizeHint = 0) + { + var size = sizeHint < 1 ? _initialBufferSize : sizeHint; + EnsureBufferCapacity(size); + return _buffer.AsSpan().Slice(_start, size); + } + + private void EnsureBufferCapacity(int neededCapacity) + { + if (_capacity < neededCapacity) + { + byte[] buffer = _buffer; + + int newSize = _buffer.Length * 2; + if (neededCapacity > buffer.Length) + { + newSize += neededCapacity; + } + + _buffer = ArrayPool.Shared.Rent(newSize); + _capacity += _buffer.Length - buffer.Length; + + buffer.AsSpan().CopyTo(_buffer); + ArrayPool.Shared.Return(buffer); + } + } + + public void Clear() + { + ArrayPool.Shared.Return(_buffer); + _buffer = ArrayPool.Shared.Rent(_initialBufferSize); + _capacity = _buffer.Length; + } + + public void Dispose() + { + if (!_disposed) + { + ArrayPool.Shared.Return(_buffer); + _buffer = Array.Empty(); + _disposed = true; + } + } + } +} diff --git a/src/Stitching/Stitching/Utilities/MergeQueryRewriter.cs b/src/Stitching/Stitching/Utilities/MergeQueryRewriter.cs index 2fdfa32774c..ed87f3abe0c 100644 --- a/src/Stitching/Stitching/Utilities/MergeQueryRewriter.cs +++ b/src/Stitching/Stitching/Utilities/MergeQueryRewriter.cs @@ -9,6 +9,7 @@ namespace HotChocolate.Stitching.Utilities internal class MergeQueryRewriter : QuerySyntaxRewriter { + private static readonly NameNode _defaultName = new NameNode("exec_batch"); private static readonly HashSet _emptySet = new HashSet(); private readonly List _fields = new List(); @@ -40,6 +41,8 @@ public MergeQueryRewriter(IEnumerable globalVariableNames) private bool IsAutoGenerated => !_rewriteFragments; + public NameNode OperationName => _operationName ?? _defaultName; + public void SetOperationName(NameNode name) => _operationName = name; public IDictionary AddQuery( @@ -117,7 +120,7 @@ public DocumentNode Merge() definitions.Add(new OperationDefinitionNode ( null, - _operationName ?? new NameNode("exec_batch"), + _operationName ?? _defaultName, _operationType.Value, new List(_variables.Values), Array.Empty(), diff --git a/src/Stitching/Stitching/Utilities/ObjectVariableRewriter.cs b/src/Stitching/Stitching/Utilities/ObjectVariableRewriter.cs deleted file mode 100644 index 94849fb89b5..00000000000 --- a/src/Stitching/Stitching/Utilities/ObjectVariableRewriter.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Collections.Generic; -using HotChocolate.Types; - -namespace HotChocolate.Stitching.Utilities -{ - internal static class ObjectVariableRewriter - { - public static object RewriteVariable( - NameString schemaName, - IInputType type, - object value) - { - return RewriteVariableValue(in schemaName, type, value); - } - - private static IDictionary RewriteVariableObject( - in NameString schemaName, - InputObjectType type, - IDictionary dict) - { - foreach (IInputField field in type.Fields) - { - if (field.TryGetSourceDirective(schemaName, - out SourceDirective sourceDirective) - && !sourceDirective.Name.Equals(field.Name) - && dict.TryGetValue(field.Name, out object o)) - { - dict.Remove(field.Name); - dict.Add(sourceDirective.Name, o); - } - } - return dict; - } - - private static IList RewriteVariableList( - in NameString schemaName, - ListType type, - IList list) - { - INamedType namedType = type.NamedType(); - - for (int i = 0; i < list.Count; i++) - { - list[i] = RewriteVariableValue( - schemaName, namedType, list[i]); - } - return list; - } - - private static object RewriteVariableValue( - in NameString schemaName, - IType type, - object value) - { - if (type.IsListType() && value is IList list) - { - return RewriteVariableList( - in schemaName, type.ListType(), list); - } - else if (type.NamedType() is InputObjectType inputObject - && value is IDictionary dict) - { - return RewriteVariableObject( - in schemaName, inputObject, dict); - } - else - { - return value; - } - } - } -} diff --git a/src/Templates/StarWars/content/StarWars.sln b/src/Templates/StarWars/content/StarWars.sln index f6639f8b6b6..7c402f12c8c 100644 --- a/src/Templates/StarWars/content/StarWars.sln +++ b/src/Templates/StarWars/content/StarWars.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StarWars", "StarWars\StarWars.csproj", "{DD35F196-1631-4C30-8369-68FACB27BA8A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StarWars", "StarWars\StarWars.csproj", "{DD35F196-1631-4C30-8369-68FACB27BA8A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tools/Build.Core.sln b/tools/Build.Core.sln index 850662708c9..876ae9868aa 100644 --- a/tools/Build.Core.sln +++ b/tools/Build.Core.sln @@ -73,9 +73,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.HttpGet", "..\sr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.HttpPost", "..\src\Server\AspNetCore.HttpPost\AspNetCore.HttpPost.csproj", "{CBD7536C-543D-4E10-8FB5-196895FC761B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersistedQueries.FileSystem", "..\src\Core\PersistedQueries.FileSystem\PersistedQueries.FileSystem.csproj", "{61EDA3F4-1184-4CDB-927D-F0A02C45C550}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersistedQueries.FileSystem", "..\src\Core\PersistedQueries.FileSystem\PersistedQueries.FileSystem.csproj", "{61EDA3F4-1184-4CDB-927D-F0A02C45C550}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersistedQueries.Redis", "..\src\Core\PersistedQueries.Redis\PersistedQueries.Redis.csproj", "{EAB3DACC-27D1-405E-9C97-4DD651C69C56}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersistedQueries.Redis", "..\src\Core\PersistedQueries.Redis\PersistedQueries.Redis.csproj", "{EAB3DACC-27D1-405E-9C97-4DD651C69C56}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersistedQueries.FileSystem.Tests", "..\src\Core\PersistedQueries.FileSystem.Tests\PersistedQueries.FileSystem.Tests.csproj", "{DD1345AC-A55D-4E41-8F2A-0EE2ECA74B2D}" EndProject @@ -91,11 +91,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenDonut.Tests", "..\src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenDonut.DiagnosticSource.Tests", "..\src\DataLoader\DiagnosticSource.Tests\GreenDonut.DiagnosticSource.Tests.csproj", "{1D789F92-E049-47A9-8220-D0919082DA47}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting", "..\src\Core\Types.Sorting\Types.Sorting.csproj", "{1AE961BF-3BDA-44D2-BC58-F01FF86E27DF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting", "..\src\Core\Types.Sorting\Types.Sorting.csproj", "{1AE961BF-3BDA-44D2-BC58-F01FF86E27DF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting.Mongo.Tests", "..\src\Core\Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{C1A847C5-C2DF-4602-9E15-8BB01EA434A3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Mongo.Tests", "..\src\Core\Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{C1A847C5-C2DF-4602-9E15-8BB01EA434A3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting.Tests", "..\src\Core\Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{F2C3763D-4331-4E38-968E-2DD38953F4EB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Tests", "..\src\Core\Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{F2C3763D-4331-4E38-968E-2DD38953F4EB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tools/Build.sln b/tools/Build.sln index a6366adbe03..ba914d17b7f 100644 --- a/tools/Build.sln +++ b/tools/Build.sln @@ -113,11 +113,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenDonut.Tests", "..\src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenDonut.DiagnosticSource.Tests", "..\src\DataLoader\DiagnosticSource.Tests\GreenDonut.DiagnosticSource.Tests.csproj", "{FE0F443F-A0C5-4222-8E53-A5C3328DB545}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting", "..\src\Core\Types.Sorting\Types.Sorting.csproj", "{47068127-8C8B-411F-B620-A6AC70F97CAB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting", "..\src\Core\Types.Sorting\Types.Sorting.csproj", "{47068127-8C8B-411F-B620-A6AC70F97CAB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting.Tests", "..\src\Core\Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{546E0DFD-40F2-41F5-AC54-52DD1D168D24}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Tests", "..\src\Core\Types.Sorting.Tests\Types.Sorting.Tests.csproj", "{546E0DFD-40F2-41F5-AC54-52DD1D168D24}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Types.Sorting.Mongo.Tests", "..\src\Core\Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{77432023-09F0-481B-BA86-1D0C233A24AF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Types.Sorting.Mongo.Tests", "..\src\Core\Types.Sorting.Mongo.Tests\Types.Sorting.Mongo.Tests.csproj", "{77432023-09F0-481B-BA86-1D0C233A24AF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution