Skip to content

Commit

Permalink
Added tests for filtering in combination with paging. (#2317)
Browse files Browse the repository at this point in the history
  • Loading branch information
PascalSenn committed Sep 26, 2020
1 parent a127779 commit 5b478a9
Show file tree
Hide file tree
Showing 38 changed files with 371 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using HotChocolate.Resolvers;
using HotChocolate.Types;
using System.Linq;
using HotChocolate.Types.Relay;

namespace HotChocolate.Data.Filters
{
Expand All @@ -26,7 +27,8 @@ public FilterVisitorTestBase()

protected IRequestExecutor CreateSchema<TEntity, T>(
TEntity[] entities,
FilterConvention? convention = null)
FilterConvention? convention = null,
bool withPaging = false)
where TEntity : class
where T : FilterInputType<TEntity>
{
Expand All @@ -37,13 +39,23 @@ public FilterVisitorTestBase()
ISchemaBuilder builder = SchemaBuilder.New()
.AddConvention<IFilterConvention>(convention)
.AddFiltering()
.AddQueryType(c => c
.Name("Query")
.Field("root")
.Resolver(resolver)
.UseFiltering<T>());

ISchema? schema = builder.Create();
.AddQueryType(
c =>
{
IObjectFieldDescriptor field = c
.Name("Query")
.Field("root")
.Resolver(resolver);
if (withPaging)
{
field.UsePaging<ObjectType<TEntity>>();
}
field.UseFiltering<T>();
});

ISchema schema = builder.Create();

return schema.MakeExecutable();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.Threading.Tasks;
using HotChocolate.Data.Filters;
using HotChocolate.Execution;
using Snapshooter;
using Snapshooter.Xunit;
using Xunit;

namespace HotChocolate.Data.Filters
{
public class FilteringAndPaging
{
private static readonly Foo[] _fooEntities =
{
new Foo { Bar = true },
new Foo { Bar = false }
};

private readonly SchemaCache _cache = new SchemaCache();

[Fact]
public async Task Create_BooleanEqual_Expression()
{
// arrange
IRequestExecutor tester = _cache.CreateSchema<Foo, FooFilterType>(_fooEntities, true);

// act
// assert
IExecutionResult res1 = await tester.ExecuteAsync(
QueryRequestBuilder.New()
.SetQuery("{ root(where: { bar: { eq: true}}){ nodes { bar } }}")
.Create());

res1.ToJson().MatchSnapshot(new SnapshotNameExtension("true"));

IExecutionResult res2 = await tester.ExecuteAsync(
QueryRequestBuilder.New()
.SetQuery("{ root(where: { bar: { eq: false}}){ nodes { bar }}}")
.Create());

res2.ToJson().MatchSnapshot(new SnapshotNameExtension("false"));
}

public class Foo
{
public int Id { get; set; }

public bool Bar { get; set; }
}

public class FooNullable
{
public int Id { get; set; }

public bool? Bar { get; set; }
}

public class FooFilterType
: FilterInputType<Foo>
{
}

public class FooNullableFilterType
: FilterInputType<FooNullable>
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,21 @@

namespace HotChocolate.Data.Filters
{
public class SchemaCache : FilterVisitorTestBase, IDisposable
public class SchemaCache
: FilterVisitorTestBase
, IDisposable
{
private readonly ConcurrentDictionary<(Type, Type, object), IRequestExecutor> _cache =
new ConcurrentDictionary<(Type, Type, object), IRequestExecutor>();

public SchemaCache()
: base()
{

}

public IRequestExecutor CreateSchema<T, TType>(T[] entites)
public IRequestExecutor CreateSchema<T, TType>(T[] entities, bool withPaging = false)
where T : class
where TType : FilterInputType<T>
{
(Type, Type, T[] entites) key = (typeof(T), typeof(TType), entites);
return _cache.GetOrAdd(key, (k) => base.CreateSchema<T, TType>(entites));
(Type, Type, T[] entites) key = (typeof(T), typeof(TType), entities);
return _cache.GetOrAdd(
key,
k => base.CreateSchema<T, TType>(entities, withPaging: withPaging));
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"data": {
"root": {
"nodes": [
{
"bar": false
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"data": {
"root": {
"nodes": [
{
"bar": true
}
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using HotChocolate.Execution.Configuration;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using HotChocolate.Types.Relay;
using Microsoft.Extensions.DependencyInjection;

namespace HotChocolate.Data.Filters
Expand Down Expand Up @@ -42,7 +43,8 @@ public class FilterVisitorTestBase

protected IRequestExecutor CreateSchema<TEntity, T>(
TEntity[] entities,
FilterConvention? convention = null)
FilterConvention? convention = null,
bool withPaging = false)
where TEntity : class
where T : FilterInputType<TEntity>
{
Expand All @@ -54,47 +56,60 @@ public class FilterVisitorTestBase
.AddConvention<IFilterConvention>(convention)
.AddFiltering()
.AddQueryType(
c => c
.Name("Query")
.Field("root")
.Resolver(resolver)
.Use(next => async context =>
c =>
{
IObjectFieldDescriptor field = c
.Name("Query")
.Field("root")
.Resolver(resolver)
.Use(
next => async context =>
{
await next(context);
if (context.Result is IQueryable<TEntity> queryable)
{
try
{
context.ContextData["sql"] = queryable.ToQueryString();
}
catch (Exception)
{
context.ContextData["sql"] =
"EF Core 3.1 does not support ToQueryString";
}
}
});
if (withPaging)
{
await next(context);
field.UsePaging<ObjectType<TEntity>>();
}
if (context.Result is IQueryable<TEntity> queryable)
{
try
{
context.ContextData["sql"] = queryable.ToQueryString();
}
catch (Exception)
{
context.ContextData["sql"] =
"EF Core 3.1 does not support ToQuerString offically";
}
}
})
.UseFiltering<T>());
field.UseFiltering<T>();
});

ISchema? schema = builder.Create();
ISchema schema = builder.Create();

return new ServiceCollection()
.Configure<RequestExecutorFactoryOptions>(Schema.DefaultName, o => o.Schema = schema)
.Configure<RequestExecutorFactoryOptions>(
Schema.DefaultName,
o => o.Schema = schema)
.AddGraphQL()
.UseRequest(next => async context =>
{
await next(context);
if (context.Result is IReadOnlyQueryResult result &&
context.ContextData.TryGetValue("sql", out var queryString))
.UseRequest(
next => async context =>
{
context.Result =
QueryResultBuilder
.FromResult(result)
.SetContextData("sql", queryString)
.Create();
}
})
await next(context);
if (context.Result is IReadOnlyQueryResult result &&
context.ContextData.TryGetValue("sql", out var queryString))
{
context.Result =
QueryResultBuilder
.FromResult(result)
.SetContextData("sql", queryString)
.Create();
}
})
.UseDefaultPipeline()
.Services
.BuildServiceProvider()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Threading.Tasks;
using HotChocolate.Data.Filters;
using HotChocolate.Execution;
using Xunit;

namespace HotChocolate.Data.Filters
{
public class FilteringAndPaging
{
private static readonly Foo[] _fooEntities =
{
new Foo { Bar = true },
new Foo { Bar = false }
};

private readonly SchemaCache _cache = new SchemaCache();

[Fact]
public async Task Create_BooleanEqual_Expression()
{
// arrange
IRequestExecutor tester = _cache.CreateSchema<Foo, FooFilterType>(_fooEntities, true);

// act
IExecutionResult res1 = await tester.ExecuteAsync(
QueryRequestBuilder.New()
.SetQuery("{ root(where: { bar: { eq: true}}){ nodes { bar } }}")
.Create());

IExecutionResult res2 = await tester.ExecuteAsync(
QueryRequestBuilder.New()
.SetQuery("{ root(where: { bar: { eq: false}}){ nodes { bar }}}")
.Create());

// assert
res1.MatchSqlSnapshot("true");
res2.MatchSqlSnapshot("false");
}


public class Foo
{
public int Id { get; set; }

public bool Bar { get; set; }
}

public class FooNullable
{
public int Id { get; set; }

public bool? Bar { get; set; }
}

public class FooFilterType
: FilterInputType<Foo>
{
}

public class FooNullableFilterType
: FilterInputType<FooNullable>
{
}
}
}

0 comments on commit 5b478a9

Please sign in to comment.