diff --git a/src/HotChocolate/Core/src/Abstractions/Execution/IQuery.cs b/src/HotChocolate/Core/src/Abstractions/Execution/IQuery.cs index 9590075e8f0..21bac84ba4d 100644 --- a/src/HotChocolate/Core/src/Abstractions/Execution/IQuery.cs +++ b/src/HotChocolate/Core/src/Abstractions/Execution/IQuery.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Execution { /// - /// Represent a executable query. + /// Represents an executable query. /// public interface IQuery { diff --git a/src/HotChocolate/Core/src/Abstractions/IExecutable.cs b/src/HotChocolate/Core/src/Abstractions/IExecutable.cs new file mode 100644 index 00000000000..34bf6a02b72 --- /dev/null +++ b/src/HotChocolate/Core/src/Abstractions/IExecutable.cs @@ -0,0 +1,12 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace HotChocolate +{ + public interface IExecutable + { + ValueTask ExecuteAsync(CancellationToken cancellationToken); + + string Print(); + } +} diff --git a/src/HotChocolate/Core/src/Abstractions/IExecutable~1.cs b/src/HotChocolate/Core/src/Abstractions/IExecutable~1.cs new file mode 100644 index 00000000000..fbe7a0df091 --- /dev/null +++ b/src/HotChocolate/Core/src/Abstractions/IExecutable~1.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace HotChocolate +{ + public interface IExecutable : IExecutable + { + new ValueTask> ExecuteAsync(CancellationToken cancellationToken); + } +} diff --git a/src/HotChocolate/Core/src/Execution/Extensions/ExecutionRequestExecutorExtensions.cs b/src/HotChocolate/Core/src/Execution/Extensions/ExecutionRequestExecutorExtensions.cs index 650dd8e79b6..9b9eb5316dc 100644 --- a/src/HotChocolate/Core/src/Execution/Extensions/ExecutionRequestExecutorExtensions.cs +++ b/src/HotChocolate/Core/src/Execution/Extensions/ExecutionRequestExecutorExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using static HotChocolate.Execution.Properties.Resources; namespace HotChocolate.Execution { @@ -38,7 +39,7 @@ public static class ExecutionRequestExecutorExtensions if (string.IsNullOrEmpty(query)) { throw new ArgumentException( - "The query mustn't be null or empty.", + ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty, nameof(query)); } @@ -60,7 +61,7 @@ public static class ExecutionRequestExecutorExtensions if (string.IsNullOrEmpty(query)) { throw new ArgumentException( - "The query mustn't be null or empty.", + ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty, nameof(query)); } @@ -82,7 +83,7 @@ public static class ExecutionRequestExecutorExtensions if (string.IsNullOrEmpty(query)) { throw new ArgumentException( - "The query mustn't be null or empty.", + ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty, nameof(query)); } @@ -113,7 +114,7 @@ public static class ExecutionRequestExecutorExtensions if (string.IsNullOrEmpty(query)) { throw new ArgumentException( - "The query mustn't be null or empty.", + ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty, nameof(query)); } @@ -163,7 +164,7 @@ public static class ExecutionRequestExecutorExtensions if (string.IsNullOrEmpty(query)) { throw new ArgumentException( - "The query mustn't be null or empty.", + ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty, nameof(query)); } @@ -186,7 +187,7 @@ public static class ExecutionRequestExecutorExtensions if (string.IsNullOrEmpty(query)) { throw new ArgumentException( - "The query mustn't be null or empty.", + ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty, nameof(query)); } diff --git a/src/HotChocolate/Core/src/Execution/Processing/ArgumentNonNullValidator.cs b/src/HotChocolate/Core/src/Execution/Processing/ArgumentNonNullValidator.cs index 2918eeb1793..623ae19f329 100644 --- a/src/HotChocolate/Core/src/Execution/Processing/ArgumentNonNullValidator.cs +++ b/src/HotChocolate/Core/src/Execution/Processing/ArgumentNonNullValidator.cs @@ -8,15 +8,36 @@ internal static class ArgumentNonNullValidator { public static ValidationResult Validate(IInputField field, IValueNode? value, Path path) { - if (value.IsNull()) + // if no value was provided + if (value is null) { + // the type is a non-null type and no default value has been set we mark this + // field as violation. if (field.Type.IsNonNullType() && field.DefaultValue.IsNull()) { return new ValidationResult(field.Type, path); } + + // if the field has a default value or nullable everything is fine and we + // return success. return default; } + // if null was explicitly set + if (value is NullValueNode) + { + // and the field type is a non-null type we will mark the field value + // as violation. + if (field.Type.IsNonNullType()) + { + return new ValidationResult(field.Type, path); + } + + // if the field is nullable we will mark the field as valid. + return default; + } + + // if the field has a value we traverse it and make sure the value is correct. return ValidateInnerType(field.Type, value, path); } @@ -40,10 +61,8 @@ private static ValidationResult ValidateInnerType(IType type, IValueNode? value, { return ValidateList(listType, listValue, path); } - else - { - Validate(listType.ElementType, value, path); - } + + Validate(listType.ElementType, value, path); } if (innerType is InputObjectType inputType && value is ObjectValueNode ov) @@ -61,7 +80,7 @@ private static ValidationResult ValidateInnerType(IType type, IValueNode? value, { var fields = new Dictionary(); - for (int i = 0; i < value.Fields.Count; i++) + for (var i = 0; i < value.Fields.Count; i++) { ObjectFieldNode field = value.Fields[i]; fields[field.Name.Value] = field.Value; @@ -88,7 +107,7 @@ private static ValidationResult ValidateInnerType(IType type, IValueNode? value, private static ValidationResult ValidateList(ListType type, ListValueNode list, Path path) { IType elementType = type.ElementType(); - int i = 0; + var i = 0; foreach (IValueNode element in list.Items) { diff --git a/src/HotChocolate/Core/src/Execution/Processing/ResolverTask.cs b/src/HotChocolate/Core/src/Execution/Processing/ResolverTask.cs index d03b6abfd99..54260923ae9 100644 --- a/src/HotChocolate/Core/src/Execution/Processing/ResolverTask.cs +++ b/src/HotChocolate/Core/src/Execution/Processing/ResolverTask.cs @@ -66,6 +66,10 @@ private async ValueTask ExecuteResolverPipelineAsync() switch (_context.Result) { + case IExecutable executable: + _context.Result = await executable.ExecuteAsync(_context.RequestAborted); + break; + case IQueryable queryable: _context.Result = await Task.Run(() => { diff --git a/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs b/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs index b94b38dc1fb..35d330f008b 100644 --- a/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs +++ b/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs @@ -284,5 +284,11 @@ internal class Resources { return ResourceManager.GetString("OperationCompiler_Compile_SelectionSetIsEmpty", resourceCulture); } } + + internal static string ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty { + get { + return ResourceManager.GetString("ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty", resourceCulture); + } + } } } diff --git a/src/HotChocolate/Core/src/Execution/Properties/Resources.resx b/src/HotChocolate/Core/src/Execution/Properties/Resources.resx index f379b3eaa5f..e871aedde2f 100644 --- a/src/HotChocolate/Core/src/Execution/Properties/Resources.resx +++ b/src/HotChocolate/Core/src/Execution/Properties/Resources.resx @@ -237,4 +237,7 @@ The operation selection set is empty. + + The query cannot be null or empty. + \ No newline at end of file diff --git a/src/HotChocolate/Core/src/Execution/Serialization/JsonQueryResultSerializer.cs b/src/HotChocolate/Core/src/Execution/Serialization/JsonQueryResultSerializer.cs index 3e47f744385..a6f431350d2 100644 --- a/src/HotChocolate/Core/src/Execution/Serialization/JsonQueryResultSerializer.cs +++ b/src/HotChocolate/Core/src/Execution/Serialization/JsonQueryResultSerializer.cs @@ -194,6 +194,13 @@ private static void WritePath(Utf8JsonWriter writer, Path? path) private static void WritePathValue(Utf8JsonWriter writer, Path path) { + if (path is RootPathSegment) + { + writer.WriteStartArray(); + writer.WriteEndArray(); + return; + } + writer.WriteStartArray(); IReadOnlyList list = path.ToList(); @@ -400,7 +407,7 @@ private static void WritePathValue(Utf8JsonWriter writer, Path path) break; case Path p: - WritePath(writer, p); + WritePathValue(writer, p); break; default: diff --git a/src/HotChocolate/Core/src/Types/Configuration/SyntaxTypeReferenceHandler.cs b/src/HotChocolate/Core/src/Types/Configuration/SyntaxTypeReferenceHandler.cs index 861619047dd..0242cfd0cf6 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/SyntaxTypeReferenceHandler.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/SyntaxTypeReferenceHandler.cs @@ -13,6 +13,7 @@ internal sealed class SyntaxTypeReferenceHandler : ITypeRegistrarHandler { private readonly ITypeInspector _typeInspector; + private readonly HashSet _handled = new HashSet(); public SyntaxTypeReferenceHandler(ITypeInspector typeInspector) { @@ -26,9 +27,9 @@ public SyntaxTypeReferenceHandler(ITypeInspector typeInspector) foreach (SyntaxTypeReference typeReference in typeReferences.OfType()) { - if (Scalars.TryGetScalar( - typeReference.Type.NamedType().Name.Value, - out Type? scalarType)) + string name = typeReference.Type.NamedType().Name.Value; + if (_handled.Add(name) && + Scalars.TryGetScalar(name, out Type? scalarType)) { ExtendedTypeReference namedTypeReference = _typeInspector.GetTypeRef(scalarType); diff --git a/src/HotChocolate/Core/src/Types/Configuration/TypeDiscoverer.cs b/src/HotChocolate/Core/src/Types/Configuration/TypeDiscoverer.cs index 9e909963c14..22815a27bc0 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/TypeDiscoverer.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/TypeDiscoverer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using HotChocolate.Language; using HotChocolate.Properties; using HotChocolate.Types; using HotChocolate.Types.Descriptors; @@ -109,7 +110,7 @@ public IReadOnlyList DiscoverTypes() if (_errors.Count == 0) { - _typeRegistry.CompleteDiscovery(); + _typeRegistry.CompleteDiscovery(); } return _errors; @@ -190,7 +191,7 @@ private void CollectErrors() { builder.SetTypeSystemObject(types[0].Type); } - else if(types.Count > 1) + else if (types.Count > 1) { builder .SetTypeSystemObject(types[0].Type) diff --git a/src/HotChocolate/Core/src/Types/Configuration/TypeRegistry.cs b/src/HotChocolate/Core/src/Types/Configuration/TypeRegistry.cs index 9c55a310b32..90e3494c932 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/TypeRegistry.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/TypeRegistry.cs @@ -149,6 +149,17 @@ public void Register(RegisteredType registeredType) } } + public void Register(NameString typeName, ExtendedTypeReference typeReference) + { + if (typeReference is null) + { + throw new ArgumentNullException(nameof(typeReference)); + } + + typeName.EnsureNotEmpty(nameof(typeName)); + _nameRefs[typeName] = typeReference; + } + public void Register(NameString typeName, RegisteredType registeredType) { if (registeredType is null) diff --git a/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Helper.cs b/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Helper.cs index 095c5465896..72931324be9 100644 --- a/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Helper.cs +++ b/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Helper.cs @@ -166,7 +166,8 @@ public static bool IsSupportedCollectionInterface(Type type) || typeDefinition == typeof(ImmutableList<>) || typeDefinition == typeof(ImmutableQueue<>) || typeDefinition == typeof(ImmutableStack<>) - || typeDefinition == typeof(ImmutableHashSet<>)) + || typeDefinition == typeof(ImmutableHashSet<>) + || typeDefinition == typeof(IExecutable<>)) { return true; } diff --git a/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Members.cs b/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Members.cs index 026c9f24a5d..90c5a506c0f 100644 --- a/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Members.cs +++ b/src/HotChocolate/Core/src/Types/Internal/ExtendedType.Members.cs @@ -40,7 +40,8 @@ public static ExtendedMethodInfo FromMethod(MethodInfo method, TypeCache cache) method, () => Rewrite( CreateExtendedType(context, helper.GetFlags(method), method.ReturnType), - method, cache)); + method, + cache)); ParameterInfo[] parameters = method.GetParameters(); var parameterTypes = new Dictionary(); @@ -203,6 +204,7 @@ public static ExtendedMethodInfo FromMethod(MethodInfo method, TypeCache cache) state = flags[0]; } } + return state; } } diff --git a/src/HotChocolate/Core/src/Types/Internal/ExtendedType.SystemType.cs b/src/HotChocolate/Core/src/Types/Internal/ExtendedType.SystemType.cs index 1a513799c76..d13fc99df33 100644 --- a/src/HotChocolate/Core/src/Types/Internal/ExtendedType.SystemType.cs +++ b/src/HotChocolate/Core/src/Types/Internal/ExtendedType.SystemType.cs @@ -20,7 +20,7 @@ private static ExtendedType FromTypeInternal(Type type, TypeCache cache) && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { Type inner = type.GetGenericArguments()[0]; - + return new ExtendedType( inner, ExtendedTypeKind.Runtime, @@ -50,7 +50,7 @@ private static ExtendedType FromTypeInternal(Type type, TypeCache cache) } public static IReadOnlyList GetGenericArguments( - Type type, + Type type, TypeCache cache) { if (type.IsGenericType) diff --git a/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs b/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs index a1e8cf0e3a7..14810c4363f 100644 --- a/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs +++ b/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs @@ -112,10 +112,12 @@ public static Schema Create(SchemaBuilder builder) builder, OperationType.Query, visitor.QueryTypeName); + RegisterOperationName( builder, OperationType.Mutation, visitor.MutationTypeName); + RegisterOperationName( builder, OperationType.Subscription, @@ -334,7 +336,7 @@ public static Schema Create(SchemaBuilder builder) Dictionary operations = builder._operations.ToDictionary( - t => t.Key, + t => t.Key, t => t.Value(context.TypeInspector)); definition.QueryType = ResolveOperation( diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Definitions/FieldDefinitionBase.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Definitions/FieldDefinitionBase.cs index 3c92e058981..ab6ae11d5c2 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Definitions/FieldDefinitionBase.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Definitions/FieldDefinitionBase.cs @@ -7,24 +7,10 @@ public abstract class FieldDefinitionBase : DefinitionBase , IHasDirectiveDefinition { - private ITypeReference type; - /// /// Gets the field type. /// - public ITypeReference Type - { - get => type; - set - { - if(type is ExtendedTypeReference r && - r.Type.Kind == ExtendedTypeKind.Extended) - { - - } - type = value; - } - } + public ITypeReference Type { get; set; } /// /// Defines if this field is ignored and will diff --git a/src/HotChocolate/Core/src/Types/Types/Factories/ObjectTypeFactory.cs b/src/HotChocolate/Core/src/Types/Types/Factories/ObjectTypeFactory.cs index 5c643e997e2..3b9cef6db42 100644 --- a/src/HotChocolate/Core/src/Types/Types/Factories/ObjectTypeFactory.cs +++ b/src/HotChocolate/Core/src/Types/Types/Factories/ObjectTypeFactory.cs @@ -4,6 +4,8 @@ using HotChocolate.Configuration; using HotChocolate.Language; +#nullable enable + namespace HotChocolate.Types.Factories { internal sealed class ObjectTypeFactory @@ -34,8 +36,7 @@ internal sealed class ObjectTypeFactory if (bindingInfo.SourceType != null) { - d.Extend().OnBeforeCreate( - t => t.RuntimeType = bindingInfo.SourceType); + d.Extend().OnBeforeCreate(t => t.RuntimeType = bindingInfo.SourceType); } foreach (DirectiveNode directive in node.Directives) @@ -91,10 +92,10 @@ internal sealed class ObjectTypeFactory } } - string deprecactionReason = fieldDefinition.DeprecationReason(); - if (!string.IsNullOrEmpty(deprecactionReason)) + string deprecationReason = fieldDefinition.DeprecationReason(); + if (!string.IsNullOrEmpty(deprecationReason)) { - fieldDescriptor.Deprecated(deprecactionReason); + fieldDescriptor.Deprecated(deprecationReason); } DeclareFieldArguments(fieldDescriptor, fieldDefinition); @@ -112,8 +113,7 @@ internal sealed class ObjectTypeFactory a => { IArgumentDescriptor descriptor = a - .Description( - inputFieldDefinition.Description?.Value) + .Description(inputFieldDefinition.Description?.Value) .Type(inputFieldDefinition.Type) .DefaultValue(inputFieldDefinition.DefaultValue) .SyntaxNode(inputFieldDefinition); diff --git a/src/HotChocolate/Core/src/Types/Types/Factories/UnionTypeFactory.cs b/src/HotChocolate/Core/src/Types/Types/Factories/UnionTypeFactory.cs index ad402be7445..02024b93f6b 100644 --- a/src/HotChocolate/Core/src/Types/Types/Factories/UnionTypeFactory.cs +++ b/src/HotChocolate/Core/src/Types/Types/Factories/UnionTypeFactory.cs @@ -32,8 +32,7 @@ internal sealed class UnionTypeFactory if (bindingInfo.SourceType != null) { - d.Extend().OnBeforeCreate( - t => t.RuntimeType = bindingInfo.SourceType); + d.Extend().OnBeforeCreate(t => t.RuntimeType = bindingInfo.SourceType); } foreach (NamedTypeNode namedType in node.Types) diff --git a/src/HotChocolate/Core/src/Types/Types/Helpers/TypeDependencyHelper.cs b/src/HotChocolate/Core/src/Types/Types/Helpers/TypeDependencyHelper.cs index b989c436702..22699a35b68 100644 --- a/src/HotChocolate/Core/src/Types/Types/Helpers/TypeDependencyHelper.cs +++ b/src/HotChocolate/Core/src/Types/Types/Helpers/TypeDependencyHelper.cs @@ -126,7 +126,7 @@ internal static class TypeDependencyHelper { RegisterAdditionalDependencies(context, field); - if (field.Type != null) + if (field.Type is not null) { context.RegisterDependency(field.Type, TypeDependencyKind.Default); @@ -158,13 +158,13 @@ internal static class TypeDependencyHelper private static void RegisterFieldDependencies( this ITypeDiscoveryContext context, - IEnumerable fields) + IReadOnlyList fields) { foreach (OutputFieldDefinitionBase field in fields) { RegisterAdditionalDependencies(context, field); - if (field.Type != null) + if (field.Type is not null) { context.RegisterDependency(field.Type, TypeDependencyKind.Default); @@ -173,10 +173,10 @@ internal static class TypeDependencyHelper context.RegisterDependencyRange( field.Directives.Select(t => t.TypeReference), TypeDependencyKind.Completed); - - RegisterFieldDependencies(context, - fields.SelectMany(t => t.Arguments).ToList()); } + + RegisterFieldDependencies(context, + fields.SelectMany(t => t.Arguments)); } private static void RegisterFieldDependencies( @@ -187,7 +187,7 @@ internal static class TypeDependencyHelper { RegisterAdditionalDependencies(context, field); - if (field.Type != null) + if (field.Type is not null) { context.RegisterDependency(field.Type, TypeDependencyKind.Completed); diff --git a/src/HotChocolate/Core/src/Types/Types/ObjectType.cs b/src/HotChocolate/Core/src/Types/Types/ObjectType.cs index f661f686fa4..837958a6881 100644 --- a/src/HotChocolate/Core/src/Types/Types/ObjectType.cs +++ b/src/HotChocolate/Core/src/Types/Types/ObjectType.cs @@ -6,6 +6,7 @@ using HotChocolate.Resolvers; using HotChocolate.Types.Descriptors; using HotChocolate.Types.Descriptors.Definitions; +using static HotChocolate.Utilities.ErrorHelper; #nullable enable @@ -133,21 +134,7 @@ private void CompleteIsOfType(ITypeCompletionContext context) foreach (ObjectFieldDefinition field in invalidFields) { - // TODO : ErrorHelper - context.ReportError(SchemaErrorBuilder.New() - .SetMessage( - "Unable to infer or resolve the type of " + - "field {0}.{1}. Try to explicitly provide the " + - "type like the following: " + - "`descriptor.Field(\"field\")" + - ".Type>()`.", - Name, - field.Name) - .SetCode(ErrorCodes.Schema.NoFieldType) - .SetTypeSystemObject(this) - .SetPath(Path.New(Name).Append(field.Name)) - .SetExtension(TypeErrorFields.Definition, field) - .Build()); + context.ReportError(ObjectType_UnableToInferOrResolveType(Name, this, field)); } return invalidFields.Length == 0; diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/IntType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/IntType.cs index f390e36eae7..8b8d5ac7d64 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/IntType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/IntType.cs @@ -17,28 +17,28 @@ public sealed class IntType : IntegerTypeBase { public IntType() - : this(int.MinValue, int.MaxValue) + : this(ScalarNames.Int, + TypeResources.IntType_Description, + bind: BindingBehavior.Implicit) { } public IntType(int min, int max) - : this(ScalarNames.Int, min, max) + : this(ScalarNames.Int, + TypeResources.IntType_Description, + min, + max, + BindingBehavior.Implicit) { - Description = TypeResources.IntType_Description; } - public IntType(NameString name) - : this(name, int.MinValue, int.MaxValue) - { - } - - public IntType(NameString name, int min, int max) - : base(name, min, max, BindingBehavior.Implicit) - { - } - - public IntType(NameString name, string description, int min, int max) - : base(name, min, max, BindingBehavior.Implicit) + public IntType( + NameString name, + string? description = null, + int min = int.MinValue, + int max = int.MaxValue, + BindingBehavior bind = BindingBehavior.Explicit) + : base(name, min, max, bind) { Description = description; } diff --git a/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs index ebf8b300937..4a25fc72d6d 100644 --- a/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs @@ -1,6 +1,7 @@ using HotChocolate.Language; using HotChocolate.Properties; using HotChocolate.Types; +using HotChocolate.Types.Descriptors.Definitions; #nullable enable @@ -10,7 +11,7 @@ internal static class ErrorHelper { public static ISchemaError CompleteInterfacesHelper_UnableToResolveInterface( ITypeSystemObject interfaceOrObject, - ISyntaxNode? node)=> + ISyntaxNode? node)=> SchemaErrorBuilder.New() .SetMessage("COULD NOT RESOLVE INTERFACE") .SetCode(ErrorCodes.Schema.MissingType) @@ -38,7 +39,7 @@ internal static class ErrorHelper Types.DirectiveLocation location, ITypeSystemObject type, DirectiveNode? syntaxNode, - object source) => + object source) => SchemaErrorBuilder.New() .SetMessage( TypeResources.DirectiveCollection_LocationNotAllowed, @@ -55,7 +56,7 @@ internal static class ErrorHelper ITypeSystemObject type, DirectiveNode? syntaxNode, object source, - string argumentName) => + string argumentName) => SchemaErrorBuilder.New() .SetMessage( "The argument `{0}` value type is wrong.", @@ -101,5 +102,22 @@ internal static class ErrorHelper .AddSyntaxNode(syntaxNode) .SetExtension("Source", source) .Build(); + + public static ISchemaError ObjectType_UnableToInferOrResolveType( + NameString typeName, ObjectType type, ObjectFieldDefinition field) => + SchemaErrorBuilder.New() + .SetMessage( + "Unable to infer or resolve the type of " + + "field {0}.{1}. Try to explicitly provide the " + + "type like the following: " + + "`descriptor.Field(\"field\")" + + ".Type>()`.", + typeName, + field.Name) + .SetCode(ErrorCodes.Schema.NoFieldType) + .SetTypeSystemObject(type) + .SetPath(Path.New(typeName).Append(field.Name)) + .SetExtension(TypeErrorFields.Definition, field) + .Build(); } } diff --git a/src/HotChocolate/Core/src/Validation/Rules/FragmentVisitor.cs b/src/HotChocolate/Core/src/Validation/Rules/FragmentVisitor.cs index 54b9bed4449..09ee201cf1f 100644 --- a/src/HotChocolate/Core/src/Validation/Rules/FragmentVisitor.cs +++ b/src/HotChocolate/Core/src/Validation/Rules/FragmentVisitor.cs @@ -73,7 +73,7 @@ internal sealed class FragmentVisitor : TypeDocumentValidatorVisitor { context.Names.Clear(); - for (int i = 0; i < node.Definitions.Count; i++) + for (var i = 0; i < node.Definitions.Count; i++) { IDefinitionNode definition = node.Definitions[i]; if (definition.Kind == SyntaxKind.FragmentDefinition) @@ -114,19 +114,18 @@ internal sealed class FragmentVisitor : TypeDocumentValidatorVisitor { return Skip; } - else if (context.Types.TryPeek(out IType type) && + + if (context.Types.TryPeek(out IType type) && type.NamedType() is IComplexOutputType ot && - ot.Fields.TryGetField(node.Name.Value, out IOutputField of)) + ot.Fields.TryGetField(node.Name.Value, out IOutputField? of)) { context.OutputFields.Push(of); context.Types.Push(of.Type); return Continue; } - else - { - context.UnexpectedErrorsDetected = true; - return Skip; - } + + context.UnexpectedErrorsDetected = true; + return Skip; } protected override ISyntaxVisitorAction Leave( @@ -157,17 +156,13 @@ internal sealed class FragmentVisitor : TypeDocumentValidatorVisitor context.Types.Push(type); return Continue; } - else - { - context.Errors.Add(context.FragmentOnlyCompositeType(node, type.NamedType())); - return Skip; - } - } - else - { - context.Errors.Add(context.FragmentTypeConditionUnknown(node, node.TypeCondition)); + + context.Errors.Add(context.FragmentOnlyCompositeType(node, type.NamedType())); return Skip; } + + context.Errors.Add(context.FragmentTypeConditionUnknown(node, node.TypeCondition)); + return Skip; } protected override ISyntaxVisitorAction Leave( @@ -186,7 +181,8 @@ internal sealed class FragmentVisitor : TypeDocumentValidatorVisitor { return Continue; } - else if (context.Schema.TryGetType( + + if (context.Schema.TryGetType( node.TypeCondition.Name.Value, out INamedOutputType type)) { @@ -199,17 +195,13 @@ internal sealed class FragmentVisitor : TypeDocumentValidatorVisitor context.Types.Push(type); return Continue; } - else - { - context.Errors.Add(context.FragmentOnlyCompositeType(node, type.NamedType())); - return Skip; - } - } - else - { - context.Errors.Add(context.FragmentTypeConditionUnknown(node, node.TypeCondition)); + + context.Errors.Add(context.FragmentOnlyCompositeType(node, type.NamedType())); return Skip; } + + context.Errors.Add(context.FragmentTypeConditionUnknown(node, node.TypeCondition)); + return Skip; } protected override ISyntaxVisitorAction Enter( diff --git a/src/HotChocolate/Core/src/Validation/Rules/ValueVisitor.cs b/src/HotChocolate/Core/src/Validation/Rules/ValueVisitor.cs index 76b3bcd5182..a98c42b9648 100644 --- a/src/HotChocolate/Core/src/Validation/Rules/ValueVisitor.cs +++ b/src/HotChocolate/Core/src/Validation/Rules/ValueVisitor.cs @@ -60,7 +60,7 @@ public ValueVisitor() if (context.Types.TryPeek(out IType type) && type.NamedType() is IComplexOutputType ot && - ot.Fields.TryGetField(node.Name.Value, out IOutputField of)) + ot.Fields.TryGetField(node.Name.Value, out IOutputField? of)) { context.OutputFields.Push(of); context.Types.Push(of.Type); @@ -131,7 +131,7 @@ public ValueVisitor() { if (context.Directives.TryPeek(out DirectiveType directive)) { - if (directive.Arguments.TryGetField(node.Name.Value, out Argument argument)) + if (directive.Arguments.TryGetField(node.Name.Value, out Argument? argument)) { context.InputFields.Push(argument); context.Types.Push(argument.Type); @@ -143,7 +143,7 @@ public ValueVisitor() if (context.OutputFields.TryPeek(out IOutputField field)) { - if (field.Arguments.TryGetField(node.Name.Value, out IInputField argument)) + if (field.Arguments.TryGetField(node.Name.Value, out IInputField? argument)) { context.InputFields.Push(argument); context.Types.Push(argument.Type); @@ -221,7 +221,7 @@ public ValueVisitor() { if (context.Types.TryPeek(out IType type) && type.NamedType() is InputObjectType it && - it.Fields.TryGetField(node.Name.Value, out InputField field)) + it.Fields.TryGetField(node.Name.Value, out InputField? field)) { if (field.Type.IsNonNullType() && node.Value.IsNull()) diff --git a/src/HotChocolate/Core/test/Execution.Tests/ArgumentNonNullValidatorTests.cs b/src/HotChocolate/Core/test/Execution.Tests/ArgumentNonNullValidatorTests.cs index 735556320b4..d825160d01b 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/ArgumentNonNullValidatorTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/ArgumentNonNullValidatorTests.cs @@ -22,15 +22,16 @@ public void Validate_Input_With_Non_Null_Props_That_Have_No_Value_But_A_DefaultV a: String! = ""bar"" } ") - .Use(next => context => default(ValueTask)) + .Use(next => context => default) .Create(); IInputField field = schema.QueryType.Fields["test"].Arguments["bar"]; // act - var report = ArgumentNonNullValidator.Validate( - field, - new ObjectValueNode(), Path.New("root")); + ArgumentNonNullValidator.ValidationResult report = + ArgumentNonNullValidator.Validate( + field, + new ObjectValueNode(), Path.New("root")); // assert Assert.False(report.HasErrors); diff --git a/src/HotChocolate/Core/test/Execution.Tests/AutoUpdateRequestExecutorProxyTests.cs b/src/HotChocolate/Core/test/Execution.Tests/AutoUpdateRequestExecutorProxyTests.cs index 51023d82385..9d32f4490ac 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/AutoUpdateRequestExecutorProxyTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/AutoUpdateRequestExecutorProxyTests.cs @@ -60,8 +60,18 @@ public async Task Ensure_Executor_Is_Correctly_Swapped_When_Evicted() // act IRequestExecutor a = proxy.InnerExecutor; resolver.EvictRequestExecutor(); - await Task.Delay(100); + + var i = 0; IRequestExecutor b = proxy.InnerExecutor; + while (ReferenceEquals(a, b)) + { + await Task.Delay(100); + b = proxy.InnerExecutor; + if (i++ > 10) + { + break; + } + } // assert Assert.NotSame(a, b); diff --git a/src/HotChocolate/Core/test/Execution.Tests/CodeFirstTests.cs b/src/HotChocolate/Core/test/Execution.Tests/CodeFirstTests.cs index 9c9c0c7d977..e42c2661a84 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/CodeFirstTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/CodeFirstTests.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using HotChocolate.Execution; using HotChocolate.Resolvers; @@ -43,6 +45,22 @@ public async Task ExecuteOneFieldQueryWithMethod() result.MatchSnapshot(); } + [Fact] + public async Task ExecuteOneFieldQueryWithQuery() + { + // arrange + var schema = Schema.Create( + c => c.RegisterType()); + + // act + IExecutionResult result = + await schema.MakeExecutable().ExecuteAsync("{ query }"); + + // assert + Assert.Null(result.Errors); + result.MatchSnapshot(); + } + [Fact] public async Task ExecuteWithUnionType() { @@ -51,13 +69,16 @@ public async Task ExecuteWithUnionType() // act IExecutionResult result = - await schema.MakeExecutable().ExecuteAsync( - @"{ - fooOrBar { - ... on Bar { nameBar } - ... on Foo { nameFoo } + await schema.MakeExecutable() + .ExecuteAsync( + @" + { + fooOrBar { + ... on Bar { nameBar } + ... on Foo { nameFoo } + } } - }"); + "); // assert Assert.Null(result.Errors); @@ -263,6 +284,11 @@ public string GetTest() return "Hello World!"; } + public IExecutable GetQuery() + { + return MockQuery.From("foo", "bar"); + } + public string TestProp => "Hello World!"; } @@ -285,6 +311,7 @@ public class QueryTypeWithMethod { descriptor.Name("Query"); descriptor.Field(t => t.GetTest()).Name("test"); + descriptor.Field(t => t.GetQuery()).Name("query"); } } @@ -434,5 +461,32 @@ public class DogType .Type>(); } } + + public class MockQuery : IExecutable + { + private readonly IReadOnlyList _list; + + private MockQuery(IEnumerable list) + { + _list = list.ToArray(); + } + + async ValueTask IExecutable.ExecuteAsync(CancellationToken cancellationToken) + { + return await ExecuteAsync(cancellationToken); + } + + public ValueTask> ExecuteAsync(CancellationToken cancellationToken) + { + return new ValueTask>(_list); + } + + public string Print() + { + return _list.ToString(); + } + + public static MockQuery From(params T[] items) => new MockQuery(items); + } } } diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/ArgumentCoercionTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/ArgumentCoercionTests.cs new file mode 100644 index 00000000000..db889fccd06 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/ArgumentCoercionTests.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Snapshooter.Xunit; +using Xunit; + +#nullable enable + +namespace HotChocolate.Execution.Integration.Spec +{ + public class ArgumentCoercionTests + { + [Fact] + public async Task Pass_In_Null_To_NonNullArgument_With_DefaultValue() + { + // arrange + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync("{ sayHello(name: null) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Pass_In_Nothing_To_NonNullArgument_With_DefaultValue() + { + // arrange + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync("{ sayHello }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Pass_In_Nothing_To_NonNullArgument_With_DefaultValue_By_Variable() + { + // arrange + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "query ($a: String!) { sayHello(name: $a) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Pass_In_Null_To_NonNullArgument_With_DefaultValue_By_Variable() + { + // arrange + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType() + .BuildRequestExecutorAsync(); + + var variables = new Dictionary { { "a", null } }; + + // act + IExecutionResult result = await executor.ExecuteAsync( + "query ($a: String!) { sayHello(name: $a) }", + variables); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Pass_In_Sydney_To_NonNullArgument_With_DefaultValue_By_Variable() + { + // arrange + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType() + .BuildRequestExecutorAsync(); + + var variables = new Dictionary { { "a", "Sydney" } }; + + // act + IExecutionResult result = await executor.ExecuteAsync( + "query ($a: String!) { sayHello(name: $a) }", + variables); + + // assert + result.ToJson().MatchSnapshot(); + } + + public class Query + { + public string SayHello(string name = "Michael") => $"Hello {name}."; + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Nothing_To_NonNullArgument_With_DefaultValue.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Nothing_To_NonNullArgument_With_DefaultValue.snap new file mode 100644 index 00000000000..1ab07123ac8 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Nothing_To_NonNullArgument_With_DefaultValue.snap @@ -0,0 +1,5 @@ +{ + "data": { + "sayHello": "Hello Michael." + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Nothing_To_NonNullArgument_With_DefaultValue_By_Variable.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Nothing_To_NonNullArgument_With_DefaultValue_By_Variable.snap new file mode 100644 index 00000000000..210e6174b3d --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Nothing_To_NonNullArgument_With_DefaultValue_By_Variable.snap @@ -0,0 +1,17 @@ +{ + "errors": [ + { + "message": "Variable \u0060a\u0060 is required.", + "locations": [ + { + "line": 1, + "column": 8 + } + ], + "extensions": { + "code": "EXEC_NON_NULL_VIOLATION", + "variable": "a" + } + } + ] +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap new file mode 100644 index 00000000000..5df7530226d --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap @@ -0,0 +1,19 @@ +{ + "errors": [ + { + "message": "Detected a non-null violation in argument \u0060name\u0060.", + "locations": [ + { + "line": 1, + "column": 12 + } + ], + "extensions": { + "responseName": "sayHello", + "errorPath": [ + "name" + ] + } + } + ] +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue_By_Variable.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue_By_Variable.snap new file mode 100644 index 00000000000..210e6174b3d --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue_By_Variable.snap @@ -0,0 +1,17 @@ +{ + "errors": [ + { + "message": "Variable \u0060a\u0060 is required.", + "locations": [ + { + "line": 1, + "column": 8 + } + ], + "extensions": { + "code": "EXEC_NON_NULL_VIOLATION", + "variable": "a" + } + } + ] +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Sydney_To_NonNullArgument_With_DefaultValue_By_Variable.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Sydney_To_NonNullArgument_With_DefaultValue_By_Variable.snap new file mode 100644 index 00000000000..14db1ef5fa0 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Sydney_To_NonNullArgument_With_DefaultValue_By_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "sayHello": "Hello Sydney." + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Field_Based_Optimizers.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Field_Based_Optimizers.snap deleted file mode 100644 index b768114f5bc..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Field_Based_Optimizers.snap +++ /dev/null @@ -1,18 +0,0 @@ -{ - ... on Query { - root { - ... on Foo { - bar { - ... on Bar { - text - baz @_internal { - ... on Baz { - text @_internal - } - } - } - } - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited.snap deleted file mode 100644 index 455eeecf475..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited.snap +++ /dev/null @@ -1,16 +0,0 @@ -query foo($v: Boolean) { - ... on Query { - hero(episode: EMPIRE) { - ... on Human { - name @include(if: $v) - id - height @include(if: $v) - } - ... on Droid { - name @include(if: $v) - id - height @include(if: $v) - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited_2.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited_2.snap deleted file mode 100644 index 2683f5d8d1d..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited_2.snap +++ /dev/null @@ -1,16 +0,0 @@ -query foo($v: Boolean, $q: Boolean) { - ... on Query { - hero(episode: EMPIRE) { - ... on Human { - name @include(if: $q) - id - height @include(if: $v) - } - ... on Droid { - name @include(if: $q) - id - height @include(if: $v) - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited_3.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited_3.snap deleted file mode 100644 index 65e23a43199..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Object_Field_Visibility_Is_Correctly_Inherited_3.snap +++ /dev/null @@ -1,12 +0,0 @@ -query foo($v: Boolean, $q: Boolean) { - ... on Query { - hero(episode: EMPIRE) @include(if: $v) { - ... on Human { - name @include(if: $q) - } - ... on Droid { - name @include(if: $q) - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Prepare_Fragment_Definition.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Prepare_Fragment_Definition.snap deleted file mode 100644 index bc679f1ab1d..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Prepare_Fragment_Definition.snap +++ /dev/null @@ -1,14 +0,0 @@ -{ - ... on Query { - hero(episode: EMPIRE) { - ... on Human { - name - homePlanet - } - ... on Droid { - name - primaryFunction - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Prepare_Inline_Fragment.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Prepare_Inline_Fragment.snap deleted file mode 100644 index bc679f1ab1d..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Prepare_Inline_Fragment.snap +++ /dev/null @@ -1,14 +0,0 @@ -{ - ... on Query { - hero(episode: EMPIRE) { - ... on Human { - name - homePlanet - } - ... on Droid { - name - primaryFunction - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Reuse_Selection.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Reuse_Selection.snap deleted file mode 100644 index 5f48a964030..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/OperationCompilerTests.Reuse_Selection.snap +++ /dev/null @@ -1,36 +0,0 @@ -query Hero($episode: Episode, $withFriends: Boolean!) { - ... on Query { - hero(episode: $episode) { - ... on Human { - name - friends @include(if: $withFriends) { - ... on CharacterConnection { - nodes @include(if: $withFriends) { - ... on Human { - id @include(if: $withFriends) - } - ... on Droid { - id @include(if: $withFriends) - } - } - } - } - } - ... on Droid { - name - friends @include(if: $withFriends) { - ... on CharacterConnection { - nodes @include(if: $withFriends) { - ... on Human { - id @include(if: $withFriends) - } - ... on Droid { - id @include(if: $withFriends) - } - } - } - } - } - } - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/ResultHelperTests.BuildResult_SimpleResultSet_SnapshotMatches.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/ResultHelperTests.BuildResult_SimpleResultSet_SnapshotMatches.snap deleted file mode 100644 index 769cd361886..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/ResultHelperTests.BuildResult_SimpleResultSet_SnapshotMatches.snap +++ /dev/null @@ -1,5 +0,0 @@ -{ - "data": { - "abc": "def" - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_ReviewInput_Variable_With_Dictionary.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_ReviewInput_Variable_With_Dictionary.snap deleted file mode 100644 index dd91f5e3fe1..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_ReviewInput_Variable_With_Dictionary.snap +++ /dev/null @@ -1 +0,0 @@ -{ stars: 5 } diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_ReviewInput_Variable_With_Review_Object.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_ReviewInput_Variable_With_Review_Object.snap deleted file mode 100644 index a729e82ec41..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_ReviewInput_Variable_With_Review_Object.snap +++ /dev/null @@ -1 +0,0 @@ -{ stars: 5, commentary: null } diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_String_Variable_With_Default_Where_Plain_Value_Is_Provided.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_String_Variable_With_Default_Where_Plain_Value_Is_Provided.snap deleted file mode 100644 index 5f4269fe6dd..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Coerce_Nullable_String_Variable_With_Default_Where_Plain_Value_Is_Provided.snap +++ /dev/null @@ -1 +0,0 @@ -"xyz" diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Input_Field_Has_Different_Properties_Than_Defined.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Input_Field_Has_Different_Properties_Than_Defined.snap deleted file mode 100644 index c9550aabfd2..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Input_Field_Has_Different_Properties_Than_Defined.snap +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "Message": "Variable `abc` got an invalid value.", - "Code": "EXEC_INVALID_TYPE", - "Path": null, - "Locations": null, - "Extensions": { - "code": "EXEC_INVALID_TYPE", - "variable": "abc" - }, - "Exception": null - } -] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_PlainValue_Is_Null_On_Non_Null_Variable.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_PlainValue_Is_Null_On_Non_Null_Variable.snap deleted file mode 100644 index ce5cb5dc04b..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_PlainValue_Is_Null_On_Non_Null_Variable.snap +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "Message": "Variable `abc` is required.", - "Code": "EXEC_NON_NULL_VIOLATION", - "Path": null, - "Locations": null, - "Extensions": { - "code": "EXEC_NON_NULL_VIOLATION", - "variable": "abc" - }, - "Exception": null - } -] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_PlainValue_Type_Does_Not_Match_Variable_Type.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_PlainValue_Type_Does_Not_Match_Variable_Type.snap deleted file mode 100644 index c9550aabfd2..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_PlainValue_Type_Does_Not_Match_Variable_Type.snap +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "Message": "Variable `abc` got an invalid value.", - "Code": "EXEC_INVALID_TYPE", - "Path": null, - "Locations": null, - "Extensions": { - "code": "EXEC_INVALID_TYPE", - "variable": "abc" - }, - "Exception": null - } -] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Value_Is_Null_On_Non_Null_Variable.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Value_Is_Null_On_Non_Null_Variable.snap deleted file mode 100644 index ce5cb5dc04b..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Value_Is_Null_On_Non_Null_Variable.snap +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "Message": "Variable `abc` is required.", - "Code": "EXEC_NON_NULL_VIOLATION", - "Path": null, - "Locations": null, - "Extensions": { - "code": "EXEC_NON_NULL_VIOLATION", - "variable": "abc" - }, - "Exception": null - } -] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Value_Type_Does_Not_Match_Variable_Type.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Value_Type_Does_Not_Match_Variable_Type.snap deleted file mode 100644 index c9550aabfd2..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Error_When_Value_Type_Does_Not_Match_Variable_Type.snap +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "Message": "Variable `abc` got an invalid value.", - "Code": "EXEC_INVALID_TYPE", - "Path": null, - "Locations": null, - "Extensions": { - "code": "EXEC_INVALID_TYPE", - "variable": "abc" - }, - "Exception": null - } -] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Variable_Type_Is_Not_An_Input_Type.snap b/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Variable_Type_Is_Not_An_Input_Type.snap deleted file mode 100644 index 9edc6374ead..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Utilities/__snapshots__/VariableCoercionHelperTests.Variable_Type_Is_Not_An_Input_Type.snap +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "Message": "Variable `abc` is not an input type.", - "Code": "EXEC_NON_NULL_VIOLATION", - "Path": null, - "Locations": null, - "Extensions": { - "code": "EXEC_NON_NULL_VIOLATION", - "variable": "abc", - "type": "Human" - }, - "Exception": null - } -] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/CodeFirstTests.ExecuteOneFieldQueryWithQuery.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/CodeFirstTests.ExecuteOneFieldQueryWithQuery.snap new file mode 100644 index 00000000000..f9bb2f97588 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/CodeFirstTests.ExecuteOneFieldQueryWithQuery.snap @@ -0,0 +1,14 @@ +{ + "Label": null, + "Path": null, + "Data": { + "query": [ + "foo", + "bar" + ] + }, + "Errors": null, + "Extensions": null, + "ContextData": null, + "HasNext": null +} diff --git a/src/HotChocolate/Core/test/Types.Tests/Internal/ExtendedTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Internal/ExtendedTypeTests.cs index 169e2c6bc85..050b70a47e8 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Internal/ExtendedTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Internal/ExtendedTypeTests.cs @@ -301,6 +301,7 @@ public void IsEqual_Object_Byte_String_False() [InlineData(typeof(IEnumerable), "IEnumerable", "String")] [InlineData(typeof(IReadOnlyCollection), "IReadOnlyCollection", "String")] [InlineData(typeof(IReadOnlyList), "IReadOnlyList", "String")] + [InlineData(typeof(IExecutable), "IExecutable", "String")] [InlineData(typeof(string[]), "[String]", "String")] [InlineData( typeof(Task>), @@ -328,6 +329,7 @@ public void SupportedListTypes(Type type, string listTypeName, string elementTyp [InlineData(typeof(CustomStringList2))] [InlineData(typeof(ImmutableArray))] [InlineData(typeof(IEnumerable))] + [InlineData(typeof(IExecutable))] [InlineData(typeof(Task>))] [InlineData(typeof(ValueTask>))] [Theory] @@ -345,10 +347,10 @@ public void ChangeNullability_From_ElementType(Type listType) } [Fact] - public void NullableOptionalNullableString() + public void NullableOptionalNullableString() { // arrange - MethodInfo member = + MethodInfo member = typeof(Nullability).GetMethod(nameof(Nullability.NullableOptionalNullableString))!; // act @@ -359,10 +361,10 @@ public void NullableOptionalNullableString() } [Fact] - public void OptionalNullableOptionalNullableString() + public void OptionalNullableOptionalNullableString() { // arrange - MethodInfo member = + MethodInfo member = typeof(Nullability) .GetMethod(nameof(Nullability.OptionalNullableOptionalNullableString))!; @@ -373,6 +375,20 @@ public void OptionalNullableOptionalNullableString() Assert.Equal("Optional>!", type.ToString()); } + [Fact] + public void From_IExecutableScalar() + { + // arrange + // act + ExtendedType dict = ExtendedType.FromType( + typeof(IExecutable), + _cache); + + // assert + Assert.True(dict.IsList); + Assert.True(dict.IsArrayOrList); + } + private class CustomStringList1 : List { @@ -394,11 +410,11 @@ private class CustomStringList3 #nullable enable public class Nullability - { - public Nullable> NullableOptionalNullableString() => + { + public Nullable> NullableOptionalNullableString() => throw new NotImplementedException(); - public Optional>> OptionalNullableOptionalNullableString() => + public Optional>> OptionalNullableOptionalNullableString() => throw new NotImplementedException(); } diff --git a/src/HotChocolate/Core/test/Types.Tests/Internal/TypeInfoTests.cs b/src/HotChocolate/Core/test/Types.Tests/Internal/TypeInfoTests.cs index 6505d463c90..04a27c2e1ba 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Internal/TypeInfoTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Internal/TypeInfoTests.cs @@ -60,6 +60,9 @@ public class TypeInfoTests [InlineData(typeof(IAsyncEnumerable), "[String]")] [InlineData(typeof(IEnumerable), "[String]")] [InlineData(typeof(IQueryable), "[String]")] + [InlineData(typeof(IExecutable), "[String]")] + [InlineData(typeof(IExecutable), "[String!]")] + [InlineData(typeof(IExecutable), "[String]")] [Theory] public void CreateTypeInfoFromRuntimeType( Type clrType, @@ -84,6 +87,7 @@ public class TypeInfoTests [InlineData(typeof(IEnumerable), "[String]")] [InlineData(typeof(IReadOnlyCollection), "[String]")] [InlineData(typeof(IReadOnlyList), "[String]")] + [InlineData(typeof(IExecutable), "[String]")] [InlineData(typeof(string[]), "[String]")] [Theory] public void SupportedListTypes(Type clrType, string expectedTypeName) @@ -152,6 +156,61 @@ public void NullableListNonNullElement() Assert.Equal("[String!]", typeInfo.CreateType(new StringType()).Print()); } + [Fact] + public void NonNullQueryNonNullElement() + { + // arrange + MethodInfo methodInfo = + typeof(Nullability).GetMethod(nameof(Nullability.NonNullQueryNonNullElement)); + + // act + var typeInfo = TypeInfo.Create(_typeInspector.GetReturnType(methodInfo!), _cache); + + // assert + Assert.Equal("[String!]!", typeInfo.CreateType(new StringType()).Print()); + } + + [Fact] + public void NonNullQueryNullableElement() + { + // arrange + MethodInfo methodInfo = + typeof(Nullability).GetMethod(nameof(Nullability.NonNullQueryNullableElement)); + + // act + var typeInfo = TypeInfo.Create(_typeInspector.GetReturnType(methodInfo!), _cache); + + // assert + Assert.Equal("[String]!", typeInfo.CreateType(new StringType()).Print()); + } + + [Fact] + public void NullableQueryNullableElement() + { + // arrange + MethodInfo methodInfo = + typeof(Nullability).GetMethod(nameof(Nullability.NullableQueryNullableElement)); + + // act + var typeInfo = TypeInfo.Create(_typeInspector.GetReturnType(methodInfo!), _cache); + + // assert + Assert.Equal("[String]", typeInfo.CreateType(new StringType()).Print()); + } + + [Fact] + public void NullableQueryNonNullElement() + { + // arrange + MethodInfo methodInfo = + typeof(Nullability).GetMethod(nameof(Nullability.NullableQueryNonNullElement)); + + // act + var typeInfo = TypeInfo.Create(_typeInspector.GetReturnType(methodInfo!), _cache); + + // assert + Assert.Equal("[String!]", typeInfo.CreateType(new StringType()).Print()); + } [Fact] public void NonNullCollectionNonNullElement() { @@ -538,6 +597,14 @@ public class Nullability public ICollection? NullableCollectionNonNullElement() => default; + public IExecutable NonNullQueryNonNullElement() => default!; + + public IExecutable NonNullQueryNullableElement() => default!; + + public IExecutable? NullableQueryNullableElement() => default; + + public IExecutable? NullableQueryNonNullElement() => default; + public string[] NonNullArrayNonNullElement() => default!; public string?[] NonNullArrayNullableElement() => default!; @@ -549,7 +616,7 @@ public class Nullability public List?>? NestedList() => default; public Optional OptionalNullableString() => default; - + public Nullable> NullableOptionalNullableString() => default; } diff --git a/src/HotChocolate/Core/test/Validation.Tests/DocumentValidatorTests.cs b/src/HotChocolate/Core/test/Validation.Tests/DocumentValidatorTests.cs index 40e528094a7..9f58cec5431 100644 --- a/src/HotChocolate/Core/test/Validation.Tests/DocumentValidatorTests.cs +++ b/src/HotChocolate/Core/test/Validation.Tests/DocumentValidatorTests.cs @@ -166,7 +166,7 @@ ... missingRequiredArg } ", t => Assert.Equal( - $"The argument `nonNullBooleanArg` is required.", + "The argument `nonNullBooleanArg` is required.", t.Message)); } diff --git a/src/HotChocolate/Core/test/Validation.Tests/Types/QueryType.cs b/src/HotChocolate/Core/test/Validation.Tests/Types/QueryType.cs index 824b412448b..42b684776cf 100644 --- a/src/HotChocolate/Core/test/Validation.Tests/Types/QueryType.cs +++ b/src/HotChocolate/Core/test/Validation.Tests/Types/QueryType.cs @@ -35,6 +35,10 @@ protected override void Configure(IObjectTypeDescriptor descriptor) descriptor.Field(t => t.GetDogOrHuman()) .Type(); + + descriptor.Field("nonNull") + .Argument("a", a => a.Type>().DefaultValue("abc")) + .Resolve("foo"); } } } diff --git a/src/HotChocolate/Core/test/Validation.Tests/ValuesOfCorrectTypeRuleTests.cs b/src/HotChocolate/Core/test/Validation.Tests/ValuesOfCorrectTypeRuleTests.cs index 0ae7921af17..9cee76d1404 100644 --- a/src/HotChocolate/Core/test/Validation.Tests/ValuesOfCorrectTypeRuleTests.cs +++ b/src/HotChocolate/Core/test/Validation.Tests/ValuesOfCorrectTypeRuleTests.cs @@ -62,7 +62,7 @@ query queryWithListInput() "The specified argument value does not" + " match the argument type.", t.Message); - Assert.Equal("[Boolean!]", t.Extensions["locationType"]); + Assert.Equal("[Boolean!]", t.Extensions!["locationType"]); Assert.Equal("booleanListArg", t.Extensions["argument"]); }); } @@ -81,7 +81,7 @@ query queryWithListInput() "The specified argument value does not" + " match the argument type.", t.Message); - Assert.Equal("[Boolean!]", t.Extensions["locationType"]); + Assert.Equal("[Boolean!]", t.Extensions!["locationType"]); Assert.Equal("booleanListArg", t.Extensions["argument"]); }); } @@ -668,6 +668,17 @@ public void BadWrongCasingEnumIntoEnum() "); } + [Fact(Skip = "This really should be caught! " + + "=> Spec issue http://spec.graphql.org/draft/#sel-JALTHHDHFFCAACEQl_M")] + public void BadNullToString() + { + ExpectErrors(@" + query InvalidItem { + nonNull(a: null) + } + "); + } + [Fact] public void GoodListValue() { diff --git a/src/HotChocolate/Core/test/Validation.Tests/__snapshots__/ValuesOfCorrectTypeRuleTests.BadNullToString.snap b/src/HotChocolate/Core/test/Validation.Tests/__snapshots__/ValuesOfCorrectTypeRuleTests.BadNullToString.snap new file mode 100644 index 00000000000..e3b9502de6d --- /dev/null +++ b/src/HotChocolate/Core/test/Validation.Tests/__snapshots__/ValuesOfCorrectTypeRuleTests.BadNullToString.snap @@ -0,0 +1,24 @@ +[ + { + "Message": "The specified argument value does not match the argument type.", + "Code": null, + "Path": { + "Parent": null, + "Depth": 0, + "Name": "nonNull" + }, + "Locations": [ + { + "Line": 3, + "Column": 32 + } + ], + "Extensions": { + "argument": "a", + "argumentValue": "null", + "locationType": "String!", + "specifiedBy": "http://spec.graphql.org/June2018/#sec-Values-of-Correct-Type" + }, + "Exception": null + } +] diff --git a/src/HotChocolate/Data/src/Data/Filters/Convention/FilterConvention.cs b/src/HotChocolate/Data/src/Data/Filters/Convention/FilterConvention.cs index 0b067043a64..97fb89b0b56 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Convention/FilterConvention.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Convention/FilterConvention.cs @@ -200,8 +200,8 @@ public NameString GetOperationName(int operation) public bool TryGetHandler( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition, + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition, [NotNullWhen(true)] out IFilterFieldHandler? handler) { foreach (IFilterFieldHandler filterFieldHandler in _provider.FieldHandlers) diff --git a/src/HotChocolate/Data/src/Data/Filters/Convention/IFilterConvention.cs b/src/HotChocolate/Data/src/Data/Filters/Convention/IFilterConvention.cs index 93996531357..f0222c6f930 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Convention/IFilterConvention.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Convention/IFilterConvention.cs @@ -114,8 +114,8 @@ public interface IFilterConvention : IConvention bool TryGetHandler( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition, + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition, [NotNullWhen(true)] out IFilterFieldHandler? handler); /// diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Boolean/QueryableBooleanOperationHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Boolean/QueryableBooleanOperationHandler.cs index c5ca4954ffc..5d15e1ca1bb 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Boolean/QueryableBooleanOperationHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Boolean/QueryableBooleanOperationHandler.cs @@ -9,8 +9,8 @@ public abstract class QueryableBooleanOperationHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is BooleanOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Comparable/QueryableComparableOperationHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Comparable/QueryableComparableOperationHandler.cs index f889e19dad0..aec6664dbf5 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Comparable/QueryableComparableOperationHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Comparable/QueryableComparableOperationHandler.cs @@ -22,8 +22,8 @@ public abstract class QueryableComparableOperationHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IComparableOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumEqualsHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumEqualsHandler.cs index 881f7e9e8bb..dbd35017384 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumEqualsHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumEqualsHandler.cs @@ -14,8 +14,8 @@ public class QueryableEnumEqualsHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IEnumOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumInHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumInHandler.cs index d103e5ba6e7..59a161b67c1 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumInHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumInHandler.cs @@ -14,8 +14,8 @@ public class QueryableEnumInHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IEnumOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotEqualsHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotEqualsHandler.cs index 9c79f6536fe..2f38bf785d4 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotEqualsHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotEqualsHandler.cs @@ -14,8 +14,8 @@ public class QueryableEnumNotEqualsHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IEnumOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotInHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotInHandler.cs index 3056a63df17..743525ee2d4 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotInHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/Enum/QueryableEnumNotInHandler.cs @@ -14,8 +14,8 @@ public class QueryableEnumNotInHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IEnumOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListAnyOperationHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListAnyOperationHandler.cs index 2530e6aff24..a9e7723db09 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListAnyOperationHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListAnyOperationHandler.cs @@ -20,8 +20,8 @@ public class QueryableListAnyOperationHandler public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IListFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListOperationHandlerBase.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListOperationHandlerBase.cs index 9b096c20a8e..99eb1f24fc7 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListOperationHandlerBase.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/List/QueryableListOperationHandlerBase.cs @@ -15,8 +15,8 @@ public abstract class QueryableListOperationHandlerBase public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is IListFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDataOperationHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDataOperationHandler.cs index 666c79f7a36..dfff74c1d1b 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDataOperationHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDataOperationHandler.cs @@ -8,8 +8,8 @@ public class QueryableDataOperationHandler { public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return fieldDefinition is FilterOperationFieldDefinition def && def.Id == DefaultOperations.Data; diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDefaultFieldHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDefaultFieldHandler.cs index 3d26be213f5..cc89337fcc0 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDefaultFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/QueryableDefaultFieldHandler.cs @@ -13,8 +13,8 @@ public class QueryableDefaultFieldHandler { public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) => + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) => !(fieldDefinition is FilterOperationFieldDefinition) && fieldDefinition.Member is not null; diff --git a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/String/QueryableStringOperationHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/String/QueryableStringOperationHandler.cs index 6987d12f3ed..5bce85b1b19 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/String/QueryableStringOperationHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Expressions/Handlers/String/QueryableStringOperationHandler.cs @@ -8,8 +8,8 @@ public abstract class QueryableStringOperationHandler : QueryableOperationHandle public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return context.Type is StringOperationFilterInput && fieldDefinition is FilterOperationFieldDefinition operationField && diff --git a/src/HotChocolate/Data/src/Data/Filters/FilterFieldDefinition.cs b/src/HotChocolate/Data/src/Data/Filters/FilterFieldDefinition.cs index 97d552757a6..bb15b3ec9c4 100644 --- a/src/HotChocolate/Data/src/Data/Filters/FilterFieldDefinition.cs +++ b/src/HotChocolate/Data/src/Data/Filters/FilterFieldDefinition.cs @@ -7,6 +7,7 @@ namespace HotChocolate.Data.Filters public class FilterFieldDefinition : InputFieldDefinition , IHasScope + , IFilterFieldDefinition { public MemberInfo? Member { get; set; } diff --git a/src/HotChocolate/Data/src/Data/Filters/FilterInputTypeDefinition.cs b/src/HotChocolate/Data/src/Data/Filters/FilterInputTypeDefinition.cs index 572421ec4f2..a91ef23b84d 100644 --- a/src/HotChocolate/Data/src/Data/Filters/FilterInputTypeDefinition.cs +++ b/src/HotChocolate/Data/src/Data/Filters/FilterInputTypeDefinition.cs @@ -7,6 +7,7 @@ namespace HotChocolate.Data.Filters public class FilterInputTypeDefinition : InputObjectTypeDefinition , IHasScope + , IFilterInputTypeDefinition { public Type? EntityType { get; set; } diff --git a/src/HotChocolate/Data/src/Data/Filters/IFilterFieldDefinition.cs b/src/HotChocolate/Data/src/Data/Filters/IFilterFieldDefinition.cs new file mode 100644 index 00000000000..1e3265002a9 --- /dev/null +++ b/src/HotChocolate/Data/src/Data/Filters/IFilterFieldDefinition.cs @@ -0,0 +1,13 @@ +using System.Reflection; + +namespace HotChocolate.Data.Filters +{ + public interface IFilterFieldDefinition + { + MemberInfo? Member { get; } + + IFilterFieldHandler? Handler { get; } + + string? Scope { get; } + } +} diff --git a/src/HotChocolate/Data/src/Data/Filters/IFilterInputTypeDefinition.cs b/src/HotChocolate/Data/src/Data/Filters/IFilterInputTypeDefinition.cs new file mode 100644 index 00000000000..c272f4ce5c7 --- /dev/null +++ b/src/HotChocolate/Data/src/Data/Filters/IFilterInputTypeDefinition.cs @@ -0,0 +1,15 @@ +using System; + +namespace HotChocolate.Data.Filters +{ + public interface IFilterInputTypeDefinition + { + Type? EntityType { get; } + + string? Scope { get; } + + bool UseOr { get; } + + bool UseAnd { get; } + } +} diff --git a/src/HotChocolate/Data/src/Data/Filters/Visitor/FilterFieldHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Visitor/FilterFieldHandler.cs index 696337aab49..77744a6b9f1 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Visitor/FilterFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Visitor/FilterFieldHandler.cs @@ -34,7 +34,7 @@ public abstract class FilterFieldHandler /// public abstract bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition); + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition); } } diff --git a/src/HotChocolate/Data/src/Data/Filters/Visitor/IFilterFieldHandler.cs b/src/HotChocolate/Data/src/Data/Filters/Visitor/IFilterFieldHandler.cs index 08a1d3a1a5e..510a8571c62 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Visitor/IFilterFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Visitor/IFilterFieldHandler.cs @@ -6,7 +6,7 @@ public interface IFilterFieldHandler { bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition); + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition); } } diff --git a/src/HotChocolate/Data/src/Data/Sorting/Convention/ISortConvention.cs b/src/HotChocolate/Data/src/Data/Sorting/Convention/ISortConvention.cs index 3f2d6f52620..b8ab6bbd648 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Convention/ISortConvention.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Convention/ISortConvention.cs @@ -128,8 +128,8 @@ public interface ISortConvention : IConvention bool TryGetFieldHandler( ITypeDiscoveryContext context, - SortInputTypeDefinition typeDefinition, - SortFieldDefinition fieldDefinition, + ISortInputTypeDefinition typeDefinition, + ISortFieldDefinition fieldDefinition, [NotNullWhen(true)] out ISortFieldHandler? handler); bool TryGetOperationHandler( diff --git a/src/HotChocolate/Data/src/Data/Sorting/Convention/SortConvention.cs b/src/HotChocolate/Data/src/Data/Sorting/Convention/SortConvention.cs index 7762445cf69..0d9b7572a6a 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Convention/SortConvention.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Convention/SortConvention.cs @@ -246,8 +246,8 @@ public NameString GetOperationName(int operation) public bool TryGetFieldHandler( ITypeDiscoveryContext context, - SortInputTypeDefinition typeDefinition, - SortFieldDefinition fieldDefinition, + ISortInputTypeDefinition typeDefinition, + ISortFieldDefinition fieldDefinition, [NotNullWhen(true)] out ISortFieldHandler? handler) { foreach (ISortFieldHandler sortFieldHandler in _provider.FieldHandlers) diff --git a/src/HotChocolate/Data/src/Data/Sorting/Expressions/Handlers/QueryableDefaultFieldHandler.cs b/src/HotChocolate/Data/src/Data/Sorting/Expressions/Handlers/QueryableDefaultFieldHandler.cs index 4b408445016..09fc27d2dab 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Expressions/Handlers/QueryableDefaultFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Expressions/Handlers/QueryableDefaultFieldHandler.cs @@ -13,8 +13,8 @@ public class QueryableDefaultFieldHandler { public override bool CanHandle( ITypeDiscoveryContext context, - SortInputTypeDefinition typeDefinition, - SortFieldDefinition fieldDefinition) => + ISortInputTypeDefinition typeDefinition, + ISortFieldDefinition fieldDefinition) => fieldDefinition.Member is not null; public override bool TryHandleEnter( diff --git a/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs b/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs index 3b1634fc293..187b6c92cad 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortObjectFieldDescriptorExtensions.cs @@ -178,10 +178,10 @@ public static class SortObjectFieldDescriptorExtensions LazyTypeConfigurationBuilder .New() .Definition(definition) - .Configure((context, defintion) => + .Configure((context, def) => CompileMiddleware( context, - definition, + def, argumentTypeReference, placeholder, scope)) @@ -193,7 +193,7 @@ public static class SortObjectFieldDescriptorExtensions LazyTypeConfigurationBuilder .New() .Definition(definition) - .Configure((context, defintion) => + .Configure((context, _) => argumentDefinition.Name = context.GetSortConvention(scope).GetArgumentName()) .On(ApplyConfigurationOn.Naming) diff --git a/src/HotChocolate/Data/src/Data/Sorting/ISortFieldDefinition.cs b/src/HotChocolate/Data/src/Data/Sorting/ISortFieldDefinition.cs new file mode 100644 index 00000000000..51fb5d34e5c --- /dev/null +++ b/src/HotChocolate/Data/src/Data/Sorting/ISortFieldDefinition.cs @@ -0,0 +1,13 @@ +using System.Reflection; +using HotChocolate.Types; + +namespace HotChocolate.Data.Sorting +{ + public interface ISortFieldDefinition + : IHasScope + { + public MemberInfo? Member { get; } + + public ISortFieldHandler? Handler { get; } + } +} diff --git a/src/HotChocolate/Data/src/Data/Sorting/ISortInputTypeDefinition.cs b/src/HotChocolate/Data/src/Data/Sorting/ISortInputTypeDefinition.cs new file mode 100644 index 00000000000..93b0ee24d12 --- /dev/null +++ b/src/HotChocolate/Data/src/Data/Sorting/ISortInputTypeDefinition.cs @@ -0,0 +1,12 @@ +using System; +using HotChocolate.Types; +using HotChocolate.Types.Descriptors.Definitions; + +namespace HotChocolate.Data.Sorting +{ + public interface ISortInputTypeDefinition + : IHasScope + { + Type? EntityType { get; } + } +} diff --git a/src/HotChocolate/Data/src/Data/Sorting/SortFieldDefinition.cs b/src/HotChocolate/Data/src/Data/Sorting/SortFieldDefinition.cs index a09f25acb57..ea5de0df841 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/SortFieldDefinition.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/SortFieldDefinition.cs @@ -1,12 +1,11 @@ using System.Reflection; -using HotChocolate.Types; using HotChocolate.Types.Descriptors.Definitions; namespace HotChocolate.Data.Sorting { public class SortFieldDefinition : InputFieldDefinition - , IHasScope + , ISortFieldDefinition { public MemberInfo? Member { get; set; } diff --git a/src/HotChocolate/Data/src/Data/Sorting/SortInputTypeDefinition.cs b/src/HotChocolate/Data/src/Data/Sorting/SortInputTypeDefinition.cs index aabb936f7f5..003cae7054e 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/SortInputTypeDefinition.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/SortInputTypeDefinition.cs @@ -1,12 +1,11 @@ using System; -using HotChocolate.Types; using HotChocolate.Types.Descriptors.Definitions; namespace HotChocolate.Data.Sorting { public class SortInputTypeDefinition : InputObjectTypeDefinition - , IHasScope + , ISortInputTypeDefinition { public Type? EntityType { get; set; } diff --git a/src/HotChocolate/Data/src/Data/Sorting/Visitor/ISortFieldHandler.cs b/src/HotChocolate/Data/src/Data/Sorting/Visitor/ISortFieldHandler.cs index 3ad460e20ba..3f1da2b7573 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Visitor/ISortFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Visitor/ISortFieldHandler.cs @@ -6,7 +6,7 @@ public interface ISortFieldHandler { bool CanHandle( ITypeDiscoveryContext context, - SortInputTypeDefinition typeDefinition, - SortFieldDefinition fieldDefinition); + ISortInputTypeDefinition typeDefinition, + ISortFieldDefinition fieldDefinition); } } diff --git a/src/HotChocolate/Data/src/Data/Sorting/Visitor/SortFieldHandler.cs b/src/HotChocolate/Data/src/Data/Sorting/Visitor/SortFieldHandler.cs index 3c8e1bade77..1179ba8b452 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Visitor/SortFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Visitor/SortFieldHandler.cs @@ -34,7 +34,7 @@ public abstract class SortFieldHandler /// public abstract bool CanHandle( ITypeDiscoveryContext context, - SortInputTypeDefinition typeDefinition, - SortFieldDefinition fieldDefinition); + ISortInputTypeDefinition typeDefinition, + ISortFieldDefinition fieldDefinition); } } diff --git a/src/HotChocolate/Data/test/Data.Filters.Tests/Expression/QueryableFilterVisitorMethodTests.cs b/src/HotChocolate/Data/test/Data.Filters.Tests/Expression/QueryableFilterVisitorMethodTests.cs index 42a0dde4ab3..6f1b84c21e2 100644 --- a/src/HotChocolate/Data/test/Data.Filters.Tests/Expression/QueryableFilterVisitorMethodTests.cs +++ b/src/HotChocolate/Data/test/Data.Filters.Tests/Expression/QueryableFilterVisitorMethodTests.cs @@ -19,8 +19,8 @@ public class QueryableFilterVisitorMethodTests public void Create_MethodSimple_Expression() { // arrange - IValueNode? value = Syntax.ParseValueLiteral("{ simple: { eq:\"a\" }}"); - ExecutorBuilder? tester = CreateProviderTester( + IValueNode value = Syntax.ParseValueLiteral("{ simple: { eq:\"a\" }}"); + ExecutorBuilder tester = CreateProviderTester( new FooFilterType(), new FilterConvention( x => @@ -36,7 +36,7 @@ public void Create_MethodSimple_Expression() })); // act - Func? func = tester.Build(value); + Func func = tester.Build(value); // assert var a = new Foo { Bar = "a" }; @@ -50,7 +50,7 @@ public void Create_MethodSimple_Expression() public void Create_MethodComplex_Expression() { // arrange - ExecutorBuilder? tester = CreateProviderTester( + ExecutorBuilder tester = CreateProviderTester( new FooFilterType(), new FilterConvention( x => @@ -65,14 +65,14 @@ public void Create_MethodComplex_Expression() .AddDefaultFieldHandlers())); })); - IValueNode? valueTrue = Utf8GraphQLParser.Syntax.ParseValueLiteral( + IValueNode valueTrue = Utf8GraphQLParser.Syntax.ParseValueLiteral( "{ complex: {parameter:\"a\", eq:\"a\" }}"); - IValueNode? valueFalse = Utf8GraphQLParser.Syntax.ParseValueLiteral( + IValueNode valueFalse = Utf8GraphQLParser.Syntax.ParseValueLiteral( "{ complex: {parameter:\"a\", eq:\"b\" }}"); // act - Func? funcTrue = tester.Build(valueTrue); - Func? funcFalse = tester.Build(valueFalse); + Func funcTrue = tester.Build(valueTrue); + Func funcFalse = tester.Build(valueFalse); // assert var a = new Foo(); @@ -95,8 +95,8 @@ public QueryableSimpleMethodTest(ITypeInspector typeInspector) public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { return fieldDefinition is FilterOperationFieldDefinition { Id: 155 }; } @@ -105,7 +105,7 @@ public QueryableSimpleMethodTest(ITypeInspector typeInspector) QueryableFilterContext context, IFilterField field, ObjectFieldNode node, - out ISyntaxVisitorAction? action) + out ISyntaxVisitorAction action) { if (node.Value.IsNull()) { @@ -136,12 +136,12 @@ private class QueryableComplexMethodTest { private static readonly MethodInfo Method = typeof(Foo).GetMethod(nameof(Foo.Complex))!; - private IExtendedType? _extendedType; + private IExtendedType _extendedType = null!; public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) { _extendedType ??= context.TypeInspector.GetReturnType(Method); @@ -152,7 +152,7 @@ private class QueryableComplexMethodTest QueryableFilterContext context, IFilterField field, ObjectFieldNode node, - out ISyntaxVisitorAction? action) + out ISyntaxVisitorAction action) { if (node.Value.IsNull()) { @@ -172,7 +172,7 @@ private class QueryableComplexMethodTest if (field.Type is StringOperationFilterInput operationType && node.Value is ObjectValueNode objectValue) { - IValueNode? parameterNode = null; + IValueNode parameterNode = null!; for (var i = 0; i < objectValue.Fields.Count; i++) { @@ -187,7 +187,7 @@ private class QueryableComplexMethodTest throw new InvalidOperationException(); } - object? value = + object value = operationType.Fields["parameter"].Type.ParseLiteral(parameterNode); Expression nestedProperty = Expression.Call( @@ -201,7 +201,7 @@ private class QueryableComplexMethodTest return true; } - action = null; + action = null!; return false; } } diff --git a/src/HotChocolate/Data/test/Data.Filters.Tests/Mock/MatchAnyFieldHandler.cs b/src/HotChocolate/Data/test/Data.Filters.Tests/Mock/MatchAnyFieldHandler.cs index fe3cfeb60d6..74060d08fff 100644 --- a/src/HotChocolate/Data/test/Data.Filters.Tests/Mock/MatchAnyFieldHandler.cs +++ b/src/HotChocolate/Data/test/Data.Filters.Tests/Mock/MatchAnyFieldHandler.cs @@ -9,7 +9,7 @@ public class MatchAnyQueryableFieldHandler { public override bool CanHandle( ITypeDiscoveryContext context, - FilterInputTypeDefinition typeDefinition, - FilterFieldDefinition fieldDefinition) => true; + IFilterInputTypeDefinition typeDefinition, + IFilterFieldDefinition fieldDefinition) => true; } } diff --git a/src/HotChocolate/Data/test/Data.Sorting.Tests/Mock/MatchAnyFieldHandler.cs b/src/HotChocolate/Data/test/Data.Sorting.Tests/Mock/MatchAnyFieldHandler.cs index 8c8fa5b952a..5ba3b3d914b 100644 --- a/src/HotChocolate/Data/test/Data.Sorting.Tests/Mock/MatchAnyFieldHandler.cs +++ b/src/HotChocolate/Data/test/Data.Sorting.Tests/Mock/MatchAnyFieldHandler.cs @@ -1,4 +1,3 @@ -using System.Linq.Expressions; using HotChocolate.Configuration; using HotChocolate.Data.Sorting.Expressions; @@ -9,7 +8,7 @@ public class MatchAnyQueryableFieldHandler { public override bool CanHandle( ITypeDiscoveryContext context, - SortInputTypeDefinition typeDefinition, - SortFieldDefinition fieldDefinition) => true; + ISortInputTypeDefinition typeDefinition, + ISortFieldDefinition fieldDefinition) => true; } } diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/HotChocolate.Stitching.Tests.csproj b/src/HotChocolate/Stitching/test/Stitching.Tests/HotChocolate.Stitching.Tests.csproj index cbe7f13b171..55a8be3407b 100644 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/HotChocolate.Stitching.Tests.csproj +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/HotChocolate.Stitching.Tests.csproj @@ -7,6 +7,7 @@ + diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/BaseTests.cs b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/BaseTests.cs index fababe77a97..275f6b03f25 100644 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/BaseTests.cs +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/BaseTests.cs @@ -9,6 +9,7 @@ using HotChocolate.Resolvers; using HotChocolate.Types; using HotChocolate.Language; +using HotChocolate.Types.Descriptors.Definitions; namespace HotChocolate.Stitching.Integration { @@ -521,7 +522,7 @@ public async Task AutoMerge_Execute_RenameScalar() .ModifyRequestOptions(o => o.IncludeExceptionDetails = true) .BuildRequestExecutorAsync(); - var variables = new Dictionary + var variables = new Dictionary { { "v", new FloatValueNode(1.2f) } }; @@ -581,9 +582,9 @@ public async Task AutoMerge_Execute_IntField() .AddRemoteSchema(Context.CustomerSchema) .AddTypeExtensionsFromString( @"extend type Customer { - int: Int! + int: Int! @delegate( - schema: ""contract"", + schema: ""contract"", path: ""int(i:$fields:someInt)"") }") .ModifyRequestOptions(o => o.IncludeExceptionDetails = true) @@ -616,9 +617,9 @@ public async Task AutoMerge_Execute_GuidField() .AddRemoteSchema(Context.CustomerSchema) .AddTypeExtensionsFromString( @"extend type Customer { - guid: Uuid! + guid: Uuid! @delegate( - schema: ""contract"", + schema: ""contract"", path: ""guid(guid:$fields:someGuid)"") }") .ModifyRequestOptions(o => o.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/RewriteTypesTests.cs b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/RewriteTypesTests.cs new file mode 100644 index 00000000000..1b6568f4e73 --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/RewriteTypesTests.cs @@ -0,0 +1,132 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using ChilliCream.Testing; +using HotChocolate.Execution; +using HotChocolate.Language; +using HotChocolate.Types; +using HotChocolate.Utilities; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace HotChocolate.Stitching.Integration +{ + public class RewriteTypesTests : IClassFixture + { + public RewriteTypesTests(StitchingTestContext context) + { + Context = context; + } + + protected StitchingTestContext Context { get; } + + [Fact] + public async Task AutoMerge_Schema() + { + // arrange + IHttpClientFactory httpClientFactory = + Context.CreateDefaultRemoteSchemas(); + + // act + IServiceProvider services = + new ServiceCollection() + .AddSingleton(httpClientFactory) + .AddGraphQL() + .AddRemoteSchemaFromString( + "AdvisorClient", + FileResource.Open("AdvisorClient.graphql")) + .AddRemoteSchemaFromString( + "ContractClient", + FileResource.Open("ContractClient.graphql")) + .AddRemoteSchemaFromString( + "DocumentClient", + FileResource.Open("DocumentClient.graphql")) + .AddType(new IntType("PaginationAmount")) + .AddType(new IntType()) + .AddMergedDocumentRewriter(d => + { + var rewriter = new DocumentRewriter(); + return (DocumentNode)rewriter.Rewrite(d, null); + }) + .RewriteType("ContractClient", "Int", "PaginationAmount") + .AddGraphQL("AdvisorClient") + .AddType(new IntType("PaginationAmount")) + .AddType(new IntType()) + .AddGraphQL("ContractClient") + .AddType(new IntType("PaginationAmount")) + .AddType(new IntType()) + .AddGraphQL("DocumentClient") + .AddType(new IntType("PaginationAmount")) + .AddType(new IntType()) + .Services + .BuildServiceProvider(); + + // assert + IRequestExecutor contractExecutor = + await services.GetRequestExecutorAsync("ContractClient"); + + ObjectType type = contractExecutor.Schema.GetType("ZmaContract"); + + Assert.Equal( + "Int", + type.Fields["accountTransactions"].Arguments["first"].Type.NamedType().Name.Value); + + IRequestExecutor executor = + await services.GetRequestExecutorAsync(); + + type = executor.Schema.GetType("ZmaContract"); + + Assert.Equal( + "PaginationAmount", + type.Fields["accountTransactions"].Arguments["first"].Type.NamedType().Name.Value); + } + + private class DocumentRewriter : SchemaSyntaxRewriter + { + protected override FieldDefinitionNode RewriteFieldDefinition( + FieldDefinitionNode node, + object context) + { + if(node.Type.NamedType().Name.Value.EndsWith("Connection") && + node.Arguments.Any(t => t.Name.Value.EqualsOrdinal("first") && + t.Type.NamedType().Name.Value.EqualsOrdinal("Int"))) + { + var arguments = node.Arguments.ToList(); + + InputValueDefinitionNode first = + arguments.First(t => t.Name.Value.EqualsOrdinal("first")); + + InputValueDefinitionNode last = + arguments.First(t => t.Name.Value.EqualsOrdinal("last")); + + arguments[arguments.IndexOf(first)] = + first.WithType(RewriteType(first.Type, "PaginationAmount")); + + arguments[arguments.IndexOf(last)] = + first.WithType(RewriteType(first.Type, "PaginationAmount")); + + node = node.WithArguments(arguments); + } + + return base.RewriteFieldDefinition(node, context); + } + + private static ITypeNode RewriteType(ITypeNode type, NameString name) + { + if (type is NonNullTypeNode nonNullType) + { + return new NonNullTypeNode( + (INullableTypeNode)RewriteType(nonNullType.Type, name)); + } + + if (type is ListTypeNode listType) + { + return new ListTypeNode(RewriteType(listType.Type, name)); + } + + return new NamedTypeNode(name); + } + } + } +} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/AdvisorClient.graphql b/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/AdvisorClient.graphql new file mode 100644 index 00000000000..fb69580c4fb --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/AdvisorClient.graphql @@ -0,0 +1,116 @@ +schema { + query: Query +} + +type Query { + contractAdvisor(advisorRequest: AdvisorRequestInput! = null): Advisor! + contractAdvisors(advisorRequests: [AdvisorRequestInput!]! = null): [Advisor!]! + digisAdvisor(contractNumber: String! = null): Advisor! + evContractAdvisor(contractId: String! = null): Advisor! + fzContractAdvisor(contractId: String! = null): Advisor! + mortgageAdvisor(mortgageNumber: String = null): Advisor! + nvsAdvisor(contractNumber: String! = null): Advisor! + swissLifeGeneralInfo: SwissLifeGeneralInfo! + threeAContractAdvisor(contractId: String! = null): Advisor! + zmaContractAdvisor(contractId: String! = null): Advisor! +} + +type SwissLifeAdvisor implements Advisor { + agency: GeneralAgency + email: String + firstName: String! + id: ID! + "Translated" + jobDescription: String + lastName: String! + phoneNumber: String + pictureUrl: String +} + +type BrokerCompany implements Advisor { + companyName: String! @deprecated(reason: "Use Name instead.") + email: String + id: ID! + name: BrokerCompanyName! + phoneNumber: String + pictureUrl: String + url: String +} + +type GeneralAgency implements Advisor { + address: Address @deprecated(reason: "Not used on Front") + agencyName: String! + email: String + id: ID! + phoneNumber: String + pictureUrl: String + url: String +} + +type SwissLifeGeneralInfo implements Advisor { + email: String + id: ID! + name: String! + phoneNumber: String + phoneNumbers: [SwissLifePhoneNumber]! + pictureUrl: String +} + +enum ApplyPolicy { + BEFORE_RESOLVER + AFTER_RESOLVER +} + +interface Advisor { + email: String + id: ID! + phoneNumber: String + pictureUrl: String +} + +type SwissLifePhoneNumber { + "Translated" + label: String! + phoneNumber: String! +} + +enum TranslatableLanguage { + NOTSET + DE + FR + IT + EN +} + +type BrokerCompanyName { + additionalName: String + displayName: String! + name: String! +} + +input AdvisorRequestInput { + sourceRelevantId: String! = null + sourceSystem: SourceSystem! = null +} + +type Address { + city: String! + country: String! + streetName: String! + streetNumber: String! + zipCode: String! +} + +enum SourceSystem { + HSSAG + DIGIS + NVS + NVS_FZP + EV + LPZZMA + LPZFZ + LPZ +} + +directive @authorize("Defines when when the resolver shall be executed.By default the resolver is executed after the policy has determined that the current user is allowed to access the field." apply: ApplyPolicy! = BEFORE_RESOLVER "The name of the authorization policy that determines access to the annotated resource." policy: String = null "Roles that are allowed to access the annotated resource." roles: [String!] = null) repeatable on SCHEMA | OBJECT | FIELD_DEFINITION + diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/ContractClient.graphql b/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/ContractClient.graphql new file mode 100644 index 00000000000..0221f7ec0fb --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/ContractClient.graphql @@ -0,0 +1,1914 @@ +schema { + query: Query + mutation: Mutation + subscription: Subscription +} + +type Query { + contract("The contract's Id" id: ID! = null): Contract + customerContract: CustomerContract! + node(id: ID! = null): Node +} + +type Mutation { + confirmThreeAPaymentSimulation(confirmations: [ThreeAPaymentConfirmationInput!]! = null): [ThreeAPaymentConfirmation!]! + portfolioCheck(contractId: ID! = null): Boolean! + requestSurrenderValueDocument(request: SurrenderValueDocument! = null): RequestSurrenderValueDocumentInfo + setPaperless(paperless: [PaperlessInput!]! = null supressNotification: Boolean = null): [PaperlessResult!]! +} + +type ZmaContract implements Contract & Investment & Paperless & Node { + accounts: [ZmaAccount]! + accounttransactions(after: String = null before: String = null filter: [FilterInfoInput] = null first: Int = null last: Int = null sortBy: String = null sortDirection: SortDirection = null): ZmaAccountTransactionConnection @deprecated(reason: "Deprecated use accountTransaction instead") + accountTransactions(after: String = null before: String = null first: Int = null last: Int = null order_by: ZmaAccountTransactionSort = null where: ZmaAccountTransactionFilter = null): ZmaAccountTransactionConnection + active: Boolean! + begin: DateTime! + category: ContractCategory! + contractId: String! + currency: String! + customer: ZmaCustomer! + depositsFromContractStart: Float + id: ID! + investmentStrategy: InvestmentStrategy! + investmentTheme: InvestmentTheme + latestContractPerformanceYear: ZmaContractPerformance! + number: String! + paperlessEnabled: Boolean + payoutPeriodicity: PaymentPeriodicity! + payoutPeriodicPayment: Float + payoutStartMonth: DateTime + portfolio: ZmaPortfolio + portfolioName: String + powerOfAttorney: ZmaPowerOfAttorney + product: ZmaProduct! + productName: String! + sourceSystemName: String + totalBalance: Float! + uniqueId: String + youthAccountDateOfBirth: DateTime + youthAccountFirstName: String + youthAccountGender: Gender + youthAccountLastName: String +} + +interface PensionFundPolicy { + active: Boolean! + additionalLumpSumDeathBenefitMarried: Float! + additionalLumpSumDeathBenefitMarriedAccident: Float! + additionalLumpSumDeathBenefitNotMarried: Float! + additionalLumpSumDeathBenefitNotMarriedAccident: Float! + begin: DateTime! + benefits: PensionFundPolicyBenefits! + category: ContractCategory! + childrensBenefitIvPension: Float! + childrensBenefitIvPensionAccident: Float! + childrensBenefitIvWaitingPeriod: Int! + childrensBenefitPension: Float! + contributionEmployee: Float! + contributionEmployer: Float! + contributionExonerationDelay: Int! + contributionTotal: Float! + conversionRateMandatory: Float! + conversionRateSupplementary: Float! + currency: String! + deathBenefit: Float! + degreeOfDisability: Float! + endDate: DateTime + "PolicyId" + id: ID! + insuranceGroup: String + interestRateMandatory: Float! + interestRateSupplementary: Float! + iVPension: Float! + iVPensionAccident: Float! + iVWaitingPeriod: Int! + levelOfEmployment: Float! + monthlyRetirementPension: Float! + number: String! + nvsPortalInsuredPersonId: String! + orphansBenefit: Float! + orphansBenefitAccident: Float! + paperlessEnabled: Boolean + pensionPlan: PensionPlan + policyId: String! + productName: String! + purchaseEarlyWithdrawalForHomeOwnership: Float! + purchasePensionFund: Float! + purchaseTotalPossible: Float! + purchaseWithdrawalDivorce: Float! + reportedSalary: Float! + retirementCapital: Float! + retirementPension: Float! + retirementSavings: Float! + sourceSystemName: String + startDateEmployment: DateTime + status: PensionFundPolicyStatus! + totalBalance: Float! + unmarriedPartnersPension: Float! + unmarriedPartnersPensionAccident: Float! + withdrawalCapital: Float! +} + +interface Address { + additional: String + careOf: String + city: String + company: String + department: String + firstName: String + id: String + lastName: String + postOfficeBox: String + salutation: String + street: String + zipCode: String +} + +type XPlanPolicy implements Contract & PensionFundPolicy & Paperless & Node { + active: Boolean! + additionalLumpSumDeathBenefitMarried: Float! + additionalLumpSumDeathBenefitMarriedAccident: Float! + additionalLumpSumDeathBenefitNotMarried: Float! + additionalLumpSumDeathBenefitNotMarriedAccident: Float! + begin: DateTime! + benefits: PensionFundPolicyBenefits! + category: ContractCategory! + childrensBenefitIvPension: Float! + childrensBenefitIvPensionAccident: Float! + childrensBenefitIvWaitingPeriod: Int! + childrensBenefitPension: Float! + contact: XPlanContactInfo + contract: XPlanContract! + contractId: String! + contributionEmployee: Float! + contributionEmployer: Float! + contributionExonerationDelay: Int! + contributionTotal: Float! + conversionRateMandatory: Float! + conversionRateSupplementary: Float! + currency: String! + currentFundBalance: XPlanPremiumFundBalance + deathBenefit: Float! + degreeOfDisability: Float! + domicileAddress: XPlanAddress + endDate: DateTime + fundDevelopments: [XPlanFundDevelopment!] + "PolicyId" + id: ID! + insuranceGroup: String + interestRateMandatory: Float! + interestRateSupplementary: Float! + iVPension: Float! + iVPensionAccident: Float! + iVWaitingPeriod: Int! + levelOfEmployment: Float! + maxRetirementCapital: Float! + monthlyRetirementPension: Float! + number: String! + nvsPortalInsuredPersonId: String! + orphansBenefit: Float! + orphansBenefitAccident: Float! + paperlessEnabled: Boolean + pensionPlan: PensionPlan + policyId: String! + productName: String! + projectedRetirement: XPlanProjectedRetirement! + purchaseEarlyWithdrawalForHomeOwnership: Float! + purchasePensionFund: Float! + purchaseTotalPossible: Float! + purchaseWithdrawalDivorce: Float! + reportedSalary: Float! + retirementCapital: Float! + retirementDevelopment: [XPlanRetirementDevelopment!]! + retirementPension: Float! + retirementSavings: Float! + "Null for inactive policies" + simulationParameters: PensionFundSimulationParameters + sourceSystemName: String + startDateEmployment: DateTime + status: PensionFundPolicyStatus! + totalBalance: Float! + transactions(after: String = null before: String = null first: Int = null last: Int = null order_by: XPlanTransactionSort = null where: XPlanPensionFundTransactionFilterInput = null): XPlanTransactionConnection + unmarriedPartnersPension: Float! + unmarriedPartnersPensionAccident: Float! + withdrawalCapital: Float! +} + +type PensionFundFzPolicy implements Contract & Paperless & Node { + active: Boolean! + ahvNumber: String + benefits: PensionFundFzPolicyBenefits! + birthDate: DateTime! + category: ContractCategory! + contractId: String! + currency: String! + displayName: String! + domicileAddress: XPlanAddress + fimCustomerId: String! + firstName: String! + "PolicyId" + id: ID! + interestRate: Float! + lastName: String! + number: String! + nvsPortalInsuredPersonId: String! + paperlessEnabled: Boolean + planType: PensionFundFzPolicyPlanType! + "Translated" + productName: String! + retirementAge: Int! + retirementDate: DateTime! + "Null for inactive policies" + simulationParameters: PensionFundSimulationParameters + startDate: DateTime! + status: PensionFundPolicyStatus! + totalBalance: Float! + transactions(after: String = null before: String = null first: Int = null last: Int = null order_by: PensionFundFzPolicyTransactionSort = null where: PensionFundFzPolicyTransactionFilter = null): PensionFundFzPolicyTransactionConnection + validFrom: DateTime! +} + +type DigisPolicy implements Contract & PensionFundPolicy & Paperless & Node { + active: Boolean! + additionalLumpSumDeathBenefitMarried: Float! + additionalLumpSumDeathBenefitMarriedAccident: Float! + additionalLumpSumDeathBenefitNotMarried: Float! + additionalLumpSumDeathBenefitNotMarriedAccident: Float! + begin: DateTime! + benefits: PensionFundPolicyBenefits! + category: ContractCategory! + childrensBenefitIvPension: Float! + childrensBenefitIvPensionAccident: Float! + childrensBenefitIvWaitingPeriod: Int! + childrensBenefitPension: Float! + contract: DigisContract! + contractId: String! + contributionEmployee: Float! + contributionEmployer: Float! + contributionExonerationDelay: Int! + contributionTotal: Float! + conversionRateMandatory: Float! + conversionRateSupplementary: Float! + currency: String! + customer: DigisCustomer! + deathAfterRetirement: DeathAfterRetirement + deathBenefit: Float! + degreeOfDisability: Float! + endDate: DateTime + "PolicyId" + id: ID! + insuranceGroup: String + interestRateMandatory: Float! + interestRateSupplementary: Float! + iVPension: Float! + iVPensionAccident: Float! + iVWaitingPeriod: Int! + lastCalcDate: DateTime! + levelOfEmployment: Float! + monthlyRetirementPension: Float! + number: String! + nvsPortalInsuredPersonId: String! + orphansBenefit: Float! + orphansBenefitAccident: Float! + paperlessEnabled: Boolean + pensionPlan: PensionPlan + policyId: String! + policyTypeId: String + productName: String! + projectedRetirement: DigisProjectedRetirement + purchaseEarlyWithdrawalForHomeOwnership: Float! + purchasePensionFund: Float! + purchaseTotalPossible: Float! + purchaseWithdrawalDivorce: Float! + reportedSalary: Float! + retirementCapital: Float! + retirementDevelopment: [DigisRetirementDevelopment!]! + retirementPension: Float! + retirementSavings: Float! + sourceSystemName: String + startDateEmployment: DateTime + status: PensionFundPolicyStatus! + statusId: Int! + totalBalance: Float! + transactionId: Int! + transactions(after: String = null before: String = null first: Int = null last: Int = null order_by: DigisTransactionSort = null where: DigisPensionFundTransactionFilterInput = null): DigisTransactionConnection + unmarriedPartnersPension: Float! + unmarriedPartnersPensionAccident: Float! + withdrawalCapital: Float! +} + +type EvContract implements Contract & ThreeA & ThreeASimulation & Paperless & Node { + accountContractId: String @deprecated(reason: "No longer required") + accountId: ID + active: Boolean! + annualPremium: Float! + annualPremiumSimulation: Float @deprecated(reason: "Use threeASimulation.annualPremiumSimulation instead") + begin: DateTime! + beneficiaryClause: String! + benefitsUponSurvivalDisclaimer: String @deprecated(reason: "use benefitUponSurvival.Disclaimer instead") + benefitUponSurvival: EvBenefitUponSurvival + bVGInsured: Boolean + bvgMismatch: Boolean! + category: ContractCategory! + contractEndDate: DateTime + contractId: String! + currency: String! + currencySimulation: String @deprecated(reason: "Use threeASimulation.currencySimulation instead") + customer: EvCustomer! + customers: [EvCustomer!]! + hasAccount: Boolean! + hasMonetaryAsset: Boolean! + id: ID! + "Translatable" + insuranceType: String! + "Translated" + insuranceTypeName: String! + isThreeA: Boolean! + maximumAmount: Float + maximumAmountSimulation: Float @deprecated(reason: "Use threeASimulation.maximumAmountSimulation instead") + maximumAnnualSimulation: Float @deprecated(reason: "Use threeASimulation.maximumAnnualSimulation instead") + minimumAmountSimulation: Float @deprecated(reason: "Use threeASimulation.minimumAmountSimulation instead") + number: String! + paperlessEnabled: Boolean + partnerId: String! + paymentPossibleSimulation: Boolean! @deprecated(reason: "Use threeASimulation.paymentPossibleSimulation instead") + "Translatable" + pillar: String + portfolio: EvPortfolio + portfolioCode: String + portfolioName: String + premium: EvPremium + premiumInvoiceProcessing: Boolean! + premiuminvoices(after: String = null before: String = null first: Int = null last: Int = null order_by: EvPremiumInvoiceSort = null where: EvPremiumInvoiceFilter = null): EvPremiumInvoiceConnection + productGroup: String! + "Translatable" + productId: String + productName: String! + productNameCode: String + retirementStart: DateTime + sourceSystemName: String + surrenderValue: EvSurrenderValue + surrenderValueDocumentPartnerId: String! + tariffs: [EvTariff!]! + threeAPaymentInfo(amount: Float! = null): ThreeASimulationPaymentInfo @deprecated(reason: "Use threeASimulation.threeAPaymentInfo instead") + threeASimulation: EvContractThreeASimulationType! + totalBalance: Float! + uniqueId: String +} + +type EvAccount implements Contract & Node { + accountBalance: Float! + accountCategory: EvAccountCategory! + accountdevelopments: [EvAccountDevelopment!]! + accounttransactions(after: String = null before: String = null filter: [FilterInfoInput] = null first: Int = null last: Int = null sortBy: String = null sortDirection: SortDirection = null): EvAccountTransactionConnection @deprecated(reason: "Deprecated use accountTransaction instead") + accountTransactions(after: String = null before: String = null first: Int = null last: Int = null order_by: EvAccountTransactionSort = null where: EvAccountTransactionFilter = null): EvAccountTransactionConnection + "Translatable" + accountType: String + active: Boolean! + availableProducts: [EvAccountProduct!]! + category: ContractCategory! + connectedContracts: [EvContract!]! + contractId: String! + currency: String! + id: ID! + number: String! + partner: EvPartner! + productName: String! + referenceNumber: String + totalBalance: Float! +} + +type MortgageContract implements Contract & Node { + active: Boolean! + amountTotal: Float! + begin: DateTime + category: ContractCategory! + collaterals: [MortgageCollateral]! + contractId: String! + contractNumber: String! + currency: String! + id: ID! + interests: [MortgageInterest]! + mortgages(order_by: MortgageSort = null): [Mortgage]! + number: String! + object: MortgageObject! + productName: String! + sourceSystemName: String + stakeholders: [MortgageStakeholder]! + totalBalance: Float! + uniqueId: String + yearlyInterestTotal: Float! +} + +type ThreeAStartContract implements Contract & Node & Paperless & ThreeA & ThreeASimulation { + accounts: [ThreeAStartFzAccount!]! + accounttransactions(after: String = null before: String = null filter: [FilterInfoInput] = null first: Int = null last: Int = null sortBy: String = null sortDirection: SortDirection = null): ThreeAStartFzTransactionConnection @deprecated(reason: "Deprecated use accountTransaction instead") + accountTransactions(after: String = null before: String = null first: Int = null last: Int = null order_by: ThreeAStartFzTransactionSort = null where: ThreeAStartFzTransactionFilter = null): ThreeAStartFzTransactionConnection + active: Boolean! + annualPremium: Float! + annualPremiumSimulation: Float @deprecated(reason: "use threeASimulation.annualPremiumSimulation instead.") + availableAccountTypes: [ThreeAStartFzAccountType]! + begin: DateTime! + bvgMismatch: Boolean! + category: ContractCategory! + closeCode: Int + commissionDiscount: Float + contractChangeDate: DateTime + contractdevelopments: [ThreeAStartFzDevelopment!]! + contractId: String! + contractProductNumber: String + currency: String! + currencySimulation: String @deprecated(reason: "use threeASimulation.currencySimulation instead.") + customer: ThreeAStartFzCustomer! + "ThreeAStartContractId" + id: ID! + investmentShare: Float + latestCalculationDate: DateTime + maximumAmount: Float + maximumAmountSimulation: Float @deprecated(reason: "Use threeASimulation.maximumAmountSimulation instead") + maximumAnnualSimulation: Float @deprecated(reason: "use threeASimulation.maximumAnnualSimulation instead.") + minimumAmountSimulation: Float @deprecated(reason: "use threeASimulation.minimumAmountSimulation instead.") + modelPortfolioNumber: String + number: String! + paperlessEnabled: Boolean + paymentPossibleSimulation: Boolean! @deprecated(reason: "Use threeASimulation.paymentPossibleSimulation instead") + portfolio: ThreeAStartFzPortfolio! + "Translatable" + productId: String + productName: String! + sourceSystemName: String + threeASimulation: ThreeAStartSimulationType! + totalBalance: Float! + uniqueId: String +} + +type FzContract implements Contract & Node & Paperless { + accounts: [ThreeAStartFzAccount!]! + accounttransactions(after: String = null before: String = null filter: [FilterInfoInput] = null first: Int = null last: Int = null sortBy: String = null sortDirection: SortDirection = null): ThreeAStartFzTransactionConnection @deprecated(reason: "Deprecated use accountTransaction instead") + accountTransactions(after: String = null before: String = null first: Int = null last: Int = null order_by: ThreeAStartFzTransactionSort = null where: ThreeAStartFzTransactionFilter = null): ThreeAStartFzTransactionConnection + active: Boolean! + availableAccountTypes: [ThreeAStartFzAccountType]! + begin: DateTime! + category: ContractCategory! + closeCode: Int + commissionDiscount: Float + contractChangeDate: DateTime + contractdevelopments: [ThreeAStartFzDevelopment!]! + contractId: String! + contractProductNumber: String + currency: String! + customer: ThreeAStartFzCustomer! + "FzContractId" + id: ID! + investmentShare: Float + modelPortfolioNumber: String + number: String! + paperlessEnabled: Boolean + portfolio: ThreeAStartFzPortfolio! + "Translatable" + productId: String + productName: String! + sourceSystemName: String + totalBalance: Float! + uniqueId: String +} + +type NotImplementedContract implements Contract & Node { + active: Boolean! + category: ContractCategory! + contractId: String! + currency: String! + id: ID! + number: String! + nvsPortalInsuredPersonId: String + productName: String! + showDocumentLink: Boolean! + sourceSystemName: String + totalBalance: Float! + uniqueId: String +} + +enum PensionFundPolicyStatus { + ACTIVE + INACTIVE + INACTIVEPAID + REVERSAL + PENSION +} + +"The node interface is implemented by entities that have a global unique identifier." +interface Node { + id: ID! +} + +type CustomerContract { + contracts(hiddenContracts: [String!] = null tag: [ContractTag] = null): [Contract!]! + "PortalCustomerId" + id: ID! + outline: ContractsOutline +} + +interface Contract { + active: Boolean! + category: ContractCategory! + contractId: String! + currency: String! + id: ID! + number: String! + productName: String! + totalBalance: Float! +} + +type PaperlessResult { + contract: Contract! + success: Boolean! +} + +input PaperlessInput { + contractId: ID! = null + enable: Boolean! = null +} + +input SurrenderValueDocument { + contractId: ID! = null + customerId: String = null + date: Date = null + partnerId: String! = null +} + +input ThreeAPaymentConfirmationInput { + contractId: ID! = null + payment: Float! = null +} + +type RequestSurrenderValueDocumentInfo { + jobId: Int! +} + +type ThreeAPaymentConfirmation { + contractId: ID! + payment: Float! +} + +type ZmaAccountTransaction implements Node { + accountBalance: Float! + accountTransactionAmount: Float! + accountType: ZmaAccountType! + accountTypeName: String! + bookingDate: DateTime! + contractId: String + currency: String! + iban: String + "AccountTransactionId" + id: ID! + marketPrice: Float! + narrativeText: String + securityNominal: Float! + transactionText: String + valueDate: DateTime! +} + +input ZmaAccountTransactionSort { + bookingDate: SortOperationKind = null + valueDate: SortOperationKind = null +} + +input ZmaAccountTransactionFilter { + accountType: ZmaAccountType = null + accountType_gt: ZmaAccountType = null + accountType_gte: ZmaAccountType = null + accountType_in: [ZmaAccountType!] = null + accountType_lt: ZmaAccountType = null + accountType_lte: ZmaAccountType = null + accountType_not: ZmaAccountType = null + accountType_not_gt: ZmaAccountType = null + accountType_not_gte: ZmaAccountType = null + accountType_not_in: [ZmaAccountType!] = null + accountType_not_lt: ZmaAccountType = null + accountType_not_lte: ZmaAccountType = null + AND: [ZmaAccountTransactionFilter!] = null + bookingDate: DateTime = null + bookingDate_gt: DateTime = null + bookingDate_gte: DateTime = null + bookingDate_in: [DateTime] = null + bookingDate_lt: DateTime = null + bookingDate_lte: DateTime = null + bookingDate_not: DateTime = null + bookingDate_not_gt: DateTime = null + bookingDate_not_gte: DateTime = null + bookingDate_not_in: [DateTime] = null + bookingDate_not_lt: DateTime = null + bookingDate_not_lte: DateTime = null + OR: [ZmaAccountTransactionFilter!] = null +} + +interface Investment { + investmentStrategy: InvestmentStrategy! + investmentTheme: InvestmentTheme +} + +interface Paperless { + paperlessEnabled: Boolean +} + +enum SortDirection { + ASCENDING + DESCENDING +} + +input FilterInfoInput { + equality: FilterEqualityOperator! = null + field: String! = null + logical: FilterLogicalOperator = null + value: String = null +} + +"The `DateTime` scalar represents an ISO-8601 compliant date time type." +scalar DateTime + +type ZmaCustomer implements Node { + beneficiaryAccountNumber: String + correspondenceAddress: ZmaAddress + customerId: String! + domicileAddress: ZmaAddress + firstName: String! + id: ID! + lastName: String! +} + +type ZmaAccount { + accountId: String + accountType: ZmaAccountType! + accountTypeName: String! + calculationDate: DateTime! + contractId: String + currency: String! + currentBalanceAccountCurrency: Float! + iban: String! + id: ID! + standingOrders: [ZmaStandingOrder]! +} + +type ZmaPortfolio { + calculationDate: DateTime + contractId: String + currency: String! + factSheetUrl: String + history: [ZmaPortfolioHistory!]! + id: ID! + portfolioId: String! + portfolioValueInBalanceSheetCurrency: Float + portfolioValueInPortfolioCurrency: Float! + positions: [ZmaPortfolioPosition!]! +} + +type ZmaProduct { + contractType: ZmaContractType! + id: ID! + investmentStrategy: String! + investmentTheme: String + productName: String! + productNumber: String! +} + +enum PaymentPeriodicity { + SINGLE + ANNUALY + SEMIANNUALY + QUARTERLY + MONTHLY +} + +type ZmaContractPerformance { + calculationType: ZmaContractPerformanceCalculation! + contractPerformanceId: String! + historicalPerformance: Float! + id: ID! + performanceDate: DateTime! + referenceCurrency: String! + zmaContractId: String +} + +"A connection to a list of items." +type ZmaAccountTransactionConnection { + "A list of edges." + edges: [ZmaAccountTransactionEdge!] + "A flattened list of the nodes." + nodes: [ZmaAccountTransaction] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +type ZmaPowerOfAttorney { + firstName: String! + id: ID! + lastName: String! + powerOfAttorneyId: String! +} + +enum ContractCategory { + UNDEFINED + PENSIONFUND + FZ + PERSONALPENSION + MORTGAGE + FZP +} + +enum InvestmentStrategy { + INCOME + BALANCED + GROWTH + EQUITY + CERTIFICATE +} + +enum InvestmentTheme { + GLOBAL + SWISSNESS + TRENDS + DIVIDEND + SWISSLIFE + SUSTAINABILITY +} + +enum Gender { + UNKNOWN + FEMALE + MALE +} + +type PensionFundPolicyBenefits { + childrensBenefitIvPension: PeriodicalValuesOfDouble! + childrensBenefitIvPensionAccident: PeriodicalValuesOfDouble! + childrensBenefitIvWaitingPeriod: Int! + childrensBenefitPension: PeriodicalValuesOfDouble! + "Contribution exoneration delay in months" + contributionExonerationDelay: Int! + iVPension: PeriodicalValuesOfDouble! + iVPensionAccident: PeriodicalValuesOfDouble! + iVWaitingPeriod: Int! + orphanPension: PeriodicalValuesOfDouble + orphanPensionPercent: Float! + orphansBenefit: PeriodicalValuesOfDouble! + orphansBenefitAccident: PeriodicalValuesOfDouble! + retirementPension: PeriodicalValuesOfDouble! + unmarriedPartnersPension: PeriodicalValuesOfDouble! + unmarriedPartnersPensionAccident: PeriodicalValuesOfDouble! + widowPension: PeriodicalValuesOfDouble + widowPensionPercent: Float! +} + +type XPlanTransaction implements Node { + amount: Float + bookingCode: String + bookingDate: DateTime! + "Translated" + bookingText: String! + bookingType: String + id: ID! + processId: String + transactionId: String! +} + +input XPlanTransactionSort { + bookingDate: SortOperationKind = null +} + +input XPlanPensionFundTransactionFilterInput { + amount: Float = null + amount_gt: Float = null + amount_gte: Float = null + amount_in: [Float] = null + amount_lt: Float = null + amount_lte: Float = null + amount_not: Float = null + amount_not_gt: Float = null + amount_not_gte: Float = null + amount_not_in: [Float] = null + amount_not_lt: Float = null + amount_not_lte: Float = null + AND: [XPlanPensionFundTransactionFilterInput!] = null + bookingDate: Date = null + bookingDate_gt: Date = null + bookingDate_gte: Date = null + bookingDate_in: [Date] = null + bookingDate_lt: Date = null + bookingDate_lte: Date = null + bookingDate_not: Date = null + bookingDate_not_gt: Date = null + bookingDate_not_gte: Date = null + bookingDate_not_in: [Date] = null + bookingDate_not_lt: Date = null + bookingDate_not_lte: Date = null + OR: [XPlanPensionFundTransactionFilterInput!] = null +} + +type PensionFundSimulationParameters { + contractSharedId: Uuid! + personSharedId: Uuid! + processId: String! +} + +type XPlanProjectedRetirement implements ProjectedRetirement { + isPossiblePrepensionDateInFuture: Boolean! + lastPossiblePurchaseDate: Date! + projectedAge: Int! + projectedDate: Date! + projectedInterestRate: Float! + projectedSavings: Decimal! +} + +type XPlanContract implements Node & PensionFundContract { + beginDate: DateTime! + contractNumber: String + endDate: DateTime + foundation: String + id: ID! + "Translated" + insuranceType: String! + productCode: String! + stakeHolder: String +} + +"A connection to a list of items." +type XPlanTransactionConnection { + "A list of edges." + edges: [XPlanTransactionEdge!] + "A flattened list of the nodes." + nodes: [XPlanTransaction] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +type XPlanRetirementDevelopment { + retirementCapital: Float! + retirementCapitalSupplementary: Float! + retirementDate: DateTime! + retirementPension: Float! + source: String! + transactions: [XPlanTransaction!]! +} + +type XPlanAddress implements Address { + additional: String + careOf: String + city: String + company: String + countryCode: Int + countryCodeNumeric: Int @deprecated(reason: "Use CountryCode instead") + department: String + firstName: String + id: String + lastName: String + postOfficeBox: String + "Translated" + salutation: String + street: String + street2: String @deprecated(reason: "Use Additional instead") + zipCode: String +} + +type PensionFundFzPolicyTransaction implements Node { + amount: Float! + "Translated" + bookingCode: String + bookingDate: DateTime! + id: ID! + processId: String + transactionId: String! +} + +input PensionFundFzPolicyTransactionSort { + bookingDate: SortOperationKind = null +} + +input PensionFundFzPolicyTransactionFilter { + AND: [PensionFundFzPolicyTransactionFilter!] = null + bookingDate: DateTime = null + bookingDate_gt: DateTime = null + bookingDate_gte: DateTime = null + bookingDate_in: [DateTime] = null + bookingDate_lt: DateTime = null + bookingDate_lte: DateTime = null + bookingDate_not: DateTime = null + bookingDate_not_gt: DateTime = null + bookingDate_not_gte: DateTime = null + bookingDate_not_in: [DateTime] = null + bookingDate_not_lt: DateTime = null + bookingDate_not_lte: DateTime = null + OR: [PensionFundFzPolicyTransactionFilter!] = null +} + +type PensionFundFzPolicyPlanType { + iV: Boolean! + planType: FzPolicyPlanType! + planTypeRaw: String! + relinquished: Boolean! + senior: Boolean! + tariffSpecification: Boolean! +} + +type PensionFundFzPolicyBenefits { + cumulatedExceeds: Float! + deathBenefit: Float! + iVCapital: Float! + retirementSavings: Float! + retirementSavingsProjected: Float! + totalDeathBenefit: Float! + totalRetirementSavings: Float! +} + +"A connection to a list of items." +type PensionFundFzPolicyTransactionConnection { + "A list of edges." + edges: [PensionFundFzPolicyTransactionEdge!] + "A flattened list of the nodes." + nodes: [PensionFundFzPolicyTransaction!] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +type DigisTransaction implements Node { + amount: Float + bookingCode: String + bookingDate: DateTime! + "Translated" + bookingText: String! + capital: Decimal! + capitalSupplementary: Decimal! + id: ID! + pension: Decimal! +} + +input DigisTransactionSort { + bookingDate: SortOperationKind = null +} + +input DigisPensionFundTransactionFilterInput { + amount: Float = null + amount_gt: Float = null + amount_gte: Float = null + amount_in: [Float] = null + amount_lt: Float = null + amount_lte: Float = null + amount_not: Float = null + amount_not_gt: Float = null + amount_not_gte: Float = null + amount_not_in: [Float] = null + amount_not_lt: Float = null + amount_not_lte: Float = null + AND: [DigisPensionFundTransactionFilterInput!] = null + bookingDate: DateTime = null + bookingDate_gt: DateTime = null + bookingDate_gte: DateTime = null + bookingDate_in: [DateTime] = null + bookingDate_lt: DateTime = null + bookingDate_lte: DateTime = null + bookingDate_not: DateTime = null + bookingDate_not_gt: DateTime = null + bookingDate_not_gte: DateTime = null + bookingDate_not_in: [DateTime] = null + bookingDate_not_lt: DateTime = null + bookingDate_not_lte: DateTime = null + OR: [DigisPensionFundTransactionFilterInput!] = null +} + +type DigisContract implements Node & PensionFundContract { + contractNumber: String + foundation: String + id: ID! + "Translated" + insuranceType: String! + productCode: String! + stakeHolder: String +} + +type DigisRetirementDevelopment implements RetirementDevelopment { + retirementAge: Int! + retirementCapital: Float! + retirementDate: DateTime! + retirementPension: Float! + transactions: [DigisTransaction!]! +} + +"A connection to a list of items." +type DigisTransactionConnection { + "A list of edges." + edges: [DigisTransactionEdge!] + "A flattened list of the nodes." + nodes: [DigisTransaction] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +type DigisProjectedRetirement implements ProjectedRetirement { + isPossiblePrepensionDateInFuture: Boolean! + lastPossiblePurchaseDate: Date! + projectedAge: Int! + projectedDate: Date! + projectedPension: Decimal! + projectedSavings: Decimal! +} + +type DigisCustomer { + ahvNumber: String + customerId: String + customerTypeId: Int! + dateOfBirth: DateTime! + degreeOfDisability: Decimal! + domicileAddress: DigisAddress + firstName: String + gender: String + governmentId: String + lastName: String + levelOfEmployment: Decimal! + nvsPortalInsuredPersonId: String + reportedSalary: Decimal! + sourceId: String + withdrawalCapital: Decimal! +} + +type EvPremiumInvoice { + balance: Float + bill: Float + contractId: String! + currency: String! + documentNumber: String! + dueDate: DateTime + "DocumentNumber" + id: ID! + invoiceNumber: String! + invoicePeriodEndDate: DateTime + invoicePeriodStartDate: DateTime + partnerId: Int! + premium: Float + settlementBlock: Boolean! + status: PremiumInvoiceStatus! + "Translated" + statusName: String +} + +input EvPremiumInvoiceSort { + dueDate: SortOperationKind = null +} + +input EvPremiumInvoiceFilter { + AND: [EvPremiumInvoiceFilter!] = null + dueDate: DateTime = null + dueDate_gt: DateTime = null + dueDate_gte: DateTime = null + dueDate_in: [DateTime] = null + dueDate_lt: DateTime = null + dueDate_lte: DateTime = null + dueDate_not: DateTime = null + dueDate_not_gt: DateTime = null + dueDate_not_gte: DateTime = null + dueDate_not_in: [DateTime] = null + dueDate_not_lt: DateTime = null + dueDate_not_lte: DateTime = null + OR: [EvPremiumInvoiceFilter!] = null +} + +interface ThreeA { + annualPremium: Float! + bvgMismatch: Boolean! + currency: String! + maximumAmount: Float +} + +interface ThreeASimulation { + annualPremiumSimulation: Float + currencySimulation: String + maximumAmountSimulation: Float + maximumAnnualSimulation: Float + minimumAmountSimulation: Float + paymentPossibleSimulation: Boolean! +} + +type EvCustomer implements Node { + correspondenceAddress: EvPartnerAddress + domicileAddress: EvPartnerAddress + firstName: String! + gender: Gender! + "PartnerId" + id: ID! + lastName: String! + partnerId: String! +} + +type EvTariff { + firstName: String! + insuredPerson: String! + lastName: String! + partnerId: String! + tariffId: String! + "Translated" + tariffName: String! + tariffPremium: Float! + tariffSortOrder: Int! +} + +type EvSurrenderValue { + disclaimer: String + existingLoan: Float + net: Float + validityDate: DateTime +} + +type EvBenefitUponSurvival { + additionalEstimatedFundAssets: Float + disclaimer: String + dueDate: DateTime + estimatedBonus: Float + estimatedFundAssets: Float + estimatedSecurityCapital: Float + estimatedTotal: Float + fundPerformanceUsedForEstimation: Float + guaranteed: Float +} + +type EvPremium { + annual: Float + contractDissolveDate: DateTime + paidCalculationDate: DateTime + paymentFrequency: PaymentPeriodicity! + periodicityName: String! + proRata: Float + single: Float + totalPremiumForYear: Float + totalPremiumPayment: Float +} + +type EvPortfolio { + contractId: String! + currency: String! + factSheetUrl: String + id: ID! + portfolioCode: String + portfolioId: String! + portfolioTotal: Decimal! + portfolioValue: Float! + positions: [EvPortfolioPosition!]! + securityCapital: Decimal +} + +type ThreeASimulationPaymentInfo { + codeLine: String! + memberNumber: String! + referenceNumber: String! +} + +type EvContractThreeASimulationType implements ThreeASimulation { + annualPremiumSimulation: Float + currencySimulation: String + maximumAmountSimulation: Float + maximumAnnualSimulation: Float + minimumAmountSimulation: Float + paymentPossibleSimulation: Boolean! + threeAPaymentInfo(amount: Float! = null): ThreeASimulationPaymentInfo +} + +"A connection to a list of items." +type EvPremiumInvoiceConnection { + "A list of edges." + edges: [EvPremiumInvoiceEdge!] + "A flattened list of the nodes." + nodes: [EvPremiumInvoice!] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +type EvAccountTransaction implements Node { + accountId: String + amount: Float! + bookingCode: Int + bookingDate: DateTime! + "Translated" + bookingText: String + clearingCode: String + contractId: String + currency: String! + currencyDate: DateTime! + "AccountTransactionId" + id: ID! + mainTransactionCode: String + partnerId: String + "Translatable" + productId: String + "Translated" + productName: String + subTransactionCode: String +} + +input EvAccountTransactionSort { + bookingDate: SortOperationKind = null +} + +input EvAccountTransactionFilter { + AND: [EvAccountTransactionFilter!] = null + bookingDate: Date = null + bookingDate_gt: Date = null + bookingDate_gte: Date = null + bookingDate_in: [Date] = null + bookingDate_lt: Date = null + bookingDate_lte: Date = null + bookingDate_not: Date = null + bookingDate_not_gt: Date = null + bookingDate_not_gte: Date = null + bookingDate_not_in: [Date] = null + bookingDate_not_lt: Date = null + bookingDate_not_lte: Date = null + OR: [EvAccountTransactionFilter!] = null + productId: String = null + productId_contains: String = null + productId_ends_with: String = null + productId_in: [String] = null + productId_not: String = null + productId_not_contains: String = null + productId_not_ends_with: String = null + productId_not_in: [String] = null + productId_not_starts_with: String = null + productId_starts_with: String = null +} + +type EvPartner { + correspondenceAddress: EvPartnerAddress + countryCode: String! + dateOfBirth: DateTime! + domicileAddress: EvPartnerAddress + firstName: String! + gender: Gender! + id: ID! + lastName: String! + partnerId: String! +} + +"A connection to a list of items." +type EvAccountTransactionConnection { + "A list of edges." + edges: [EvAccountTransactionEdge!] + "A flattened list of the nodes." + nodes: [EvAccountTransaction] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +type EvAccountDevelopment { + accountDevelopmentId: String! + accountValue: Float! + bookingDate: DateTime! + contractId: String + id: ID! + partnerId: String +} + +type EvAccountProduct { + contractId: String + "Translatable" + productId: String + "Translated" + productName: String +} + +enum EvAccountCategory { + UNKNOWN + HOLDING + PREMIUM +} + +input MortgageSort { + endDate: SortOperationKind = null + isActive: SortOperationKind = null + startDate: SortOperationKind = null +} + +type MortgageObject { + city: String + countryCode: String + id: ID! + street: String + zipCode: String +} + +type Mortgage { + amount: Float! + "Translated" + customerPrivileges: [TranslatedResource!]! + endDate: Date + "Translatable" + interestMaturity: String + "Translated" + InterestMaturityLabel: String + interestRate: Float! + isActive: Boolean! + number: String! + "Translatable" + privileges: [String] @deprecated(reason: "Use customerPrivileges instead.") + startDate: Date + "Translated" + type: String + "Translatable" + typeCode: String! + yearlyInterest: Float! +} + +type MortgageCollateral { + company: String! + id: ID! + policy: Contract + policyNumber: String! +} + +type MortgageStakeholder { + domicilAddress: MortgageStakeholderAddress + firstname: String! + id: ID! + lastname: String! +} + +type MortgageInterest { + interest: Float! + "Translated" + maturity: String! + maturityCode: String! +} + +type ThreeAStartFzTransaction { + accountBalance: Float! + accountTransactionAmount: Float! + accountType: ThreeAStartFzAccountType! + bookingDate: DateTime! + contractId: String! + currency: String! + iBAN: String + "ThreeAStartFzTransactionId" + id: ID! + marketPrice: Float! + narrativeText: String + securityNominal: Float! + transactionText: String + valueDate: DateTime! +} + +input ThreeAStartFzTransactionSort { + bookingDate: SortOperationKind = null + valueDate: SortOperationKind = null +} + +input ThreeAStartFzTransactionFilter { + accountType: ThreeAStartFzAccountType = null + accountType_gt: ThreeAStartFzAccountType = null + accountType_gte: ThreeAStartFzAccountType = null + accountType_in: [ThreeAStartFzAccountType!] = null + accountType_lt: ThreeAStartFzAccountType = null + accountType_lte: ThreeAStartFzAccountType = null + accountType_not: ThreeAStartFzAccountType = null + accountType_not_gt: ThreeAStartFzAccountType = null + accountType_not_gte: ThreeAStartFzAccountType = null + accountType_not_in: [ThreeAStartFzAccountType!] = null + accountType_not_lt: ThreeAStartFzAccountType = null + accountType_not_lte: ThreeAStartFzAccountType = null + AND: [ThreeAStartFzTransactionFilter!] = null + bookingDate: DateTime = null + bookingDate_gt: DateTime = null + bookingDate_gte: DateTime = null + bookingDate_in: [DateTime] = null + bookingDate_lt: DateTime = null + bookingDate_lte: DateTime = null + bookingDate_not: DateTime = null + bookingDate_not_gt: DateTime = null + bookingDate_not_gte: DateTime = null + bookingDate_not_in: [DateTime] = null + bookingDate_not_lt: DateTime = null + bookingDate_not_lte: DateTime = null + OR: [ThreeAStartFzTransactionFilter!] = null +} + +type ThreeAStartFzCustomer { + contractId: String + correspondenceAddress: ThreeAStartFzAddress + customerFirstName: String! + customerId: String! + customerLastName: String! + dateOfBirth: DateTime + domicileAddress: ThreeAStartFzAddress + endDate: DateTime + gender: Gender! + levelOfEmployment: ThreeAStartFzLevelOfEmployment! +} + +type ThreeAStartFzPortfolio { + calculationDate: DateTime! + contractId: String! + currency: String! + id: ID! + portfolioId: String! + portfolioValueInBalanceSheetCurrency: Float! + portfolioValueInPortfolioCurrency: Float! + positions: [ThreeAStartFzPortfolioPosition!]! +} + +type ThreeAStartFzAccount { + accountType: ThreeAStartFzAccountType! + contractId: String! + currency: String! + currentBalanceAccountCurrency: Float! + endDate: DateTime + iBAN: String + "ThreeAStartFzAccountId" + id: ID! + offsetFlag: Int! + totalTransactionAccountCurrency: Float! +} + +type ThreeAStartFzDevelopment { + amountInvestedValue: Float! + amountPaidOutValue: Float! + calculationDate: DateTime! + contractId: String! + currency: String! + entryAccountValue: Float! + "ThreeAStartFzDevelopmentId" + id: ID! + investmentAccountValue: Float! + portfolioValue: Float! + totalValue: Float! +} + +"A connection to a list of items." +type ThreeAStartFzTransactionConnection { + "A list of edges." + edges: [ThreeAStartFzTransactionEdge!] + "A flattened list of the nodes." + nodes: [ThreeAStartFzTransaction] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +enum ThreeAStartFzAccountType { + INVESTMENT3ANEW + INVESTMENTFZMIGRATION + INVESTMENT3AMIGRATION + INVESTMENTFZNEW + ANLAGE3ANEW + ANLAGEFZMIGRATION + ANLAGE3AMIGRATION + ANLAGEFZNEW +} + +type ThreeAStartSimulationType implements ThreeASimulation { + annualPremiumSimulation: Float + currencySimulation: String + maximumAmountSimulation: Float + maximumAnnualSimulation: Float + minimumAmountSimulation: Float + paymentPossibleSimulation: Boolean! +} + +enum TranslatableLanguage { + NOTSET + DE + FR + IT + EN +} + +enum ApplyPolicy { + BEFORE_RESOLVER + AFTER_RESOLVER +} + +enum ContractTag { + THREEA + PENSIONFUND + PAPERLESS +} + +type ContractsOutline { + pensionFund: PensionFundOutline +} + +"The `Date` scalar represents an ISO-8601 compliant date type." +scalar Date + +enum SortOperationKind { + ASC + DESC +} + +enum FilterEqualityOperator { + EQUALS + NOTEQUALS + GREATERTHANOREQUALS + SMALLERTHANOREQUALS + GREATERTHAN + SMALLERTHAN +} + +enum FilterLogicalOperator { + AND + OR +} + +type ZmaAddress implements Address { + additional: String + careOf: String + city: String + company: String + countryCode: String + department: String + firstName: String + id: String + lastName: String + postOfficeBox: String + "Translated" + salutation: String + street: String + zipCode: String +} + +type ZmaStandingOrder { + amount: Float! + frequency: PaymentPeriodicity! + id: ID! + standingOrderId: String! +} + +enum ZmaAccountType { + UNKNOWN + INVESTMENT + ENTRY +} + +type ZmaPortfolioHistory { + calculationDate: DateTime! + contractId: String + id: ID! + investmentValueInContractCurrency: Float + payoutValueInContractCurrency: Float + portfolioHistoryId: String! + portfolioId: String + portfolioValueInBalanceSheetCurrency: Float + portfolioValueInPortfolioCurrency: Float! +} + +type ZmaPortfolioPosition { + factSheet: Link + factSheetUrl: String @deprecated(reason: "use factSheet instead") + investmentCategory: InvestmentCategory! + "Translated" + investmentCategoryName: String! + investmentCategoryPercentage: Float! + investmentCurrencyPercentage: Float! + isin: String! + monetaryAssetName: String! + monetaryAssetTitleCurrency: String! + nominalValueOrQuantity: Float! + portfolioPositionId: String! + portfolioShare: Float! + position: Int! + provider: String + valorPerformance: Float! + valuationReferenceCurrency: Float! +} + +enum ZmaContractType { + UNDEFINED + NONWITHDRAWALPLAN + WITHDRAWALPLAN +} + +enum ZmaContractPerformanceCalculation { + MONTH + YEAR +} + +"Information about pagination in a connection." +type PageInfo { + "When paginating forwards, the cursor to continue." + endCursor: String + "Indicates whether more edges exist following the set defined by the clients arguments." + hasNextPage: Boolean! + "Indicates whether more edges exist prior the set defined by the clients arguments." + hasPreviousPage: Boolean! + "When paginating backwards, the cursor to continue." + startCursor: String +} + +"An edge in a connection." +type ZmaAccountTransactionEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: ZmaAccountTransaction +} + +type PeriodicalValuesOfDouble { + monthly: Float! + yearly: Float! +} + +interface ProjectedRetirement { + projectedAge: Int! + projectedDate: Date! + projectedSavings: Decimal! +} + +interface PensionFundContract { + contractNumber: String + foundation: String + id: ID! + insuranceType: String! + productCode: String! + stakeHolder: String +} + +"An edge in a connection." +type XPlanTransactionEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: XPlanTransaction +} + +"An edge in a connection." +type PensionFundFzPolicyTransactionEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: PensionFundFzPolicyTransaction! +} + +interface RetirementDevelopment { + retirementCapital: Float! + retirementDate: DateTime! + retirementPension: Float! +} + +"An edge in a connection." +type DigisTransactionEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: DigisTransaction +} + +type DigisAddress implements Address { + additional: String + careOf: String + city: String + company: String + countryCode: String + department: String + firstName: String + id: String + lastName: String + postOfficeBox: String + "Translated" + salutation: String + street: String + zipCode: String +} + +enum PremiumInvoiceStatus { + PENDING + PAYED +} + +type EvPartnerAddress implements Address { + additional: String + careOf: String + city: String + company: String + countryCode: String + department: String + firstName: String + id: String + lastName: String + postOfficeBox: String + "Translated" + salutation: String + street: String + zipCode: String +} + +type EvPortfolioPosition { + calculationDate: DateTime! + factSheet: Link + factSheetUrl: String @deprecated(reason: "use factSheet instead") + investmentCategory: InvestmentCategory! + "Translated" + investmentCategoryName: String! + investmentCategoryPercentage: Float! + investmentCurrencyPercentage: Float! + isin: String! + monetaryAssetName: String! + monetaryAssetTitleCurrency: String! + nominalValueOrQuantity: Float! + portfolioPositionId: String! + portfolioPositionValue: Float! + portfolioShare: Float! + position: Int! + provider: String + valorNumber: Float! + valorPerformance: Float! +} + +"An edge in a connection." +type EvPremiumInvoiceEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: EvPremiumInvoice! +} + +"An edge in a connection." +type EvAccountTransactionEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: EvAccountTransaction +} + +type TranslatedResource { + key: String! + label: String! +} + +type MortgageStakeholderAddress implements Address { + additional: String + careOf: String + city: String + company: String + countryCode: String! + department: String + firstName: String + gender: Gender! + id: String + lastName: String + postOfficeBox: String + salutation: String + street: String + zipCode: String +} + +enum ThreeAStartFzLevelOfEmployment { + UNKNOWN + EMPLOYEE + SELFEMPLOYED +} + +type ThreeAStartFzAddress implements Address { + additional: String + careOf: String + city: String + company: String + countryCode: String + department: String + firstName: String + id: String + lastName: String + postOfficeBox: String + "Translated" + salutation: String + street: String + zipCode: String +} + +type ThreeAStartFzPortfolioPosition { + contractId: String! + currency: String! + factSheet: Link + id: ID! + isin: String! + monetaryAssetName: String! + monetaryAssetShortName: String! + nominalValueOrQuantity: Float! + portfolioId: String! + portfolioPositionId: String! + portfolioPositionValue: Float! + portfolioShare: Float + position: Int! + provider: String + valorPerformance: Float! +} + +"An edge in a connection." +type ThreeAStartFzTransactionEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: ThreeAStartFzTransaction +} + +type PensionFundOutline { + purchaseOptions: PensionFundPurchaseOptions + "Use PensionFundPolicy.projectedRetirement.projectedDate instead" + retirementDate: DateTime @deprecated(reason: "Use PensionFundPolicy.projectedRetirement.projectedDate instead") +} + +enum InvestmentCategory { + MONEYMARKETFUNDS + GUARANTEEFUND + CAPITALPROTECTEDFUND + CAPITALPROTECTEDNOTE + BONDFUND + PENSIONFUND + REALESTATEFUND + CONVERTIBLEBONDS + STRATEGYFUNDBALANCEDFUND + EQUITYFUND + FUNDOFFUNDS + SPECIALFUND + RAWMATERIALSGOLD + HEDGEFUND + CERTIFICATE +} + +type Link { + title: String! + type: LinkDestinationType! + url: String! +} + +type PensionFundPurchaseOptions { + maxRetirementCapital: Float! + pensionPlan: PensionPlan + purchaseEarlyWithdrawalForHomeOwnership: Float! + purchasePensionFund: Float! + purchaseTotalPossible: Float! + purchaseWithdrawalDivorce: Float! + retirementSavings: Float! +} + +enum LinkDestinationType { + DOCUMENT + WEBSITE +} + +enum PensionPlan { + EMPLOYEE + SENIOR + IV + RETIREMENT +} + +type Subscription { + onPaperlessChanged: Boolean! +} + +type XPlanContactInfo { + companyName: String + department: String + firstName: String + lastName: String + salutationCode: Int +} + +type XPlanFundDevelopment { + calculationDate: DateTime! + totalCapital: Decimal! +} + +type XPlanPremiumFundBalance { + calculationDate: DateTime! + fundCapital: Decimal! + fundFactSheetUrl: String + fundSharePrice: Decimal + fundShares: Long! + investmentStrategy: String! + isinNumber: String + liquidityAccountBalance: Decimal! + totalCapital: Decimal! +} + +type DeathAfterRetirement { + orphanPension: Float + widowPension: Float +} + +scalar Uuid + +"The built-in `Decimal` scalar type." +scalar Decimal + +enum FzPolicyPlanType { + YEARLONG + PERENNIALLY +} + +"The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1." +scalar Long + + + +directive @authorize("Defines when when the resolver shall be executed.By default the resolver is executed after the policy has determined that the current user is allowed to access the field." apply: ApplyPolicy! = BEFORE_RESOLVER "The name of the authorization policy that determines access to the annotated resource." policy: String = null "Roles that are allowed to access the annotated resource." roles: [String!] = null) repeatable on SCHEMA | OBJECT | FIELD_DEFINITION + + diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/DocumentClient.graphql b/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/DocumentClient.graphql new file mode 100644 index 00000000000..3125f8e2b90 --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/__resources__/DocumentClient.graphql @@ -0,0 +1,339 @@ +schema { + query: Query + mutation: Mutation +} + +type Query { + envelope(processId: String = null): CustomerEnvelope + envelopes(after: String = null before: String = null contractId: String = null first: PaginationAmount = null invoiceNumber: String = null last: PaginationAmount = null order_by: CustomerEnvelopeSort = null processId: String = null where: CustomerEnvelopeFilter = null): CustomerEnvelopeConnection +} + +type Mutation { + requestDocumentDownload(id: ID! = null): String! + requestEnvelopeDownload(fileFormat: FileFormat! = null id: ID! = null): String! +} + +type NvsDocument implements Document { + contractId: String + contractNumber: String + "Translated" + documentCategory: String! + documentCategoryCode: DocumentCategoryType! + documentDate: DateTime! + documentId: String! + documentTitle: String! + documentType: String! + documentTypeCode: String! + id: ID! + isTaxRelevant: Boolean! + processId: String +} + +type EvDocument implements Document { + contractId: String + contractNumber: String + "Translated" + documentCategory: String! + documentCategoryCode: DocumentCategoryType! + documentDate: DateTime! + documentId: String! + documentTitle: String! + "Translated" + documentType: String! + documentTypeCode: String! + id: ID! + invoiceNumber: String + isTaxRelevant: Boolean! + partnerNumber: String! +} + +type BankingDocument implements Document { + businessUnit: String! + contractId: String + contractNumber: String + "Translated" + documentCategory: String! + documentCategoryCode: DocumentCategoryType! + documentDate: DateTime! + documentId: String! + documentTitle: String! + "Translated" + documentType: String! + documentTypeCode: String! + id: ID! + isTaxRelevant: Boolean! + planNr: String! @deprecated(reason: "Use contractId instead") +} + +enum ApplyPolicy { + BEFORE_RESOLVER + AFTER_RESOLVER +} + +type CustomerEnvelope { + contractNumber: String + documents: [Document!]! + envelopeDate: DateTime! + envelopeId: String! + envelopeTitle: String + id: ID! +} + +input CustomerEnvelopeSort { + envelopeDate: SortOperationKind = null +} + +input CustomerEnvelopeFilter { + AND: [CustomerEnvelopeFilter!] = null + documents_some: DocumentFilter = null + envelopeDate: DateTime = null + envelopeDate_gt: DateTime = null + envelopeDate_gte: DateTime = null + envelopeDate_in: [DateTime!] = null + envelopeDate_lt: DateTime = null + envelopeDate_lte: DateTime = null + envelopeDate_not: DateTime = null + envelopeDate_not_gt: DateTime = null + envelopeDate_not_gte: DateTime = null + envelopeDate_not_in: [DateTime!] = null + envelopeDate_not_lt: DateTime = null + envelopeDate_not_lte: DateTime = null + isTaxRelevant: Boolean = null + OR: [CustomerEnvelopeFilter!] = null +} + +"A connection to a list of items." +type CustomerEnvelopeConnection { + contractFilterEntries: [ContractFilterEntry!]! + contractNumbers: [String!]! @deprecated(reason: "Use contractFilterEntries instead") + "Translated" + documentCategories: [TranslatedResourceOfDocumentCategoryType!]! + "A list of edges." + edges: [CustomerEnvelopeEdge!] + "A flattened list of the nodes." + nodes: [CustomerEnvelope!] + "Information to aid in pagination." + pageInfo: PageInfo! + totalCount: Int! +} + +scalar PaginationAmount + +enum FileFormat { + PDF + ZIP +} + +interface Document { + contractId: String + contractNumber: String + documentCategory: String! + documentCategoryCode: DocumentCategoryType! + documentDate: DateTime! + documentId: String! + documentTitle: String! + documentType: String! + documentTypeCode: String! + id: ID! + isTaxRelevant: Boolean! +} + +"The `DateTime` scalar represents an ISO-8601 compliant date time type." +scalar DateTime + +enum DocumentCategoryType { + WERTDOKUMENTE + INKASSODOKUMENTE + KORRESPONDENZDOKUMENTE + LEISTUNGSDOKUMENTE + OFFERTDOKUMENTE + PERSONENDOKUMENTE + REPORT + SONSTIGE + STEUERDOKUMENTE + VERTRAGSANPASSUNGEN + VERTRAGSDOKUMENTE +} + +type TranslatedResourceOfDocumentCategoryType { + key: DocumentCategoryType! + label: String! +} + +type ContractFilterEntry { + key: String! + label: String! +} + +enum TranslatableLanguage { + NOTSET + DE + FR + IT + EN +} + +enum SortOperationKind { + ASC + DESC +} + +input DocumentFilter { + AND: [DocumentFilter!] = null + contractId: String = null + contractId_contains: String = null + contractId_ends_with: String = null + contractId_in: [String] = null + contractId_not: String = null + contractId_not_contains: String = null + contractId_not_ends_with: String = null + contractId_not_in: [String] = null + contractId_not_starts_with: String = null + contractId_starts_with: String = null + contractNumber: String = null + contractNumber_contains: String = null + contractNumber_ends_with: String = null + contractNumber_in: [String] = null + contractNumber_not: String = null + contractNumber_not_contains: String = null + contractNumber_not_ends_with: String = null + contractNumber_not_in: [String] = null + contractNumber_not_starts_with: String = null + contractNumber_starts_with: String = null + documentCategoryType: DocumentCategoryType = null + documentCategoryType_gt: DocumentCategoryType = null + documentCategoryType_gte: DocumentCategoryType = null + documentCategoryType_in: [DocumentCategoryType!] = null + documentCategoryType_lt: DocumentCategoryType = null + documentCategoryType_lte: DocumentCategoryType = null + documentCategoryType_not: DocumentCategoryType = null + documentCategoryType_not_gt: DocumentCategoryType = null + documentCategoryType_not_gte: DocumentCategoryType = null + documentCategoryType_not_in: [DocumentCategoryType!] = null + documentCategoryType_not_lt: DocumentCategoryType = null + documentCategoryType_not_lte: DocumentCategoryType = null + documentDate: DateTime = null + documentDate_gt: DateTime = null + documentDate_gte: DateTime = null + documentDate_in: [DateTime!] = null + documentDate_lt: DateTime = null + documentDate_lte: DateTime = null + documentDate_not: DateTime = null + documentDate_not_gt: DateTime = null + documentDate_not_gte: DateTime = null + documentDate_not_in: [DateTime!] = null + documentDate_not_lt: DateTime = null + documentDate_not_lte: DateTime = null + documentId: String = null + documentId_contains: String = null + documentId_ends_with: String = null + documentId_in: [String] = null + documentId_not: String = null + documentId_not_contains: String = null + documentId_not_ends_with: String = null + documentId_not_in: [String] = null + documentId_not_starts_with: String = null + documentId_starts_with: String = null + documentTitle: String = null + documentTitle_contains: String = null + documentTitle_ends_with: String = null + documentTitle_in: [String] = null + documentTitle_not: String = null + documentTitle_not_contains: String = null + documentTitle_not_ends_with: String = null + documentTitle_not_in: [String] = null + documentTitle_not_starts_with: String = null + documentTitle_starts_with: String = null + documentType: String = null + documentType_contains: String = null + documentType_ends_with: String = null + documentType_in: [String] = null + documentType_not: String = null + documentType_not_contains: String = null + documentType_not_ends_with: String = null + documentType_not_in: [String] = null + documentType_not_starts_with: String = null + documentType_starts_with: String = null + envelopeId: String = null + envelopeId_contains: String = null + envelopeId_ends_with: String = null + envelopeId_in: [String] = null + envelopeId_not: String = null + envelopeId_not_contains: String = null + envelopeId_not_ends_with: String = null + envelopeId_not_in: [String] = null + envelopeId_not_starts_with: String = null + envelopeId_starts_with: String = null + envelopeOrder: Int = null + envelopeOrder_gt: Int = null + envelopeOrder_gte: Int = null + envelopeOrder_in: [Int!] = null + envelopeOrder_lt: Int = null + envelopeOrder_lte: Int = null + envelopeOrder_not: Int = null + envelopeOrder_not_gt: Int = null + envelopeOrder_not_gte: Int = null + envelopeOrder_not_in: [Int!] = null + envelopeOrder_not_lt: Int = null + envelopeOrder_not_lte: Int = null + filterId: String = null + filterId_contains: String = null + filterId_ends_with: String = null + filterId_in: [String] = null + filterId_not: String = null + filterId_not_contains: String = null + filterId_not_ends_with: String = null + filterId_not_in: [String] = null + filterId_not_starts_with: String = null + filterId_starts_with: String = null + hiddenFilterId: String = null + hiddenFilterId_contains: String = null + hiddenFilterId_ends_with: String = null + hiddenFilterId_in: [String] = null + hiddenFilterId_not: String = null + hiddenFilterId_not_contains: String = null + hiddenFilterId_not_ends_with: String = null + hiddenFilterId_not_in: [String] = null + hiddenFilterId_not_starts_with: String = null + hiddenFilterId_starts_with: String = null + isTaxRelevant: Boolean = null + isTaxRelevant_not: Boolean = null + OR: [DocumentFilter!] = null + portalCustomerId: String = null + portalCustomerId_contains: String = null + portalCustomerId_ends_with: String = null + portalCustomerId_in: [String] = null + portalCustomerId_not: String = null + portalCustomerId_not_contains: String = null + portalCustomerId_not_ends_with: String = null + portalCustomerId_not_in: [String] = null + portalCustomerId_not_starts_with: String = null + portalCustomerId_starts_with: String = null +} + +"Information about pagination in a connection." +type PageInfo { + "When paginating forwards, the cursor to continue." + endCursor: String + "Indicates whether more edges exist following the set defined by the clients arguments." + hasNextPage: Boolean! + "Indicates whether more edges exist prior the set defined by the clients arguments." + hasPreviousPage: Boolean! + "When paginating backwards, the cursor to continue." + startCursor: String +} + +"An edge in a connection." +type CustomerEnvelopeEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: CustomerEnvelope! +} + + + + +directive @authorize("Defines when when the resolver shall be executed.By default the resolver is executed after the policy has determined that the current user is allowed to access the field." apply: ApplyPolicy! = BEFORE_RESOLVER "The name of the authorization policy that determines access to the annotated resource." policy: String = null "Roles that are allowed to access the annotated resource." roles: [String!] = null) repeatable on SCHEMA | OBJECT | FIELD_DEFINITION + +