Skip to content

Commit b89f2e7

Browse files
committed
Better error message when there's more than 1 resolver
1 parent d3d789f commit b89f2e7

14 files changed

+125
-22
lines changed

src/Our.Umbraco.GraphQL/Types/ComplexGraphTypeOfIPublishedContentExtensions.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using GraphQL;
22
using GraphQL.Types;
33
using Our.Umbraco.GraphQL.ValueResolvers;
4+
using System;
5+
using System.Linq;
46
using Umbraco.Core.Models;
57
using Umbraco.Core.Models.PublishedContent;
68

@@ -27,8 +29,7 @@ public static ComplexGraphType<IPublishedContent> AddUmbracoContentPropeties(
2729

2830
var publishedPropertyType = publishedContentType.GetPropertyType(property.Alias);
2931

30-
var resolver = GraphQLValueResolversResolver.Current.FindResolver(publishedPropertyType)
31-
?? new DefaultValueResolver();
32+
var resolver = GetValueResolver(contentType, publishedPropertyType);
3233

3334
var propertyGraphType = resolver.GetGraphQLType(publishedPropertyType);
3435

@@ -53,5 +54,36 @@ public static ComplexGraphType<IPublishedContent> AddUmbracoContentPropeties(
5354

5455
return graphType;
5556
}
57+
58+
private static IGraphQLValueResolver GetValueResolver(IContentTypeComposition contentType, PublishedPropertyType propertyType)
59+
{
60+
var foundResolvers = GraphQLValueResolversResolver.Current.Resolvers.Where(r => r.IsResolver(propertyType)).ToList();
61+
var defaultResolvers = GraphQLValueResolversResolver.Current.DefaultResolvers;
62+
63+
if(foundResolvers.Count == 1)
64+
{
65+
return foundResolvers[0];
66+
}
67+
68+
if (foundResolvers.Count > 0)
69+
{
70+
//more than one resolver was found
71+
//get the non-default and see if we have only one
72+
var nonDefault = foundResolvers.Except(defaultResolvers.Select(x => x.Item1)).ToList();
73+
if (nonDefault.Count == 1)
74+
{
75+
//there's only 1 custom resolver registered, so use it
76+
return nonDefault[0];
77+
}
78+
79+
//this is not allowed, there cannot be more than 1 resolver
80+
throw new InvalidOperationException($"Type '{nonDefault[1].GetType().FullName}' cannot be an IGraphQLValueResolver" +
81+
$" for property '{propertyType.PropertyTypeAlias}' of content type '{contentType.Alias}' because type '{nonDefault[0].GetType().FullName}' has already been detected as a resolver" +
82+
$" for that property, and only one converter can exist for a resolver.");
83+
}
84+
85+
//no resolvers registered so we use the fallback resolver
86+
return GraphQLValueResolversResolver.Current.FallbackResolver;
87+
}
5688
}
5789
}

src/Our.Umbraco.GraphQL/ValueResolvers/BooleanValueResolver.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace Our.Umbraco.GraphQL.ValueResolvers
77
{
8+
[DefaultGraphQLValueResolver]
89
public class BooleanValueResolver : GraphQLValueResolver
910
{
1011
public override Type GetGraphQLType(PublishedPropertyType propertyType)
@@ -14,7 +15,7 @@ public override Type GetGraphQLType(PublishedPropertyType propertyType)
1415
: typeof(ListGraphType<BooleanGraphType>);
1516
}
1617

17-
public override bool IsConverter(PublishedPropertyType propertyType)
18+
public override bool IsResolver(PublishedPropertyType propertyType)
1819
{
1920
return propertyType.ClrType == typeof(bool) ||
2021
propertyType.ClrType == typeof(IEnumerable<bool>);

src/Our.Umbraco.GraphQL/ValueResolvers/DateValueResolver.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace Our.Umbraco.GraphQL.ValueResolvers
77
{
8+
[DefaultGraphQLValueResolver]
89
public class DateValueResolver : GraphQLValueResolver
910
{
1011
public override Type GetGraphQLType(PublishedPropertyType propertyType)
@@ -15,7 +16,7 @@ public override Type GetGraphQLType(PublishedPropertyType propertyType)
1516
: typeof(ListGraphType<DateGraphType>);
1617
}
1718

18-
public override bool IsConverter(PublishedPropertyType propertyType)
19+
public override bool IsResolver(PublishedPropertyType propertyType)
1920
{
2021
return propertyType.ClrType == typeof(DateTime) ||
2122
propertyType.ClrType == typeof(DateTimeOffset) ||

src/Our.Umbraco.GraphQL/ValueResolvers/DecimalValueResolver.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace Our.Umbraco.GraphQL.ValueResolvers
77
{
8+
[DefaultGraphQLValueResolver]
89
public class DecimalValueResolver : GraphQLValueResolver
910
{
1011
public override Type GetGraphQLType(PublishedPropertyType propertyType)
@@ -15,7 +16,7 @@ public override Type GetGraphQLType(PublishedPropertyType propertyType)
1516
: typeof(ListGraphType<DecimalGraphType>);
1617
}
1718

18-
public override bool IsConverter(PublishedPropertyType propertyType)
19+
public override bool IsResolver(PublishedPropertyType propertyType)
1920
{
2021
return propertyType.ClrType == typeof(decimal) ||
2122
propertyType.ClrType == typeof(double) ||
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace Our.Umbraco.GraphQL.ValueResolvers
4+
{
5+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
6+
internal sealed class DefaultGraphQLValueResolverAttribute : Attribute
7+
{
8+
}
9+
}

src/Our.Umbraco.GraphQL/ValueResolvers/DefaultValueResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public override Type GetGraphQLType(PublishedPropertyType propertyType)
1616
return typeof(StringGraphType);
1717
}
1818

19-
public override bool IsConverter(PublishedPropertyType propertyType)
19+
public override bool IsResolver(PublishedPropertyType propertyType)
2020
{
2121
return false;
2222
}

src/Our.Umbraco.GraphQL/ValueResolvers/FloatValueResolver.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace Our.Umbraco.GraphQL.ValueResolvers
77
{
8+
[DefaultGraphQLValueResolver]
89
public class FloatValueResolver : GraphQLValueResolver
910
{
1011
public override Type GetGraphQLType(PublishedPropertyType propertyType)
@@ -14,7 +15,7 @@ public override Type GetGraphQLType(PublishedPropertyType propertyType)
1415
: typeof(ListGraphType<FloatGraphType>);
1516
}
1617

17-
public override bool IsConverter(PublishedPropertyType propertyType)
18+
public override bool IsResolver(PublishedPropertyType propertyType)
1819
{
1920
return propertyType.ClrType == typeof(float) ||
2021
propertyType.ClrType == typeof(IEnumerable<float>);
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
using System;
1+
using System;
22
using Umbraco.Core.Models.PublishedContent;
33

44
namespace Our.Umbraco.GraphQL.ValueResolvers
55
{
6+
[DefaultGraphQLValueResolver]
67
public abstract class GraphQLValueResolver : IGraphQLValueResolver
78
{
89
public abstract Type GetGraphQLType(PublishedPropertyType propertyType);
@@ -12,6 +13,6 @@ public virtual object Resolve(PublishedPropertyType propertyType, object value)
1213
return value;
1314
}
1415

15-
public abstract bool IsConverter(PublishedPropertyType propertyType);
16+
public abstract bool IsResolver(PublishedPropertyType propertyType);
1617
}
17-
}
18+
}
Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,80 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Reflection;
5+
using System.Threading;
6+
using Umbraco.Core;
47
using Umbraco.Core.Logging;
5-
using Umbraco.Core.Models.PublishedContent;
68
using Umbraco.Core.ObjectResolution;
79

810
namespace Our.Umbraco.GraphQL.ValueResolvers
911
{
1012
public class GraphQLValueResolversResolver : ManyObjectsResolverBase<GraphQLValueResolversResolver, IGraphQLValueResolver>
1113
{
14+
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
15+
private Tuple<IGraphQLValueResolver, DefaultGraphQLValueResolverAttribute>[] _defaults = null;
16+
private IGraphQLValueResolver _fallback = null;
17+
1218
internal GraphQLValueResolversResolver(IServiceProvider serviceProvider, ILogger logger,
1319
IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) : base(
1420
serviceProvider, logger, value, scope)
1521
{
1622
}
1723

18-
public IEnumerable<IGraphQLValueResolver> Converters => Values;
24+
public IEnumerable<IGraphQLValueResolver> Resolvers => Values;
1925

20-
internal IGraphQLValueResolver FindResolver(PublishedPropertyType propertyType)
26+
/// <summary>
27+
/// Caches and gets the default resolvers with their metadata
28+
/// </summary>
29+
internal Tuple<IGraphQLValueResolver, DefaultGraphQLValueResolverAttribute>[] DefaultResolvers
2130
{
22-
// TODO: Validate multiple found and throw better exceptions
23-
return Values.SingleOrDefault(x => x.IsConverter(propertyType));
31+
get
32+
{
33+
using (var locker = new UpgradeableReadLock(_lock))
34+
{
35+
if (_defaults == null)
36+
{
37+
locker.UpgradeToWriteLock();
38+
39+
var defaultResolverWithAttributes = Resolvers
40+
.Select(x => new
41+
{
42+
attribute = x.GetType().GetCustomAttribute<DefaultGraphQLValueResolverAttribute>(false),
43+
resolver = x
44+
})
45+
.Where(x => x.attribute != null)
46+
.ToArray();
47+
48+
_defaults = defaultResolverWithAttributes
49+
.Select(
50+
x => new Tuple<IGraphQLValueResolver, DefaultGraphQLValueResolverAttribute>(x.resolver, x.attribute))
51+
.ToArray();
52+
}
53+
54+
return _defaults;
55+
}
56+
}
57+
}
58+
59+
/// <summary>
60+
/// Caches and gets the fallback resolver
61+
/// </summary>
62+
internal IGraphQLValueResolver FallbackResolver
63+
{
64+
get
65+
{
66+
using (var locker = new UpgradeableReadLock(_lock))
67+
{
68+
if (_fallback == null)
69+
{
70+
locker.UpgradeToWriteLock();
71+
72+
_fallback = Resolvers.Single(x => x is DefaultValueResolver);
73+
}
74+
75+
return _fallback;
76+
}
77+
}
2478
}
2579
}
2680
}

src/Our.Umbraco.GraphQL/ValueResolvers/GridValueResolver.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44

55
namespace Our.Umbraco.GraphQL.ValueResolvers
66
{
7+
[DefaultGraphQLValueResolver]
78
public class GridValueResolver : GraphQLValueResolver
89
{
910
public override Type GetGraphQLType(PublishedPropertyType propertyType)
1011
{
1112
return typeof(GridGraphType);
1213
}
1314

14-
public override bool IsConverter(PublishedPropertyType propertyType)
15+
public override bool IsResolver(PublishedPropertyType propertyType)
1516
{
1617
return propertyType.PropertyEditorAlias == global::Umbraco.Core.Constants.PropertyEditors.GridAlias;
1718
}

0 commit comments

Comments
 (0)