Skip to content

Commit 541b58f

Browse files
committed
Make query building injectable and extendable
1 parent c0823e0 commit 541b58f

File tree

51 files changed

+789
-622
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+789
-622
lines changed

benchmarks/Serialization/OperationsSerializationBenchmarks.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using JsonApiDotNetCore.Configuration;
44
using JsonApiDotNetCore.Middleware;
55
using JsonApiDotNetCore.Queries;
6-
using JsonApiDotNetCore.Queries.Internal;
76
using JsonApiDotNetCore.Resources;
87
using JsonApiDotNetCore.Serialization.Objects;
98

benchmarks/Serialization/ResourceSerializationBenchmarks.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using JsonApiDotNetCore.Middleware;
77
using JsonApiDotNetCore.Queries;
88
using JsonApiDotNetCore.Queries.Expressions;
9-
using JsonApiDotNetCore.Queries.Internal;
109
using JsonApiDotNetCore.Resources.Annotations;
1110
using JsonApiDotNetCore.Serialization.Objects;
1211

benchmarks/Serialization/SerializationBenchmarkBase.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using JsonApiDotNetCore.Configuration;
66
using JsonApiDotNetCore.Middleware;
77
using JsonApiDotNetCore.Queries;
8-
using JsonApiDotNetCore.Queries.Internal;
98
using JsonApiDotNetCore.Resources;
109
using JsonApiDotNetCore.Resources.Annotations;
1110
using JsonApiDotNetCore.Serialization.Response;

benchmarks/Tools/NeverResourceDefinitionAccessor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.Middleware;
44
using JsonApiDotNetCore.Queries.Expressions;
5+
using JsonApiDotNetCore.Queries.QueryableBuilding;
56
using JsonApiDotNetCore.Resources;
67
using JsonApiDotNetCore.Resources.Annotations;
78

@@ -13,6 +14,7 @@ namespace Benchmarks.Tools;
1314
internal sealed class NeverResourceDefinitionAccessor : IResourceDefinitionAccessor
1415
{
1516
bool IResourceDefinitionAccessor.IsReadOnlyRequest => throw new NotImplementedException();
17+
public IQueryableBuilder QueryableBuilder => throw new NotImplementedException();
1618

1719
public IImmutableSet<IncludeElementExpression> OnApplyIncludes(ResourceType resourceType, IImmutableSet<IncludeElementExpression> existingIncludes)
1820
{

src/Examples/NoEntityFrameworkExample/QueryLayerToLinqConverter.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
using System.Collections;
22
using System.Linq.Expressions;
33
using JsonApiDotNetCore.Queries;
4-
using JsonApiDotNetCore.Queries.Internal.QueryableBuilding;
4+
using JsonApiDotNetCore.Queries.QueryableBuilding;
55
using JsonApiDotNetCore.Resources;
66
using Microsoft.EntityFrameworkCore.Metadata;
77

88
namespace NoEntityFrameworkExample;
99

1010
internal sealed class QueryLayerToLinqConverter
1111
{
12-
private readonly IResourceFactory _resourceFactory;
1312
private readonly IModel _model;
13+
private readonly IQueryableBuilder _queryableBuilder;
1414

15-
public QueryLayerToLinqConverter(IResourceFactory resourceFactory, IModel model)
15+
public QueryLayerToLinqConverter(IModel model, IQueryableBuilder queryableBuilder)
1616
{
17-
_resourceFactory = resourceFactory;
1817
_model = model;
18+
_queryableBuilder = queryableBuilder;
1919
}
2020

2121
public IEnumerable<TResource> ApplyQueryLayer<TResource>(QueryLayer queryLayer, IEnumerable<TResource> resources)
@@ -26,10 +26,9 @@ public IEnumerable<TResource> ApplyQueryLayer<TResource>(QueryLayer queryLayer,
2626
converter.ConvertIncludesToSelections();
2727

2828
// Convert QueryLayer into LINQ expression.
29-
Expression source = ((IEnumerable)resources).AsQueryable().Expression;
30-
var nameFactory = new LambdaParameterNameFactory();
31-
var queryableBuilder = new QueryableBuilder(source, queryLayer.ResourceType.ClrType, typeof(Enumerable), nameFactory, _resourceFactory, _model);
32-
Expression expression = queryableBuilder.ApplyQuery(queryLayer);
29+
IQueryable source = ((IEnumerable)resources).AsQueryable();
30+
var context = QueryableBuilderContext.CreateRoot(source, typeof(Enumerable), _model, null);
31+
Expression expression = _queryableBuilder.ApplyQuery(queryLayer, context);
3332

3433
// Insert null checks to prevent a NullReferenceException during execution of expressions such as:
3534
// 'todoItems => todoItems.Where(todoItem => todoItem.Assignee.Id == 1)' when a TodoItem doesn't have an assignee.

src/Examples/NoEntityFrameworkExample/Repositories/InMemoryResourceRepository.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using JsonApiDotNetCore.Configuration;
22
using JsonApiDotNetCore.Queries;
33
using JsonApiDotNetCore.Queries.Expressions;
4-
using JsonApiDotNetCore.Queries.Internal.QueryableBuilding;
4+
using JsonApiDotNetCore.Queries.QueryableBuilding;
55
using JsonApiDotNetCore.Repositories;
66
using JsonApiDotNetCore.Resources;
77
using NoEntityFrameworkExample.Data;
@@ -25,12 +25,12 @@ public abstract class InMemoryResourceRepository<TResource, TId> : IResourceRead
2525
private readonly ResourceType _resourceType;
2626
private readonly QueryLayerToLinqConverter _queryLayerToLinqConverter;
2727

28-
protected InMemoryResourceRepository(IResourceGraph resourceGraph, IResourceFactory resourceFactory)
28+
protected InMemoryResourceRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
2929
{
3030
_resourceType = resourceGraph.GetResourceType<TResource>();
3131

3232
var model = new InMemoryModel(resourceGraph);
33-
_queryLayerToLinqConverter = new QueryLayerToLinqConverter(resourceFactory, model);
33+
_queryLayerToLinqConverter = new QueryLayerToLinqConverter(model, queryableBuilder);
3434
}
3535

3636
/// <inheritdoc />

src/Examples/NoEntityFrameworkExample/Repositories/PersonRepository.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
3-
using JsonApiDotNetCore.Resources;
3+
using JsonApiDotNetCore.Queries.QueryableBuilding;
44
using NoEntityFrameworkExample.Data;
55
using NoEntityFrameworkExample.Models;
66

@@ -9,8 +9,8 @@ namespace NoEntityFrameworkExample.Repositories;
99
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
1010
public sealed class PersonRepository : InMemoryResourceRepository<Person, long>
1111
{
12-
public PersonRepository(IResourceGraph resourceGraph, IResourceFactory resourceFactory)
13-
: base(resourceGraph, resourceFactory)
12+
public PersonRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
13+
: base(resourceGraph, queryableBuilder)
1414
{
1515
}
1616

src/Examples/NoEntityFrameworkExample/Repositories/TagRepository.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
3-
using JsonApiDotNetCore.Resources;
3+
using JsonApiDotNetCore.Queries.QueryableBuilding;
44
using NoEntityFrameworkExample.Data;
55
using NoEntityFrameworkExample.Models;
66

@@ -9,8 +9,8 @@ namespace NoEntityFrameworkExample.Repositories;
99
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
1010
public sealed class TagRepository : InMemoryResourceRepository<Tag, long>
1111
{
12-
public TagRepository(IResourceGraph resourceGraph, IResourceFactory resourceFactory)
13-
: base(resourceGraph, resourceFactory)
12+
public TagRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
13+
: base(resourceGraph, queryableBuilder)
1414
{
1515
}
1616

src/Examples/NoEntityFrameworkExample/Repositories/TodoItemRepository.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
3-
using JsonApiDotNetCore.Resources;
3+
using JsonApiDotNetCore.Queries.QueryableBuilding;
44
using NoEntityFrameworkExample.Data;
55
using NoEntityFrameworkExample.Models;
66

@@ -9,8 +9,8 @@ namespace NoEntityFrameworkExample.Repositories;
99
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
1010
public sealed class TodoItemRepository : InMemoryResourceRepository<TodoItem, long>
1111
{
12-
public TodoItemRepository(IResourceGraph resourceGraph, IResourceFactory resourceFactory)
13-
: base(resourceGraph, resourceFactory)
12+
public TodoItemRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
13+
: base(resourceGraph, queryableBuilder)
1414
{
1515
}
1616

src/Examples/NoEntityFrameworkExample/Services/InMemoryResourceService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using JsonApiDotNetCore.Errors;
44
using JsonApiDotNetCore.Queries;
55
using JsonApiDotNetCore.Queries.Expressions;
6-
using JsonApiDotNetCore.Queries.Internal.QueryableBuilding;
6+
using JsonApiDotNetCore.Queries.QueryableBuilding;
77
using JsonApiDotNetCore.Resources;
88
using JsonApiDotNetCore.Resources.Annotations;
99
using JsonApiDotNetCore.Services;
@@ -42,7 +42,7 @@ public abstract class InMemoryResourceService<TResource, TId> : IResourceQuerySe
4242
private readonly QueryLayerToLinqConverter _queryLayerToLinqConverter;
4343

4444
protected InMemoryResourceService(IJsonApiOptions options, IResourceGraph resourceGraph, IQueryLayerComposer queryLayerComposer,
45-
IResourceFactory resourceFactory, IPaginationContext paginationContext, IEnumerable<IQueryConstraintProvider> constraintProviders,
45+
IPaginationContext paginationContext, IEnumerable<IQueryConstraintProvider> constraintProviders, IQueryableBuilder queryableBuilder,
4646
ILoggerFactory loggerFactory)
4747
{
4848
_options = options;
@@ -54,7 +54,7 @@ protected InMemoryResourceService(IJsonApiOptions options, IResourceGraph resour
5454
_resourceType = resourceGraph.GetResourceType<TResource>();
5555

5656
var model = new InMemoryModel(resourceGraph);
57-
_queryLayerToLinqConverter = new QueryLayerToLinqConverter(resourceFactory, model);
57+
_queryLayerToLinqConverter = new QueryLayerToLinqConverter(model, queryableBuilder);
5858
}
5959

6060
/// <inheritdoc />

src/Examples/NoEntityFrameworkExample/Services/TodoItemService.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.Queries;
4+
using JsonApiDotNetCore.Queries.QueryableBuilding;
45
using JsonApiDotNetCore.Resources;
56
using NoEntityFrameworkExample.Data;
67
using NoEntityFrameworkExample.Models;
@@ -10,9 +11,9 @@ namespace NoEntityFrameworkExample.Services;
1011
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
1112
public sealed class TodoItemService : InMemoryResourceService<TodoItem, long>
1213
{
13-
public TodoItemService(IJsonApiOptions options, IResourceGraph resourceGraph, IQueryLayerComposer queryLayerComposer, IResourceFactory resourceFactory,
14-
IPaginationContext paginationContext, IEnumerable<IQueryConstraintProvider> constraintProviders, ILoggerFactory loggerFactory)
15-
: base(options, resourceGraph, queryLayerComposer, resourceFactory, paginationContext, constraintProviders, loggerFactory)
14+
public TodoItemService(IJsonApiOptions options, IResourceGraph resourceGraph, IQueryLayerComposer queryLayerComposer, IPaginationContext paginationContext,
15+
IEnumerable<IQueryConstraintProvider> constraintProviders, IQueryableBuilder queryableBuilder, ILoggerFactory loggerFactory)
16+
: base(options, resourceGraph, queryLayerComposer, paginationContext, constraintProviders, queryableBuilder, loggerFactory)
1617
{
1718
}
1819

src/JsonApiDotNetCore/AtomicOperations/OperationsProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.Errors;
44
using JsonApiDotNetCore.Middleware;
5-
using JsonApiDotNetCore.Queries.Internal;
5+
using JsonApiDotNetCore.Queries;
66
using JsonApiDotNetCore.Resources;
77
using JsonApiDotNetCore.Serialization.Objects;
88

src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
using JsonApiDotNetCore.AtomicOperations.Processors;
33
using JsonApiDotNetCore.Middleware;
44
using JsonApiDotNetCore.Queries;
5-
using JsonApiDotNetCore.Queries.Internal;
65
using JsonApiDotNetCore.Queries.Parsing;
6+
using JsonApiDotNetCore.Queries.QueryableBuilding;
77
using JsonApiDotNetCore.QueryStrings;
88
using JsonApiDotNetCore.QueryStrings.Internal;
99
using JsonApiDotNetCore.Repositories;
@@ -194,6 +194,13 @@ private void AddRepositoryLayer()
194194
RegisterImplementationForInterfaces(ServiceDiscoveryFacade.RepositoryUnboundInterfaces, typeof(EntityFrameworkCoreRepository<,>));
195195

196196
_services.AddScoped<IResourceRepositoryAccessor, ResourceRepositoryAccessor>();
197+
198+
_services.TryAddTransient<IQueryableBuilder, QueryableBuilder>();
199+
_services.TryAddTransient<IIncludeClauseBuilder, IncludeClauseBuilder>();
200+
_services.TryAddTransient<IOrderClauseBuilder, OrderClauseBuilder>();
201+
_services.TryAddTransient<ISelectClauseBuilder, SelectClauseBuilder>();
202+
_services.TryAddTransient<ISkipTakeClauseBuilder, SkipTakeClauseBuilder>();
203+
_services.TryAddTransient<IWhereClauseBuilder, WhereClauseBuilder>();
197204
}
198205

199206
private void AddServiceLayer()

src/JsonApiDotNetCore/Queries/Internal/EvaluatedIncludeCache.cs renamed to src/JsonApiDotNetCore/Queries/EvaluatedIncludeCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using JsonApiDotNetCore.Queries.Expressions;
22

3-
namespace JsonApiDotNetCore.Queries.Internal;
3+
namespace JsonApiDotNetCore.Queries;
44

55
/// <inheritdoc />
66
internal sealed class EvaluatedIncludeCache : IEvaluatedIncludeCache

src/JsonApiDotNetCore/Queries/Internal/IEvaluatedIncludeCache.cs renamed to src/JsonApiDotNetCore/Queries/IEvaluatedIncludeCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using JsonApiDotNetCore.Queries.Expressions;
22
using JsonApiDotNetCore.Resources;
33

4-
namespace JsonApiDotNetCore.Queries.Internal;
4+
namespace JsonApiDotNetCore.Queries;
55

66
/// <summary>
77
/// Provides in-memory storage for the evaluated inclusion tree within a request. This tree is produced from query string and resource definition

src/JsonApiDotNetCore/Queries/Internal/ISparseFieldSetCache.cs renamed to src/JsonApiDotNetCore/Queries/ISparseFieldSetCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using JsonApiDotNetCore.Resources;
44
using JsonApiDotNetCore.Resources.Annotations;
55

6-
namespace JsonApiDotNetCore.Queries.Internal;
6+
namespace JsonApiDotNetCore.Queries;
77

88
/// <summary>
99
/// Takes sparse fieldsets from <see cref="IQueryConstraintProvider" />s and invokes

src/JsonApiDotNetCore/Queries/Internal/QueryableBuilding/LambdaParameterNameFactory.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/JsonApiDotNetCore/Queries/Internal/QueryableBuilding/LambdaParameterNameScope.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/JsonApiDotNetCore/Queries/Internal/QueryableBuilding/LambdaScope.cs

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)