Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests for filtering in combination with paging. #2317

Merged
merged 9 commits into from
Sep 26, 2020
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,66 @@
using System.Threading.Tasks;
using HotChocolate.Data.Filters;
using HotChocolate.Execution;
using Snapshooter.Xunit;
using Xunit;

namespace HotChocolate.Data
{
public class FilteringAndPaging
{
private static readonly Foo[] _fooEntities =
{
new Foo { Bar = true }, new Foo { Bar = false }
PascalSenn marked this conversation as resolved.
Show resolved Hide resolved
};

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.MatchSnapshot("true");

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

res2.MatchSnapshot("false");
}

PascalSenn marked this conversation as resolved.
Show resolved Hide resolved

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,14 @@
{
"Data": {
"root": {
"nodes": [
{
"bar": false
}
]
}
},
"Errors": null,
"Extensions": null,
"ContextData": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Data": {
"root": {
"nodes": [
{
"bar": true
}
]
}
},
"Errors": null,
"Extensions": null,
"ContextData": null
}
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
{
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.MatchSqlSnapshot("true");

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

res2.MatchSqlSnapshot("false");
}

PascalSenn marked this conversation as resolved.
Show resolved Hide resolved

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>
{
}
}
}