From fc7a3beedb60c10cac02658c966e74c05bc34896 Mon Sep 17 00:00:00 2001 From: Milos Date: Wed, 20 Feb 2019 01:15:16 +0100 Subject: [PATCH 1/2] Sparse fields with Repository override --- .../Data/DefaultEntityRepository.cs | 11 ++++-- .../Data/IEntityReadRepository.cs | 5 +++ .../Services/EntityResourceService.cs | 3 ++ .../Extensibility/RepositoryOverrideTests.cs | 37 +++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index fd3a8b48e8..7a40182425 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -79,12 +79,15 @@ public DefaultEntityRepository( } /// - public virtual IQueryable Get() + public virtual IQueryable Get() + => _dbSet; + + public virtual IQueryable Select(IQueryable entities, List fields) { - if (_jsonApiContext.QuerySet?.Fields != null && _jsonApiContext.QuerySet.Fields.Count > 0) - return _dbSet.Select(_jsonApiContext.QuerySet?.Fields); + if (fields?.Count > 0) + return entities.Select(fields); - return _dbSet; + return entities; } /// diff --git a/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs b/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs index f861ce10e2..bee908a0b4 100644 --- a/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs +++ b/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs @@ -20,6 +20,11 @@ public interface IEntityReadRepository /// IQueryable Get(); + /// + /// Apply fields to the provided queryable + /// + IQueryable Select(IQueryable entities,List fields); + /// /// Include a relationship in the query /// diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index 53cfc7a7c1..e02ca91fe1 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -108,6 +108,9 @@ public virtual async Task> GetAsync() if (_jsonApiContext.Options.IncludeTotalRecordCount) _jsonApiContext.PageManager.TotalRecords = await _entities.CountAsync(entities); + if (_jsonApiContext.QuerySet?.Fields?.Count > 0) + entities = _entities.Select(entities, _jsonApiContext.QuerySet.Fields); + // pagination should be done last since it will execute the query var pagedEntities = await ApplyPageQueryAsync(entities); return pagedEntities; diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs index 95ea814a5d..b161b14c87 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs @@ -61,5 +61,42 @@ public async Task Total_Record_Count_Included() foreach(var item in deserializedBody) Assert.Equal(person.Id, item.OwnerId); } + + [Fact] + public async Task Sparse_Fields_Works_With_Get_Override() + { + // arrange + var builder = new WebHostBuilder() + .UseStartup(); + var server = new TestServer(builder); + var client = server.CreateClient(); + var context = (AppDbContext)server.Host.Services.GetService(typeof(AppDbContext)); + var jsonApiContext = (IJsonApiContext)server.Host.Services.GetService(typeof(IJsonApiContext)); + + var person = new Person(); + context.People.Add(person); + var todoItem = new TodoItem(); + todoItem.Owner = person; + context.TodoItems.Add(todoItem); + context.SaveChanges(); + + var authService = (IAuthorizationService)server.Host.Services.GetService(typeof(IAuthorizationService)); + authService.CurrentUserId = person.Id; + + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items/{todoItem.Id}?fields[todo-items]=description"; + + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await client.SendAsync(request); + var responseBody = await response.Content.ReadAsStringAsync(); + var deserializedBody = _fixture.GetService().Deserialize(responseBody); + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(todoItem.Description, deserializedBody.Description); + + } } } From 5169fac594d2dd94587b5312d61df0acbbd10ec8 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 25 Apr 2019 10:54:25 +0200 Subject: [PATCH 2/2] chore: deprecate method --- JsonApiDotnetCore.sln | 3 ++- .../Data/DefaultEntityRepository.cs | 16 +++++++++++++--- .../Data/IEntityReadRepository.cs | 4 ++++ .../Services/EntityResourceService.cs | 4 ++-- .../ServiceDiscoveryFacadeTests.cs | 2 -- .../AuthorizedTodoItemsRepository.cs | 4 ++-- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index bad0e19743..f868670ebd 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -190,7 +190,7 @@ Global {6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x64.ActiveCfg = Release|Any CPU {6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x64.Build.0 = Release|Any CPU {6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x86.ActiveCfg = Release|Any CPU - {6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x86.Build.0 = Release|Any CPU\ + {6DFA30D7-1679-4333-9779-6FB678E48EF5}.Release|x86.Build.0 = Release|Any CPU {09C0C8D8-B721-4955-8889-55CB149C3B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09C0C8D8-B721-4955-8889-55CB149C3B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {09C0C8D8-B721-4955-8889-55CB149C3B5C}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -203,6 +203,7 @@ Global {09C0C8D8-B721-4955-8889-55CB149C3B5C}.Release|x64.Build.0 = Release|Any CPU {09C0C8D8-B721-4955-8889-55CB149C3B5C}.Release|x86.ActiveCfg = Release|Any CPU {09C0C8D8-B721-4955-8889-55CB149C3B5C}.Release|x86.Build.0 = Release|Any CPU + {DF9BFD82-D937-4907-B0B4-64670417115F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 7a40182425..854a962a9f 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -78,8 +78,18 @@ public DefaultEntityRepository( _resourceDefinition = resourceDefinition; } + + + public virtual IQueryable Get() + { + if (_jsonApiContext.QuerySet?.Fields != null && _jsonApiContext.QuerySet.Fields.Count > 0) + return _dbSet.Select(_jsonApiContext.QuerySet?.Fields); + + return _dbSet; + } + /// - public virtual IQueryable Get() + public virtual IQueryable GetQueryable() => _dbSet; public virtual IQueryable Select(IQueryable entities, List fields) @@ -130,7 +140,7 @@ public virtual IQueryable Sort(IQueryable entities, List public virtual async Task GetAsync(TId id) { - return await Get().SingleOrDefaultAsync(e => e.Id.Equals(id)); + return await GetQueryable().SingleOrDefaultAsync(e => e.Id.Equals(id)); } /// @@ -138,7 +148,7 @@ public virtual async Task GetAndIncludeAsync(TId id, string relationshi { _logger?.LogDebug($"[JADN] GetAndIncludeAsync({id}, {relationshipName})"); - var includedSet = Include(Get(), relationshipName); + var includedSet = Include(GetQueryable(), relationshipName); var result = await includedSet.SingleOrDefaultAsync(e => e.Id.Equals(id)); return result; diff --git a/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs b/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs index bee908a0b4..ce23eb8ed2 100644 --- a/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs +++ b/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -18,6 +19,9 @@ public interface IEntityReadRepository /// The base GET query. This is a good place to apply rules that should affect all reads, /// such as authorization of resources. /// + IQueryable GetQueryable(); + + [Obsolete("This method has been deprecated, use GetQueryable() instead")] IQueryable Get(); /// diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index e02ca91fe1..3fb01fa4be 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -98,7 +98,7 @@ public virtual async Task DeleteAsync(TId id) public virtual async Task> GetAsync() { - var entities = _entities.Get(); + var entities = _entities.GetQueryable(); entities = ApplySortAndFilterQuery(entities); @@ -243,7 +243,7 @@ protected virtual IQueryable IncludeRelationships(IQueryable e private async Task GetWithRelationshipsAsync(TId id) { - var query = _entities.Get().Where(e => e.Id.Equals(id)); + var query = _entities.GetQueryable().Where(e => e.Id.Equals(id)); _jsonApiContext.QuerySet.IncludedRelationships.ForEach(r => { diff --git a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs index 15667c1872..6953b5f49c 100644 --- a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs +++ b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs @@ -1,4 +1,3 @@ -using System; using GettingStarted.Models; using GettingStarted.ResourceDefinitionExample; using JsonApiDotNetCore.Builders; @@ -7,7 +6,6 @@ using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Moq; using Xunit; diff --git a/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs b/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs index 4ce5da35d8..2bf33346c4 100644 --- a/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs +++ b/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs @@ -23,9 +23,9 @@ public AuthorizedTodoItemsRepository( _authService = authService; } - public override IQueryable Get() + public override IQueryable GetQueryable() { - return base.Get().Where(todoItem => todoItem.OwnerId == _authService.CurrentUserId); + return base.GetQueryable().Where(todoItem => todoItem.OwnerId == _authService.CurrentUserId); } } }