Skip to content

Open up some members for extensibility. #927

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

Merged
merged 1 commit into from
Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace JsonApiDotNetCore.Queries.Internal.QueryableBuilding
/// <summary>
/// Drives conversion from <see cref="QueryLayer"/> into system <see cref="Expression"/> trees.
/// </summary>
public sealed class QueryableBuilder
public class QueryableBuilder
{
private readonly Expression _source;
private readonly Type _elementType;
Expand All @@ -38,7 +38,7 @@ public QueryableBuilder(Expression source, Type elementType, Type extensionType,
_lambdaScopeFactory = lambdaScopeFactory ?? new LambdaScopeFactory(_nameFactory);
}

public Expression ApplyQuery(QueryLayer layer)
public virtual Expression ApplyQuery(QueryLayer layer)
{
if (layer == null) throw new ArgumentNullException(nameof(layer));

Expand Down Expand Up @@ -72,39 +72,39 @@ public Expression ApplyQuery(QueryLayer layer)
return expression;
}

private Expression ApplyInclude(Expression source, IncludeExpression include, ResourceContext resourceContext)
protected virtual Expression ApplyInclude(Expression source, IncludeExpression include, ResourceContext resourceContext)
{
using var lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

var builder = new IncludeClauseBuilder(source, lambdaScope, resourceContext, _resourceContextProvider);
return builder.ApplyInclude(include);
}

private Expression ApplyFilter(Expression source, FilterExpression filter)
protected virtual Expression ApplyFilter(Expression source, FilterExpression filter)
{
using var lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

var builder = new WhereClauseBuilder(source, lambdaScope, _extensionType);
return builder.ApplyWhere(filter);
}

private Expression ApplySort(Expression source, SortExpression sort)
protected virtual Expression ApplySort(Expression source, SortExpression sort)
{
using var lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

var builder = new OrderClauseBuilder(source, lambdaScope, _extensionType);
return builder.ApplyOrderBy(sort);
}

private Expression ApplyPagination(Expression source, PaginationExpression pagination)
protected virtual Expression ApplyPagination(Expression source, PaginationExpression pagination)
{
using var lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

var builder = new SkipTakeClauseBuilder(source, lambdaScope, _extensionType);
return builder.ApplySkipTake(pagination);
}

private Expression ApplyProjection(Expression source, IDictionary<ResourceFieldAttribute, QueryLayer> projection, ResourceContext resourceContext)
protected virtual Expression ApplyProjection(Expression source, IDictionary<ResourceFieldAttribute, QueryLayer> projection, ResourceContext resourceContext)
{
using var lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

Expand Down
26 changes: 13 additions & 13 deletions src/JsonApiDotNetCore/Repositories/ResourceRepositoryAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public ResourceRepositoryAccessor(IServiceProvider serviceProvider, IResourceCon
public async Task<IReadOnlyCollection<TResource>> GetAsync<TResource>(QueryLayer layer, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetReadRepository(typeof(TResource));
dynamic repository = ResolveReadRepository(typeof(TResource));
return (IReadOnlyCollection<TResource>) await repository.GetAsync(layer, cancellationToken);
}

Expand All @@ -35,83 +35,83 @@ public async Task<IReadOnlyCollection<IIdentifiable>> GetAsync(Type resourceType
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic repository = GetReadRepository(resourceType);
dynamic repository = ResolveReadRepository(resourceType);
return (IReadOnlyCollection<IIdentifiable>) await repository.GetAsync(layer, cancellationToken);
}

/// <inheritdoc />
public async Task<int> CountAsync<TResource>(FilterExpression topFilter, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetReadRepository(typeof(TResource));
dynamic repository = ResolveReadRepository(typeof(TResource));
return (int) await repository.CountAsync(topFilter, cancellationToken);
}

/// <inheritdoc />
public async Task<TResource> GetForCreateAsync<TResource, TId>(TId id, CancellationToken cancellationToken)
where TResource : class, IIdentifiable<TId>
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
return await repository.GetForCreateAsync(id, cancellationToken);
}

/// <inheritdoc />
public async Task CreateAsync<TResource>(TResource resourceFromRequest, TResource resourceForDatabase, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
await repository.CreateAsync(resourceFromRequest, resourceForDatabase, cancellationToken);
}

/// <inheritdoc />
public async Task<TResource> GetForUpdateAsync<TResource>(QueryLayer queryLayer, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
return await repository.GetForUpdateAsync(queryLayer, cancellationToken);
}

/// <inheritdoc />
public async Task UpdateAsync<TResource>(TResource resourceFromRequest, TResource resourceFromDatabase, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
await repository.UpdateAsync(resourceFromRequest, resourceFromDatabase, cancellationToken);
}

/// <inheritdoc />
public async Task DeleteAsync<TResource, TId>(TId id, CancellationToken cancellationToken)
where TResource : class, IIdentifiable<TId>
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
await repository.DeleteAsync(id, cancellationToken);
}

/// <inheritdoc />
public async Task SetRelationshipAsync<TResource>(TResource primaryResource, object secondaryResourceIds, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
await repository.SetRelationshipAsync(primaryResource, secondaryResourceIds, cancellationToken);
}

/// <inheritdoc />
public async Task AddToToManyRelationshipAsync<TResource, TId>(TId primaryId, ISet<IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken)
where TResource : class, IIdentifiable<TId>
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
await repository.AddToToManyRelationshipAsync(primaryId, secondaryResourceIds, cancellationToken);
}

/// <inheritdoc />
public async Task RemoveFromToManyRelationshipAsync<TResource>(TResource primaryResource, ISet<IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken)
where TResource : class, IIdentifiable
{
dynamic repository = GetWriteRepository(typeof(TResource));
dynamic repository = ResolveWriteRepository(typeof(TResource));
await repository.RemoveFromToManyRelationshipAsync(primaryResource, secondaryResourceIds, cancellationToken);
}

protected object GetReadRepository(Type resourceType)
protected virtual object ResolveReadRepository(Type resourceType)
{
var resourceContext = _resourceContextProvider.GetResourceContext(resourceType);

Expand All @@ -130,7 +130,7 @@ protected object GetReadRepository(Type resourceType)
return _serviceProvider.GetRequiredService(resourceDefinitionType);
}

protected object GetWriteRepository(Type resourceType)
protected virtual object ResolveWriteRepository(Type resourceType)
{
var resourceContext = _resourceContextProvider.GetResourceContext(resourceType);

Expand Down
16 changes: 8 additions & 8 deletions src/JsonApiDotNetCore/Resources/ResourceDefinitionAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public IReadOnlyCollection<IncludeElementExpression> OnApplyIncludes(Type resour
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
return resourceDefinition.OnApplyIncludes(existingIncludes);
}

Expand All @@ -32,7 +32,7 @@ public FilterExpression OnApplyFilter(Type resourceType, FilterExpression existi
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
return resourceDefinition.OnApplyFilter(existingFilter);
}

Expand All @@ -41,7 +41,7 @@ public SortExpression OnApplySort(Type resourceType, SortExpression existingSort
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
return resourceDefinition.OnApplySort(existingSort);
}

Expand All @@ -50,7 +50,7 @@ public PaginationExpression OnApplyPagination(Type resourceType, PaginationExpre
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
return resourceDefinition.OnApplyPagination(existingPagination);
}

Expand All @@ -59,7 +59,7 @@ public SparseFieldSetExpression OnApplySparseFieldSet(Type resourceType, SparseF
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
return resourceDefinition.OnApplySparseFieldSet(existingSparseFieldSet);
}

Expand All @@ -69,7 +69,7 @@ public object GetQueryableHandlerForQueryStringParameter(Type resourceType, stri
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));
if (parameterName == null) throw new ArgumentNullException(nameof(parameterName));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
var handlers = resourceDefinition.OnRegisterQueryableHandlersForQueryStringParameters();

return handlers != null && handlers.ContainsKey(parameterName) ? handlers[parameterName] : null;
Expand All @@ -80,11 +80,11 @@ public IDictionary<string, object> GetMeta(Type resourceType, IIdentifiable reso
{
if (resourceType == null) throw new ArgumentNullException(nameof(resourceType));

dynamic resourceDefinition = GetResourceDefinition(resourceType);
dynamic resourceDefinition = ResolveResourceDefinition(resourceType);
return resourceDefinition.GetMeta((dynamic) resourceInstance);
}

protected object GetResourceDefinition(Type resourceType)
protected virtual object ResolveResourceDefinition(Type resourceType)
{
var resourceContext = _resourceContextProvider.GetResourceContext(resourceType);

Expand Down