Skip to content

Commit

Permalink
Allow Zero Complexity (#6097)
Browse files Browse the repository at this point in the history
* Allow Zero Complexity

* cleanup
  • Loading branch information
michaelstaib authored Apr 28, 2023
1 parent 1cbc56e commit a4ab9e1
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 16 deletions.
67 changes: 62 additions & 5 deletions src/HotChocolate/Core/src/Types/Types/Directives/CostDirective.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.Serialization;
using HotChocolate.Language;
using HotChocolate.Properties;

namespace HotChocolate.Types;
Expand All @@ -11,17 +10,32 @@ namespace HotChocolate.Types;
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
#endif
public sealed class CostDirective
{
/// <summary>
/// Initializes a new instance of <see cref="CostDirective"/>.
/// </summary>
public CostDirective()
{
Complexity = 1;
Multipliers = Array.Empty<MultiplierPathString>();
}

/// <summary>
/// Initializes a new instance of <see cref="CostDirective"/>.
/// </summary>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="complexity"/> is less than 0.
/// </exception>
public CostDirective(int complexity)
{
if (complexity <= 0)
if (complexity < 0)
{
throw new ArgumentOutOfRangeException(
nameof(complexity),
Expand All @@ -33,11 +47,26 @@ public CostDirective(int complexity)
Multipliers = Array.Empty<MultiplierPathString>();
}

/// <summary>
/// Initializes a new instance of <see cref="CostDirective"/>.
/// </summary>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <param name="multipliers">
/// The multiplier paths.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="complexity"/> is less than 0.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="multipliers"/> is <c>null</c>.
/// </exception>
public CostDirective(
int complexity,
params MultiplierPathString[] multipliers)
{
if (complexity <= 0)
if (complexity < 0)
{
throw new ArgumentOutOfRangeException(
nameof(complexity),
Expand All @@ -54,12 +83,30 @@ public CostDirective(
Multipliers = multipliers.Where(t => t.HasValue).ToArray();
}

/// <summary>
/// Initializes a new instance of <see cref="CostDirective"/>.
/// </summary>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <param name="defaultMultiplier">
/// The default multiplier.
/// </param>
/// <param name="multipliers">
/// The multiplier paths.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="complexity"/> is less than 0.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="multipliers"/> is <c>null</c>.
/// </exception>
public CostDirective(
int complexity,
int defaultMultiplier,
params MultiplierPathString[] multipliers)
{
if (complexity <= 0)
if (complexity < 0)
{
throw new ArgumentOutOfRangeException(
nameof(complexity),
Expand All @@ -85,6 +132,7 @@ public CostDirective(
Multipliers = multipliers.Where(t => t.HasValue).ToArray();
}

// this constructor is used for serialization.
private CostDirective(
int complexity,
IReadOnlyList<MultiplierPathString> multipliers,
Expand All @@ -95,9 +143,18 @@ private CostDirective(
DefaultMultiplier = defaultMultiplier;
}

/// <summary>
/// Gets the complexity of the field.
/// </summary>
public int Complexity { get; }

/// <summary>
/// Gets the multiplier paths.
/// </summary>
public IReadOnlyList<MultiplierPathString> Multipliers { get; }

/// <summary>
/// Gets the default multiplier.
/// </summary>
public int? DefaultMultiplier { get; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace HotChocolate.Types;

/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
public sealed class CostDirectiveType : DirectiveType<CostDirective>
{
protected override void Configure(IDirectiveTypeDescriptor<CostDirective> descriptor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ namespace HotChocolate.Types;

public static class CostInterfaceFieldDescriptorExtensions
{
/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
/// <param name="descriptor">
/// The interface field descriptor.
/// </param>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <returns>
/// Returns the object field descriptor for configuration chaining.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="descriptor"/> is <c>null</c>.
/// </exception>
public static IInterfaceFieldDescriptor Cost(
this IInterfaceFieldDescriptor descriptor,
int complexity)
Expand All @@ -16,6 +32,25 @@ public static IInterfaceFieldDescriptor Cost(
return descriptor.Directive(new CostDirective(complexity));
}

/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
/// <param name="descriptor">
/// The interface field descriptor.
/// </param>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <param name="multiplier">
/// The multiplier path.
/// </param>
/// <returns>
/// Returns the object field descriptor for configuration chaining.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="descriptor"/> is <c>null</c>.
/// </exception>
public static IInterfaceFieldDescriptor Cost(
this IInterfaceFieldDescriptor descriptor,
int complexity,
Expand All @@ -26,10 +61,26 @@ public static IInterfaceFieldDescriptor Cost(
throw new ArgumentNullException(nameof(descriptor));
}

return descriptor.Directive(
new CostDirective(complexity, multiplier));
return descriptor.Directive(new CostDirective(complexity, multiplier));
}

/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
/// <param name="descriptor">
/// The interface field descriptor.
/// </param>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <param name="multipliers">
/// The multiplier paths.
/// </param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="descriptor"/> is <c>null</c>.
/// </exception>
public static IInterfaceFieldDescriptor Cost(
this IInterfaceFieldDescriptor descriptor,
int complexity,
Expand All @@ -40,7 +91,6 @@ public static IInterfaceFieldDescriptor Cost(
throw new ArgumentNullException(nameof(descriptor));
}

return descriptor.Directive(
new CostDirective(complexity, multipliers));
return descriptor.Directive(new CostDirective(complexity, multipliers));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ namespace HotChocolate.Types;

public static class CostObjectFieldDescriptorExtensions
{
/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
/// <param name="descriptor">
/// The object field descriptor.
/// </param>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <returns>
/// Returns the object field descriptor for configuration chaining.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="descriptor"/> is <c>null</c>.
/// </exception>
public static IObjectFieldDescriptor Cost(
this IObjectFieldDescriptor descriptor,
int complexity)
Expand All @@ -16,6 +32,25 @@ public static IObjectFieldDescriptor Cost(
return descriptor.Directive(new CostDirective(complexity));
}

/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
/// <param name="descriptor">
/// The object field descriptor.
/// </param>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <param name="multiplier">
/// The multiplier path.
/// </param>
/// <returns>
/// Returns the object field descriptor for configuration chaining.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="descriptor"/> is <c>null</c>.
/// </exception>
public static IObjectFieldDescriptor Cost(
this IObjectFieldDescriptor descriptor,
int complexity,
Expand All @@ -26,10 +61,26 @@ public static IObjectFieldDescriptor Cost(
throw new ArgumentNullException(nameof(descriptor));
}

return descriptor.Directive(
new CostDirective(complexity, multiplier));
return descriptor.Directive(new CostDirective(complexity, multiplier));
}

/// <summary>
/// The cost directive can be used to express the expected
/// cost that a resolver incurs on the system.
/// </summary>
/// <param name="descriptor">
/// The object field descriptor.
/// </param>
/// <param name="complexity">
/// The complexity of the field.
/// </param>
/// <param name="multipliers">
/// The multiplier paths.
/// </param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="descriptor"/> is <c>null</c>.
/// </exception>
public static IObjectFieldDescriptor Cost(
this IObjectFieldDescriptor descriptor,
int complexity,
Expand All @@ -40,7 +91,6 @@ public static IObjectFieldDescriptor Cost(
throw new ArgumentNullException(nameof(descriptor));
}

return descriptor.Directive(
new CostDirective(complexity, multipliers));
return descriptor.Directive(new CostDirective(complexity, multipliers));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ namespace HotChocolate.Types.Directives;
public class CostDirectiveTests
{
[Fact]
public void ComplexityEqualsZero()
public void ComplexitySmallerThanZero()
{
// arrange
// act
void Action() => new CostDirective(0);
void Action1() => new CostDirective(0, "a");
void Action() => new CostDirective(-1);
void Action1() => new CostDirective(-1, "a");

// assert
Assert.Throws<ArgumentOutOfRangeException>(Action);
Expand Down

0 comments on commit a4ab9e1

Please sign in to comment.