Skip to content

Query Parameter Services #574

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 17 commits into from
Oct 15, 2019
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
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,14 @@ charset = utf-8

[*.{csproj,props}]
indent_size = 2

[*.{cs,vb}]
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_naming_rule.private_members_with_underscore.severity = suggestion

dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private

dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
2 changes: 1 addition & 1 deletion benchmarks/Query/QueryParser_Benchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private void Run(int iterations, Action action) {
}

// this facade allows us to expose and micro-benchmark protected methods
private class BenchmarkFacade : QueryParser {
private class BenchmarkFacade : QueryParameterDiscovery {
public BenchmarkFacade(
IRequestContext currentRequest,
JsonApiOptions options) : base(currentRequest, options) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class ContainsMediaTypeParameters_Benchmarks

[Benchmark]
public void Current()
=> JsonApiDotNetCore.Middleware.RequestMiddleware.ContainsMediaTypeParameters(MEDIA_TYPE);
=> JsonApiDotNetCore.Middleware.CurrentRequestMiddleware.ContainsMediaTypeParameters(MEDIA_TYPE);

private bool UsingSplitImpl(string mediaType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"launchUrl": "http://localhost:5000/api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"applicationUrl": "http://localhost:5000/"
}
}
}
14 changes: 7 additions & 7 deletions src/Examples/JsonApiDotNetCoreExample/Resources/UserResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ public override QueryFilters GetQueryFilters()

private IQueryable<User> FirstCharacterFilter(IQueryable<User> users, FilterQuery filterQuery)
{
switch(filterQuery.Operation)
{
case "lt":
return users.Where(u => u.Username[0] < filterQuery.Value[0]);
default:
return users.Where(u => u.Username[0] == filterQuery.Value[0]);
}
switch (filterQuery.Operation)
{
case "lt":
return users.Where(u => u.Username[0] < filterQuery.Value[0]);
default:
return users.Where(u => u.Username[0] == filterQuery.Value[0]);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,19 @@ namespace JsonApiDotNetCoreExample.Services
{
public class CustomArticleService : EntityResourceService<Article>
{
public CustomArticleService(IEntityRepository<Article, int> repository, IJsonApiOptions options,
ITargetedFields updatedFields, ICurrentRequest currentRequest,
IIncludeService includeService, ISparseFieldsService sparseFieldsService,
IPageQueryService pageManager, IResourceGraph resourceGraph,
IResourceHookExecutor hookExecutor = null, ILoggerFactory loggerFactory = null)
: base(repository, options, updatedFields, currentRequest, includeService, sparseFieldsService, pageManager, resourceGraph, hookExecutor, loggerFactory)
public CustomArticleService(ISortService sortService,
IFilterService filterService,
IEntityRepository<Article, int> repository,
IJsonApiOptions options,
ICurrentRequest currentRequest,
IIncludeService includeService,
ISparseFieldsService sparseFieldsService,
IPageService pageManager,
IResourceGraph resourceGraph,
IResourceHookExecutor hookExecutor = null,
ILoggerFactory loggerFactory = null)
: base(sortService, filterService, repository, options, currentRequest, includeService, sparseFieldsService,
pageManager, resourceGraph, hookExecutor, loggerFactory)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@
}
},
"profiles": {
"NoEntityFrameworkExample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:5000/"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"NoEntityFrameworkExample": {
"commandName": "Project",
"environmentVariables": {}
}
}
}
14 changes: 7 additions & 7 deletions src/Examples/ReportsExample/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ReportsExample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:55654/"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
6 changes: 0 additions & 6 deletions src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Extensions;
Expand Down Expand Up @@ -51,13 +50,8 @@ public BaseJsonApiController(
_update = resourceService;
_updateRelationships = resourceService;
_delete = resourceService;
ParseQueryParams();
}

private void ParseQueryParams()
{

}

public BaseJsonApiController(
IJsonApiOptions jsonApiOptions,
Expand Down
21 changes: 18 additions & 3 deletions src/JsonApiDotNetCore/Controllers/DisableQueryAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,27 @@
namespace JsonApiDotNetCore.Controllers
{
public class DisableQueryAttribute : Attribute
{
{
/// <summary>
/// Disabled one of the native query parameters for a controller.
/// </summary>
/// <param name="queryParams"></param>
public DisableQueryAttribute(QueryParams queryParams)
{
QueryParams = queryParams;
QueryParams = queryParams.ToString("G").ToLower();
}

public QueryParams QueryParams { get; set; }
/// <summary>
/// It is allowed to use strings to indicate which query parameters
/// should be disabled, because the user may have defined a custom
/// query parameter that is not included in the <see cref="QueryParams"/> enum.
/// </summary>
/// <param name="customQueryParams"></param>
public DisableQueryAttribute(string customQueryParams)
{
QueryParams = customQueryParams.ToLower();
}

public string QueryParams { get; }
}
}
2 changes: 2 additions & 0 deletions src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Middleware;
using Microsoft.AspNetCore.Mvc;

namespace JsonApiDotNetCore.Controllers
{
[ServiceFilter(typeof(IQueryParameterActionFilter))]
public abstract class JsonApiControllerMixin : ControllerBase
{
protected IActionResult Forbidden()
Expand Down
51 changes: 15 additions & 36 deletions src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ public DefaultEntityRepository(

/// <inheritdoc />
public virtual IQueryable<TEntity> Get() => _dbSet;

/// <inheritdoc />
public virtual IQueryable<TEntity> Select(IQueryable<TEntity> entities, List<string> fields)
public virtual IQueryable<TEntity> Select(IQueryable<TEntity> entities, List<AttrAttribute> fields)
{
if (fields?.Count > 0)
return entities.Select(fields);
Expand All @@ -76,51 +76,36 @@ public virtual IQueryable<TEntity> Select(IQueryable<TEntity> entities, List<str
}

/// <inheritdoc />
public virtual IQueryable<TEntity> Filter(IQueryable<TEntity> entities, FilterQuery filterQuery)
public virtual IQueryable<TEntity> Filter(IQueryable<TEntity> entities, FilterQueryContext filterQueryContext)
{
if (_resourceDefinition != null)
{
if (filterQueryContext.IsCustom)
{ // todo: consider to move this business logic to service layer
var filterQuery = filterQueryContext.Query;
var defaultQueryFilters = _resourceDefinition.GetQueryFilters();
if (defaultQueryFilters != null && defaultQueryFilters.TryGetValue(filterQuery.Attribute, out var defaultQueryFilter) == true)
{
if (defaultQueryFilters != null && defaultQueryFilters.TryGetValue(filterQuery.Target, out var defaultQueryFilter) == true)
return defaultQueryFilter(entities, filterQuery);
}

}
return entities.Filter(new AttrFilterQuery(_currentRequest.GetRequestResource(), _resourceGraph, filterQuery));
return entities.Filter(filterQueryContext);
}

/// <inheritdoc />
public virtual IQueryable<TEntity> Sort(IQueryable<TEntity> entities, List<SortQuery> sortQueries)
public virtual IQueryable<TEntity> Sort(IQueryable<TEntity> entities, SortQueryContext sortQueryContext)
{
if (sortQueries != null && sortQueries.Count > 0)
return entities.Sort(_currentRequest.GetRequestResource(), _resourceGraph, sortQueries);

if (_resourceDefinition != null)
{
var defaultSortOrder = _resourceDefinition.DefaultSort();
if (defaultSortOrder != null && defaultSortOrder.Count > 0)
{
foreach (var sortProp in defaultSortOrder)
{
// this is dumb...add an overload, don't allocate for no reason
entities.Sort(_currentRequest.GetRequestResource(), _resourceGraph, new SortQuery(sortProp.Item2, sortProp.Item1.PublicAttributeName));
}
}
}
return entities;
return entities.Sort(sortQueryContext);
}

/// <inheritdoc />
public virtual async Task<TEntity> GetAsync(TId id)
public virtual async Task<TEntity> GetAsync(TId id, List<AttrAttribute> fields = null)
{
return await Select(Get(), _currentRequest.QuerySet?.Fields).SingleOrDefaultAsync(e => e.Id.Equals(id));
return await Select(Get(), fields).SingleOrDefaultAsync(e => e.Id.Equals(id));
}

/// <inheritdoc />
public virtual async Task<TEntity> GetAndIncludeAsync(TId id, RelationshipAttribute relationship)
public virtual async Task<TEntity> GetAndIncludeAsync(TId id, RelationshipAttribute relationship, List<AttrAttribute> fields = null)
{
_logger?.LogDebug($"[JADN] GetAndIncludeAsync({id}, {relationship.PublicRelationshipName})");
var includedSet = Include(Select(Get(), _currentRequest.QuerySet?.Fields), relationship);
var includedSet = Include(Select(Get(), fields), relationship);
var result = await includedSet.SingleOrDefaultAsync(e => e.Id.Equals(id));
return result;
}
Expand Down Expand Up @@ -224,12 +209,6 @@ public void DetachRelationshipPointers(TEntity entity)
}
}

[Obsolete("Use overload UpdateAsync(TEntity updatedEntity): providing parameter ID does no longer add anything relevant")]
public virtual async Task<TEntity> UpdateAsync(TId id, TEntity updatedEntity)
{
return await UpdateAsync(updatedEntity);
}

/// <inheritdoc />
public virtual async Task<TEntity> UpdateAsync(TEntity updatedEntity)
{
Expand Down
10 changes: 5 additions & 5 deletions src/JsonApiDotNetCore/Data/IEntityReadRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface IEntityReadRepository<TEntity, in TId>
/// <summary>
/// Apply fields to the provided queryable
/// </summary>
IQueryable<TEntity> Select(IQueryable<TEntity> entities, List<string> fields);
IQueryable<TEntity> Select(IQueryable<TEntity> entities, List<AttrAttribute> fields);

/// <summary>
/// Include a relationship in the query
Expand All @@ -41,12 +41,12 @@ public interface IEntityReadRepository<TEntity, in TId>
/// <summary>
/// Apply a filter to the provided queryable
/// </summary>
IQueryable<TEntity> Filter(IQueryable<TEntity> entities, FilterQuery filterQuery);
IQueryable<TEntity> Filter(IQueryable<TEntity> entities, FilterQueryContext filterQuery);

/// <summary>
/// Apply a sort to the provided queryable
/// </summary>
IQueryable<TEntity> Sort(IQueryable<TEntity> entities, List<SortQuery> sortQueries);
IQueryable<TEntity> Sort(IQueryable<TEntity> entities, SortQueryContext sortQueries);

/// <summary>
/// Paginate the provided queryable
Expand All @@ -56,7 +56,7 @@ public interface IEntityReadRepository<TEntity, in TId>
/// <summary>
/// Get the entity by id
/// </summary>
Task<TEntity> GetAsync(TId id);
Task<TEntity> GetAsync(TId id, List<AttrAttribute> fields = null);

/// <summary>
/// Get the entity with the specified id and include the relationship.
Expand All @@ -68,7 +68,7 @@ public interface IEntityReadRepository<TEntity, in TId>
/// _todoItemsRepository.GetAndIncludeAsync(1, "achieved-date");
/// </code>
/// </example>
Task<TEntity> GetAndIncludeAsync(TId id, RelationshipAttribute relationship);
Task<TEntity> GetAndIncludeAsync(TId id, RelationshipAttribute relationship, List<AttrAttribute> fields = null);

/// <summary>
/// Count the total number of records
Expand Down
3 changes: 0 additions & 3 deletions src/JsonApiDotNetCore/Data/IEntityWriteRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ public interface IEntityWriteRepository<TEntity, in TId>

Task<TEntity> UpdateAsync(TEntity entity);

[Obsolete("Use overload UpdateAsync(TEntity updatedEntity): providing parameter ID does no longer add anything relevant")]
Task<TEntity> UpdateAsync(TId id, TEntity entity);

Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable<string> relationshipIds);

Task<bool> DeleteAsync(TId id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static IApplicationBuilder UseJsonApi(this IApplicationBuilder app, bool

app.UseEndpointRouting();

app.UseMiddleware<RequestMiddleware>();
app.UseMiddleware<CurrentRequestMiddleware>();

if (useMvc)
{
Expand Down
Loading