Skip to content

Commit

Permalink
Added Spatial Filters (#2541)
Browse files Browse the repository at this point in the history
Co-authored-by: Pascal Senn <senn.pasc@gmail.com>
Co-authored-by: steveoh <sgourley@utah.gov>
  • Loading branch information
3 people committed Nov 5, 2020
1 parent ad6cf46 commit 2f0169c
Show file tree
Hide file tree
Showing 145 changed files with 7,602 additions and 448 deletions.
2 changes: 2 additions & 0 deletions .build/Helpers.cs
Expand Up @@ -30,6 +30,8 @@ public static IEnumerable<string> GetAllProjects(string sourceDirectory)
foreach (var file in Directory.EnumerateFiles(fullDirectory, "*.csproj", SearchOption.AllDirectories))
{
if (file.Contains("benchmark", StringComparison.OrdinalIgnoreCase)
|| file.Contains("demo", StringComparison.OrdinalIgnoreCase)
|| file.Contains("sample", StringComparison.OrdinalIgnoreCase)
|| file.Contains("HotChocolate.Core.Tests", StringComparison.OrdinalIgnoreCase)
|| file.Contains("HotChocolate.Utilities.Introspection.Tests", StringComparison.OrdinalIgnoreCase)
|| file.Contains("HotChocolate.Types.Selection", StringComparison.OrdinalIgnoreCase))
Expand Down
6 changes: 6 additions & 0 deletions src/HotChocolate/Data/src/Data/DataResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/HotChocolate/Data/src/Data/DataResources.resx
Expand Up @@ -200,4 +200,7 @@
<data name="ProjectionConvention_CouldNotProject" xml:space="preserve">
<value>Projection Visitor is in invalid state. Projection failed!</value>
</data>
<data name="FilterConvention_ProviderHasToBeInitializedByConvention" xml:space="preserve">
<value>The filter provider {0} {1}was not initialized by a convention. It is only valid to register a provider over a FilterConvention</value>
</data>
</root>
Expand Up @@ -8,7 +8,6 @@
using HotChocolate.Resolvers;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors;
using HotChocolate.Types.Descriptors.Definitions;
using HotChocolate.Utilities;
using static HotChocolate.Data.DataResources;
using static HotChocolate.Data.ThrowHelper;
Expand Down Expand Up @@ -99,7 +98,7 @@ protected override void OnComplete(IConventionContext context)
{
IReadOnlyList<IFilterProviderExtension> extensions =
CollectExtensions(context.Services, Definition);
init.Initialize(context);
init.Initialize(context, this);
MergeExtensions(context, init, extensions);
init.OnComplete(context);
}
Expand Down Expand Up @@ -283,7 +282,7 @@ public NameString GetOperationName(int operation)
return extensions;
}

private static void MergeExtensions(
private void MergeExtensions(
IConventionContext context,
IFilterProviderConvention provider,
IReadOnlyList<IFilterProviderExtension> extensions)
Expand All @@ -294,7 +293,7 @@ public NameString GetOperationName(int operation)
{
if (extensions[m] is IFilterProviderConvention extensionConvention)
{
extensionConvention.Initialize(context);
extensionConvention.Initialize(context, this);
extensions[m].Merge(context, providerConvention);
extensionConvention.OnComplete(context);
}
Expand Down
Expand Up @@ -6,13 +6,15 @@ namespace HotChocolate.Data.Filters.Expressions
public class QueryableDataOperationHandler
: FilterFieldHandler<QueryableFilterContext, Expression>
{
protected virtual int Operation => DefaultOperations.Data;

public override bool CanHandle(
ITypeDiscoveryContext context,
IFilterInputTypeDefinition typeDefinition,
IFilterFieldDefinition fieldDefinition)
{
return fieldDefinition is FilterOperationFieldDefinition def &&
def.Id == DefaultOperations.Data;
def.Id == Operation;
}
}
}
Expand Up @@ -41,4 +41,4 @@ public static class DefaultOperations

public const int Data = 29;
}
}
}
18 changes: 16 additions & 2 deletions src/HotChocolate/Data/src/Data/Filters/Visitor/FilterProvider.cs
Expand Up @@ -20,6 +20,8 @@ public abstract class FilterProvider<TContext>

private Action<IFilterProviderDescriptor<TContext>>? _configure;

private IFilterConvention? _filterConvention;

protected FilterProvider()
{
_configure = Configure;
Expand Down Expand Up @@ -50,8 +52,11 @@ protected override FilterProviderDefinition CreateDefinition(IConventionContext
return descriptor.CreateDefinition();
}

void IFilterProviderConvention.Initialize(IConventionContext context)
void IFilterProviderConvention.Initialize(
IConventionContext context,
IFilterConvention convention)
{
_filterConvention = convention;
base.Initialize(context);
}

Expand All @@ -67,10 +72,18 @@ protected override void OnComplete(IConventionContext context)
throw FilterProvider_NoHandlersConfigured(this);
}

if (_filterConvention is null)
{
throw FilterConvention_ProviderHasToBeInitializedByConvention(
GetType(),
context.Scope);
}

IServiceProvider services = new DictionaryServiceProvider(
(typeof(IFilterProvider), this),
(typeof(IConventionContext), context),
(typeof(IDescriptorContext), context.DescriptorContext),
(typeof(IFilterConvention), _filterConvention),
(typeof(ITypeInspector), context.DescriptorContext.TypeInspector))
.Include(context.Services);

Expand All @@ -96,7 +109,8 @@ protected override void OnComplete(IConventionContext context)

protected virtual void Configure(IFilterProviderDescriptor<TContext> descriptor) { }

public abstract FieldMiddleware CreateExecutor<TEntityType>(NameString argumentName);
public abstract FieldMiddleware CreateExecutor<TEntityType>(
NameString argumentName);

public virtual void ConfigureField(
NameString argumentName,
Expand Down
Expand Up @@ -23,7 +23,9 @@ public FilterProviderExtensions(Action<IFilterProviderDescriptor<TContext>> conf
throw new ArgumentNullException(nameof(configure));
}

void IFilterProviderConvention.Initialize(IConventionContext context)
void IFilterProviderConvention.Initialize(
IConventionContext context,
IFilterConvention convention)
{
base.Initialize(context);
}
Expand Down
Expand Up @@ -4,7 +4,7 @@ namespace HotChocolate.Data.Filters
{
internal interface IFilterProviderConvention
{
internal void Initialize(IConventionContext context);
internal void Initialize(IConventionContext context, IFilterConvention convention);

internal void OnComplete(IConventionContext context);
}
Expand Down
12 changes: 12 additions & 0 deletions src/HotChocolate/Data/src/Data/ThrowHelper.cs
Expand Up @@ -38,6 +38,18 @@ internal static class ThrowHelper
.SetExtension(nameof(scope), scope)
.Build());

public static SchemaException FilterConvention_ProviderHasToBeInitializedByConvention(
Type provider,
string? scope) =>
new SchemaException(
SchemaErrorBuilder.New()
.SetMessage(
DataResources.FilterConvention_ProviderHasToBeInitializedByConvention,
provider.FullName ?? provider.Name,
scope is null ? "" : "in scope " + scope)
.SetExtension(nameof(scope), scope)
.Build());

public static SchemaException FilterProvider_NoHandlersConfigured(
IFilterProvider filterProvider) =>
new SchemaException(
Expand Down
Expand Up @@ -3,6 +3,8 @@
using HotChocolate.Data.Filters.Expressions;
using HotChocolate.Language;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors;
using Microsoft.Extensions.DependencyInjection;
using Snapshooter;
using Snapshooter.Xunit;
using Xunit;
Expand Down Expand Up @@ -348,6 +350,26 @@ public void FilterConvention_Should_Work_With_ProviderExtensionsType()
Assert.False(func(b));
}

[Fact]
public void FilterProvider_Throws_Exception_When_NotInitializedByConvention()
{
// arrange
var provider = new QueryableFilterProvider(
descriptor => descriptor.AddFieldHandler<QueryableStringEqualsHandler>());
var context = ConventionContext.Create(
null,
new ServiceCollection().BuildServiceProvider(),
DescriptorContext.Create());

// act
provider.Initialize(context);

// assert
SchemaException exception =
Assert.Throws<SchemaException>(() => provider.OnComplete(context));
exception.Message.MatchSnapshot();
}

protected ISchema CreateSchemaWithTypes(
IFilterInputType type,
FilterConvention convention,
Expand Down
@@ -0,0 +1,3 @@
For more details look at the `Errors` property.

1. The filter provider HotChocolate.Data.Filters.Expressions.QueryableFilterProvider was not initialized by a convention. It is only valid to register a provider over a FilterConvention
Expand Up @@ -59,7 +59,7 @@ private class OrderingMethodFinder : ExpressionVisitor
{
private bool _orderingMethodFound = false;

public override Expression Visit(Expression node)
public override Expression? Visit(Expression? node)
{
if (_orderingMethodFound)
{
Expand Down
Expand Up @@ -25,25 +25,22 @@ public static class SortingFieldCollectionExtensions
throw new ArgumentNullException(nameof(valueFactory));
}

SortOperationDescriptorBase fieldDescriptor =
fields.FirstOrDefault(
t => t.Definition?.Operation?.Property.Equals(propertyInfo) ?? false);
SortOperationDescriptorBase? fieldDescriptor = fields.FirstOrDefault(
t => t.Definition.Operation?.Property.Equals(propertyInfo) ?? false);

if (fieldDescriptor is { })
{
if (fieldDescriptor is T descritorOfT)
{
return descritorOfT;
}
else
{
fields.Remove(fieldDescriptor);
}

fields.Remove(fieldDescriptor);
}

T newDescirptor = valueFactory.Invoke();
fields.Add(newDescirptor);
return newDescirptor;
T newDescriptor = valueFactory.Invoke();
fields.Add(newDescriptor);
return newDescriptor;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -123,4 +123,7 @@
<data name="SortObjectTypeVisitor_InvalidType" xml:space="preserve">
<value>The visited type is invalid. Only InputObjectType is allowed.</value>
</data>
<data name="SortInputTypeDescriptor_Ignore_OnlyPopertiesAreAllowed" xml:space="preserve">
<value>Only properties are allowed for input types.</value>
</data>
</root>
Expand Up @@ -25,9 +25,9 @@ public async Task InvokeAsync(IMiddlewareContext context)
{
await _next(context).ConfigureAwait(false);

IValueNode sortArgument = context.Argument<IValueNode>(_contextData.ArgumentName);
IValueNode sortArgument = context.ArgumentLiteral<IValueNode>(_contextData.ArgumentName);

if (sortArgument is null || sortArgument is NullValueNode)
if (sortArgument is NullValueNode)
{
return;
}
Expand All @@ -45,8 +45,7 @@ public async Task InvokeAsync(IMiddlewareContext context)

if (source is not null &&
context.Field.Arguments[_contextData.ArgumentName].Type is InputObjectType iot &&
iot is ISortInputType fit &&
fit.EntityType is { })
iot is ISortInputType { EntityType: not null! } fit)
{
var visitorCtx = new QueryableSortVisitorContext(
iot,
Expand Down

0 comments on commit 2f0169c

Please sign in to comment.